hotkeys: Change "Tree Navigation" to "Navigation"
[git-cola.git] / cola / guicmds.py
blob567e2faea854924ad65ec537ecb19152b5923c78
1 import os
3 import cola
4 from cola import core
5 from cola import difftool
6 from cola import gitcmds
7 from cola import qt
8 from cola import qtutils
9 from cola import signals
10 from cola.git import git
11 from cola.widgets.browse import BrowseDialog
12 from cola.widgets.combodlg import ComboDialog
13 from cola.widgets.selectcommits import select_commits
16 def install_command_wrapper():
17 wrapper = CommandWrapper()
18 cola.factory().add_command_wrapper(wrapper)
21 class CommandWrapper(object):
22 def __init__(self):
23 self.callbacks = {
24 signals.confirm: qtutils.confirm,
25 signals.critical: qtutils.critical,
26 signals.information: qtutils.information,
27 signals.question: qtutils.question,
31 def choose_from_combo(title, items):
32 """Quickly choose an item from a list using a combo box"""
33 return ComboDialog(qtutils.active_window(), title=title, items=items).selected()
36 def slot_with_parent(fn, parent):
37 """Return an argument-less method for calling fn(parent=parent)
39 :param fn: - Function reference, must accept 'parent' as a keyword
40 :param parent: - Qt parent widget
42 """
43 def slot():
44 fn(parent=parent)
45 return slot
48 def branch_delete():
49 """Launch the 'Delete Branch' dialog."""
50 branch = choose_from_combo('Delete Branch',
51 cola.model().local_branches)
52 if not branch:
53 return
54 cola.notifier().broadcast(signals.delete_branch, branch)
57 def diff_revision():
58 """Diff an arbitrary revision against the worktree"""
59 ref = choose_ref('Select Revision to Diff', 'Diff',
60 default='HEAD^')
61 if not ref:
62 return
63 difftool.diff_commits(qtutils.active_window(), ref, None)
66 def browse_current():
67 """Launch the 'Browse Current Branch' dialog."""
68 branch = gitcmds.current_branch()
69 BrowseDialog.browse(branch)
72 def browse_other():
73 """Prompt for a branch and inspect content at that point in time."""
74 # Prompt for a branch to browse
75 branch = choose_from_combo('Browse Revision...', gitcmds.all_refs())
76 if not branch:
77 return
78 BrowseDialog.browse(branch)
81 def checkout_branch():
82 """Launch the 'Checkout Branch' dialog."""
83 branch = choose_from_combo('Checkout Branch',
84 cola.model().local_branches)
85 if not branch:
86 return
87 cola.notifier().broadcast(signals.checkout_branch, branch)
90 def cherry_pick():
91 """Launch the 'Cherry-Pick' dialog."""
92 revs, summaries = gitcmds.log_helper(all=True)
93 commits = select_commits('Cherry-Pick Commit',
94 revs, summaries, multiselect=False)
95 if not commits:
96 return
97 cola.notifier().broadcast(signals.cherry_pick, commits)
100 def clone_repo(spawn=True):
102 Present GUI controls for cloning a repository
104 A new cola session is invoked when 'spawn' is True.
107 url, ok = qtutils.prompt('Path or URL to clone (Env. $VARS okay)')
108 url = os.path.expandvars(core.encode(url))
109 if not ok or not url:
110 return None
111 try:
112 # Pick a suitable basename by parsing the URL
113 newurl = url.replace('\\', '/')
114 default = newurl.rsplit('/', 1)[-1]
115 if default == '.git':
116 # The end of the URL is /.git, so assume it's a file path
117 default = os.path.basename(os.path.dirname(newurl))
118 if default.endswith('.git'):
119 # The URL points to a bare repo
120 default = default[:-4]
121 if url == '.':
122 # The URL is the current repo
123 default = os.path.basename(os.getcwd())
124 if not default:
125 raise
126 except:
127 cola.notifier().broadcast(signals.information,
128 'Error Cloning',
129 'Could not parse: "%s"' % url)
130 qtutils.log(1, 'Oops, could not parse git url: "%s"' % url)
131 return None
133 # Prompt the user for a directory to use as the parent directory
134 msg = 'Select a parent directory for the new clone'
135 dirname = qtutils.opendir_dialog(msg, cola.model().getcwd())
136 if not dirname:
137 return None
138 count = 1
139 dirname = core.decode(dirname)
140 destdir = os.path.join(dirname, core.decode(default))
141 olddestdir = destdir
142 if os.path.exists(destdir):
143 # An existing path can be specified
144 msg = ('"%s" already exists, cola will create a new directory' %
145 destdir)
146 cola.notifier().broadcast(signals.information,
147 'Directory Exists', msg)
149 # Make sure the new destdir doesn't exist
150 while os.path.exists(destdir):
151 destdir = olddestdir + str(count)
152 count += 1
153 cola.notifier().broadcast(signals.clone, core.decode(url), destdir,
154 spawn=spawn)
155 return destdir
158 def export_patches():
159 """Run 'git format-patch' on a list of commits."""
160 revs, summaries = gitcmds.log_helper()
161 to_export = select_commits('Export Patches', revs, summaries)
162 if not to_export:
163 return
164 to_export.reverse()
165 revs.reverse()
166 cola.notifier().broadcast(signals.format_patch, to_export, revs)
169 def diff_expression():
170 """Diff using an arbitrary expression."""
171 tracked = gitcmds.tracked_branch()
172 current = gitcmds.current_branch()
173 if tracked and current:
174 default = tracked + '..' + current
175 else:
176 default = 'origin/master..'
177 ref = choose_ref('Enter Diff Expression', 'Diff',
178 default=default)
179 if not ref:
180 return
181 difftool.diff_expression(qtutils.active_window(), ref)
184 def goto_grep(line):
185 """Called when Search -> Grep's right-click 'goto' action."""
186 filename, line_number, contents = line.split(':', 2)
187 filename = core.encode(filename)
188 cola.notifier().broadcast(signals.edit, [filename], line_number=line_number)
191 def grep():
192 """Prompt and use 'git grep' to find the content."""
193 from cola.widgets.grep import run_grep
195 widget = run_grep(parent=qtutils.active_window())
196 widget.show()
197 widget.raise_()
198 return widget
201 def open_repo():
202 """Spawn a new cola session."""
203 dirname = qtutils.opendir_dialog('Open Git Repository...',
204 cola.model().getcwd())
205 if not dirname:
206 return
207 cola.notifier().broadcast(signals.open_repo, dirname)
210 def load_commitmsg():
211 """Load a commit message from a file."""
212 filename = qtutils.open_dialog('Load Commit Message...',
213 cola.model().getcwd())
214 if filename:
215 cola.notifier().broadcast(signals.load_commit_message, filename)
218 def rebase():
219 """Rebase onto a branch."""
220 branch = choose_from_combo('Rebase Branch',
221 cola.model().all_branches())
222 if not branch:
223 return
224 #TODO cmd
225 status, output = git.rebase(branch, with_stderr=True, with_status=True)
226 qtutils.log(status, output)
229 def choose_ref(title, button_text, default=None):
230 parent = qtutils.active_window()
231 return qt.GitRefDialog.ref(title, button_text, parent, default=default)
234 def review_branch():
235 """Diff against an arbitrary revision, branch, tag, etc."""
236 branch = choose_ref('Select Branch to Review', 'Review')
237 if not branch:
238 return
239 merge_base = gitcmds.merge_base_parent(branch)
240 difftool.diff_commits(qtutils.active_window(), merge_base, branch)