diff: use a block cursor for better usability
[git-cola.git] / cola / models / prefs.py
blob57c0c8b8cf60a15b5a503fab96b34a36c12dc205
1 from __future__ import absolute_import, division, print_function, unicode_literals
2 import sys
4 from qtpy import QtCore
5 from qtpy.QtCore import Signal
7 from .. import core
8 from .. import hidpi
9 from .. import utils
10 from ..cmd import Command
13 AUTOCOMPLETE_PATHS = 'cola.autocompletepaths'
14 AUTOTEMPLATE = 'cola.autoloadcommittemplate'
15 BACKGROUND_EDITOR = 'cola.backgroundeditor'
16 BLAME_VIEWER = 'cola.blameviewer'
17 BLOCK_CURSOR = 'cola.blockcursor'
18 BOLD_HEADERS = 'cola.boldheaders'
19 CHECK_CONFLICTS = 'cola.checkconflicts'
20 CHECK_PUBLISHED_COMMITS = 'cola.checkpublishedcommits'
21 COMMENT_CHAR = 'core.commentchar'
22 DIFFCONTEXT = 'gui.diffcontext'
23 DIFFTOOL = 'diff.tool'
24 DISPLAY_UNTRACKED = 'gui.displayuntracked'
25 EDITOR = 'gui.editor'
26 ENABLE_GRAVATAR = 'cola.gravatar'
27 EXPANDTAB = 'cola.expandtab'
28 FONTDIFF = 'cola.fontdiff'
29 HIDPI = 'cola.hidpi'
30 HISTORY_BROWSER = 'gui.historybrowser'
31 ICON_THEME = 'cola.icontheme'
32 LINEBREAK = 'cola.linebreak'
33 MAXRECENT = 'cola.maxrecent'
34 MERGE_DIFFSTAT = 'merge.diffstat'
35 MERGE_KEEPBACKUP = 'merge.keepbackup'
36 MERGE_SUMMARY = 'merge.summary'
37 MERGE_VERBOSITY = 'merge.verbosity'
38 MERGETOOL = 'merge.tool'
39 MOUSE_ZOOM = 'cola.mousezoom'
40 RESIZE_BROWSER_COLUMNS = 'cola.resizebrowsercolumns'
41 SAFE_MODE = 'cola.safemode'
42 SAVEWINDOWSETTINGS = 'cola.savewindowsettings'
43 SHOW_PATH = 'cola.showpath'
44 SORT_BOOKMARKS = 'cola.sortbookmarks'
45 SPELL_CHECK = 'cola.spellcheck'
46 STATUS_INDENT = 'cola.statusindent'
47 STATUS_SHOW_TOTALS = 'cola.statusshowtotals'
48 THEME = 'cola.theme'
49 TABWIDTH = 'cola.tabwidth'
50 TEXTWIDTH = 'cola.textwidth'
51 USER_EMAIL = 'user.email'
52 USER_NAME = 'user.name'
55 class Defaults(object):
56 """Read-only class for holding defaults that get overridden"""
58 # These should match Git's defaults for git-defined values.
59 autotemplate = False
60 blame_viewer = 'git gui blame'
61 block_cursor = True
62 bold_headers = False
63 check_conflicts = True
64 check_published_commits = True
65 comment_char = '#'
66 display_untracked = True
67 diff_context = 5
68 difftool = 'xxdiff'
69 editor = 'gvim'
70 enable_gravatar = True
71 expandtab = False
72 history_browser = 'gitk'
73 icon_theme = 'default'
74 linebreak = True
75 maxrecent = 8
76 mergetool = difftool
77 merge_diffstat = True
78 merge_keep_backup = True
79 merge_summary = True
80 merge_verbosity = 2
81 mouse_zoom = True
82 resize_browser_columns = False
83 save_window_settings = True
84 safe_mode = False
85 autocomplete_paths = True
86 show_path = True
87 sort_bookmarks = True
88 spellcheck = False
89 tabwidth = 8
90 textwidth = 72
91 theme = 'default'
92 hidpi = hidpi.Option.AUTO
93 status_indent = False
94 status_show_totals = False
97 def blame_viewer(context):
98 """Return the configured "blame" viewer"""
99 default = Defaults.blame_viewer
100 return context.cfg.get(BLAME_VIEWER, default=default)
103 def block_cursor(context):
104 """Should we display a block cursor in diff editors?"""
105 return context.cfg.get(BLOCK_CURSOR, default=Defaults.block_cursor)
108 def bold_headers(context):
109 """Should we bold the Status column headers?"""
110 return context.cfg.get(BOLD_HEADERS, default=Defaults.bold_headers)
113 def check_conflicts(context):
114 """Should we check for merge conflict markers in unmerged files?"""
115 return context.cfg.get(CHECK_CONFLICTS, default=Defaults.check_conflicts)
118 def check_published_commits(context):
119 """Should we check for published commits when amending?"""
120 return context.cfg.get(
121 CHECK_PUBLISHED_COMMITS, default=Defaults.check_published_commits
125 def display_untracked(context):
126 """Should we display untracked files?"""
127 return context.cfg.get(DISPLAY_UNTRACKED, default=Defaults.display_untracked)
130 def editor(context):
131 """Return the configured editor"""
132 app = context.cfg.get(EDITOR, default=fallback_editor())
133 return _remap_editor(app)
136 def background_editor(context):
137 """Return the configured non-blocking background editor"""
138 app = context.cfg.get(BACKGROUND_EDITOR, default=editor(context))
139 return _remap_editor(app)
142 def fallback_editor():
143 """Return a fallback editor for cases where one is not configured
145 GIT_VISUAL and VISUAL are consulted before GIT_EDITOR and EDITOR to allow
146 configuring a visual editor for Git Cola using $GIT_VISUAL and an alternative
147 editor for the Git CLI.
149 editor_variables = (
150 'GIT_VISUAL',
151 'VISUAL',
152 'GIT_EDITOR',
153 'EDITOR',
155 for env in editor_variables:
156 env_editor = core.getenv(env)
157 if env_editor:
158 return env_editor
160 return Defaults.editor
163 def _remap_editor(app):
164 """Remap a configured editor into a visual editor name"""
165 # We do this for vim users because this configuration is convenient for new users.
166 return {
167 'vim': 'gvim -f',
168 'nvim': 'nvim-qt --nofork',
169 }.get(app, app)
172 def comment_char(context):
173 """Return the configured git commit comment character"""
174 return context.cfg.get(COMMENT_CHAR, default=Defaults.comment_char)
177 def enable_gravatar(context):
178 """Is gravatar enabled?"""
179 return context.cfg.get(ENABLE_GRAVATAR, default=Defaults.enable_gravatar)
182 def default_history_browser():
183 """Return the default history browser (e.g. git-dag, gitk)"""
184 if utils.is_win32():
185 # On Windows, a sensible default is "python git-cola dag"
186 # which is different than `gitk` below, but is preferred
187 # because we don't have to guess paths.
188 git_cola = sys.argv[0].replace('\\', '/')
189 python = sys.executable.replace('\\', '/')
190 cwd = core.getcwd().replace('\\', '/')
191 argv = [python, git_cola, 'dag', '--repo', cwd]
192 argv = core.prep_for_subprocess(argv)
193 default = core.list2cmdline(argv)
194 else:
195 # The `gitk` script can be launched as-is on unix
196 default = Defaults.history_browser
197 return default
200 def history_browser(context):
201 """Return the configured history browser"""
202 default = default_history_browser()
203 return context.cfg.get(HISTORY_BROWSER, default=default)
206 def linebreak(context):
207 """Should we word-wrap lines in the commit message editor?"""
208 return context.cfg.get(LINEBREAK, default=Defaults.linebreak)
211 def maxrecent(context):
212 """Return the configured maximum number of Recent Repositories"""
213 value = Defaults.maxrecent
214 if context:
215 value = context.cfg.get(MAXRECENT, default=value)
216 return value
219 def mouse_zoom(context):
220 """Should we zoom text when using Ctrl + MouseWheel scroll"""
221 return context.cfg.get(MOUSE_ZOOM, default=Defaults.mouse_zoom)
224 def spellcheck(context):
225 """Should we spellcheck commit messages?"""
226 return context.cfg.get(SPELL_CHECK, default=Defaults.spellcheck)
229 def expandtab(context):
230 """Should we expand tabs in commit messages?"""
231 return context.cfg.get(EXPANDTAB, default=Defaults.expandtab)
234 def sort_bookmarks(context):
235 """Should we sort bookmarks by name?"""
236 return context.cfg.get(SORT_BOOKMARKS, default=Defaults.sort_bookmarks)
239 def tabwidth(context):
240 """Return the configured tab width in the commit message editor"""
241 return context.cfg.get(TABWIDTH, default=Defaults.tabwidth)
244 def textwidth(context):
245 """Return the configured text width for word wrapping commit messages"""
246 return context.cfg.get(TEXTWIDTH, default=Defaults.textwidth)
249 def status_indent(context):
250 """Should we indent items in the status widget?"""
251 return context.cfg.get(STATUS_INDENT, default=Defaults.status_indent)
254 def status_show_totals(context):
255 """Should we display count totals in the status widget headers?"""
256 return context.cfg.get(STATUS_SHOW_TOTALS, default=Defaults.status_show_totals)
259 class PreferencesModel(QtCore.QObject):
260 """Interact with repo-local and user-global git config preferences"""
262 config_updated = Signal(str, str, object)
264 def __init__(self, context):
265 super(PreferencesModel, self).__init__()
266 self.context = context
267 self.config = context.cfg
269 def set_config(self, source, config, value):
270 """Set a configuration value"""
271 if source == 'local':
272 self.config.set_repo(config, value)
273 else:
274 self.config.set_user(config, value)
275 self.config_updated.emit(source, config, value)
277 def get_config(self, source, config):
278 """Get a configured value"""
279 if source == 'local':
280 value = self.config.get_repo(config)
281 else:
282 value = self.config.get(config)
283 return value
286 class SetConfig(Command):
287 """Store a gitconfig value"""
289 UNDOABLE = True
291 def __init__(self, model, source, config, value):
292 self.source = source
293 self.config = config
294 self.value = value
295 self.old_value = None
296 self.model = model
298 def do(self):
299 """Modify the model and store the updated configuration"""
300 self.old_value = self.model.get_config(self.source, self.config)
301 self.model.set_config(self.source, self.config, self.value)
303 def undo(self):
304 """Restore the configuration change to its original value"""
305 if self.old_value is None:
306 return
307 self.model.set_config(self.source, self.config, self.old_value)