themes: use the core module for io
[git-cola.git] / cola / guicmds.py
blob8e10ef877b53152d7ce9af77789f01b858ace872
1 from __future__ import absolute_import, division, print_function, unicode_literals
2 import os
4 from . import cmds
5 from . import core
6 from . import difftool
7 from . import gitcmds
8 from . import icons
9 from . import qtutils
10 from .i18n import N_
11 from .interaction import Interaction
12 from .widgets import completion
13 from .widgets import editremotes
14 from .widgets.browse import BrowseBranch
15 from .widgets.selectcommits import select_commits
16 from .widgets.selectcommits import select_commits_and_output
19 def delete_branch(context):
20 """Launch the 'Delete Branch' dialog."""
21 icon = icons.discard()
22 branch = choose_branch(context, N_('Delete Branch'), N_('Delete'), icon=icon)
23 if not branch:
24 return
25 cmds.do(cmds.DeleteBranch, context, branch)
28 def delete_remote_branch(context):
29 """Launch the 'Delete Remote Branch' dialog."""
30 remote_branch = choose_remote_branch(
31 context, N_('Delete Remote Branch'), N_('Delete'), icon=icons.discard()
33 if not remote_branch:
34 return
35 remote, branch = gitcmds.parse_remote_branch(remote_branch)
36 if remote and branch:
37 cmds.do(cmds.DeleteRemoteBranch, context, remote, branch)
40 def browse_current(context):
41 """Launch the 'Browse Current Branch' dialog."""
42 branch = gitcmds.current_branch(context)
43 BrowseBranch.browse(context, branch)
46 def browse_other(context):
47 """Prompt for a branch and inspect content at that point in time."""
48 # Prompt for a branch to browse
49 branch = choose_ref(context, N_('Browse Commits...'), N_('Browse'))
50 if not branch:
51 return
52 BrowseBranch.browse(context, branch)
55 def checkout_branch(context):
56 """Launch the 'Checkout Branch' dialog."""
57 branch = choose_potential_branch(context, N_('Checkout Branch'), N_('Checkout'))
58 if not branch:
59 return
60 cmds.do(cmds.CheckoutBranch, context, branch)
63 def cherry_pick(context):
64 """Launch the 'Cherry-Pick' dialog."""
65 revs, summaries = gitcmds.log_helper(context, all=True)
66 commits = select_commits(
67 context, N_('Cherry-Pick Commit'), revs, summaries, multiselect=False
69 if not commits:
70 return
71 cmds.do(cmds.CherryPick, context, commits)
74 def new_repo(context):
75 """Prompt for a new directory and create a new Git repository
77 :returns str: repository path or None if no repository was created.
79 """
80 git = context.git
81 path = qtutils.opendir_dialog(N_('New Repository...'), core.getcwd())
82 if not path:
83 return None
84 # Avoid needlessly calling `git init`.
85 if git.is_git_repository(path):
86 # We could prompt here and confirm that they really didn't
87 # mean to open an existing repository, but I think
88 # treating it like an "Open" is a sensible DWIM answer.
89 return path
91 status, out, err = git.init(path)
92 if status == 0:
93 return path
95 title = N_('Error Creating Repository')
96 Interaction.command_error(title, 'git init', status, out, err)
97 return None
100 def open_new_repo(context):
101 dirname = new_repo(context)
102 if not dirname:
103 return
104 cmds.do(cmds.OpenRepo, context, dirname)
107 def new_bare_repo(context):
108 result = None
109 repo = prompt_for_new_bare_repo()
110 if not repo:
111 return result
112 # Create bare repo
113 ok = cmds.do(cmds.NewBareRepo, context, repo)
114 if not ok:
115 return result
116 # Add a new remote pointing to the bare repo
117 parent = qtutils.active_window()
118 add_remote = editremotes.add_remote(
119 context, parent, name=os.path.basename(repo), url=repo, readonly_url=True
121 if add_remote:
122 result = repo
124 return result
127 def prompt_for_new_bare_repo():
128 path = qtutils.opendir_dialog(N_('Select Directory...'), core.getcwd())
129 if not path:
130 return None
132 bare_repo = None
133 default = os.path.basename(core.getcwd())
134 if not default.endswith('.git'):
135 default += '.git'
136 while not bare_repo:
137 name, ok = qtutils.prompt(
138 N_('Enter a name for the new bare repo'),
139 title=N_('New Bare Repository...'),
140 text=default,
142 if not name or not ok:
143 return None
144 if not name.endswith('.git'):
145 name += '.git'
146 repo = os.path.join(path, name)
147 if core.isdir(repo):
148 Interaction.critical(N_('Error'), N_('"%s" already exists') % repo)
149 else:
150 bare_repo = repo
152 return bare_repo
155 def export_patches(context):
156 """Run 'git format-patch' on a list of commits."""
157 revs, summaries = gitcmds.log_helper(context)
158 to_export_and_output = select_commits_and_output(
159 context, N_('Export Patches'), revs, summaries
161 if not to_export_and_output['to_export']:
162 return
164 cmds.do(
165 cmds.FormatPatch,
166 context,
167 reversed(to_export_and_output['to_export']),
168 reversed(revs),
169 to_export_and_output['output'],
173 def diff_expression(context):
174 """Diff using an arbitrary expression."""
175 tracked = gitcmds.tracked_branch(context)
176 current = gitcmds.current_branch(context)
177 if tracked and current:
178 ref = tracked + '..' + current
179 else:
180 ref = '@{upstream}..'
181 difftool.diff_expression(context, qtutils.active_window(), ref)
184 def open_repo(context):
185 model = context.model
186 dirname = qtutils.opendir_dialog(N_('Open Git Repository...'), model.getcwd())
187 if not dirname:
188 return
189 cmds.do(cmds.OpenRepo, context, dirname)
192 def open_repo_in_new_window(context):
193 """Spawn a new cola session."""
194 model = context.model
195 dirname = qtutils.opendir_dialog(N_('Open Git Repository...'), model.getcwd())
196 if not dirname:
197 return
198 cmds.do(cmds.OpenNewRepo, context, dirname)
201 def load_commitmsg(context):
202 """Load a commit message from a file."""
203 model = context.model
204 filename = qtutils.open_file(N_('Load Commit Message'), directory=model.getcwd())
205 if filename:
206 cmds.do(cmds.LoadCommitMessageFromFile, context, filename)
209 def choose_from_dialog(get, context, title, button_text, default, icon=None):
210 parent = qtutils.active_window()
211 return get(context, title, button_text, parent, default=default, icon=icon)
214 def choose_ref(context, title, button_text, default=None, icon=None):
215 return choose_from_dialog(
216 completion.GitRefDialog.get, context, title, button_text, default, icon=icon
220 def choose_branch(context, title, button_text, default=None, icon=None):
221 return choose_from_dialog(
222 completion.GitBranchDialog.get, context, title, button_text, default, icon=icon
226 def choose_potential_branch(context, title, button_text, default=None, icon=None):
227 return choose_from_dialog(
228 completion.GitCheckoutBranchDialog.get,
229 context,
230 title,
231 button_text,
232 default,
233 icon=icon,
237 def choose_remote_branch(context, title, button_text, default=None, icon=None):
238 return choose_from_dialog(
239 completion.GitRemoteBranchDialog.get,
240 context,
241 title,
242 button_text,
243 default,
244 icon=icon,
248 def review_branch(context):
249 """Diff against an arbitrary revision, branch, tag, etc."""
250 branch = choose_ref(context, N_('Select Branch to Review'), N_('Review'))
251 if not branch:
252 return
253 merge_base = gitcmds.merge_base_parent(context, branch)
254 difftool.diff_commits(context, qtutils.active_window(), merge_base, branch)
257 def rename_branch(context):
258 """Launch the 'Rename Branch' dialogs."""
259 branch = choose_branch(context, N_('Rename Existing Branch'), N_('Select'))
260 if not branch:
261 return
262 new_branch = choose_branch(context, N_('Enter New Branch Name'), N_('Rename'))
263 if not new_branch:
264 return
265 cmds.do(cmds.RenameBranch, context, branch, new_branch)
268 def reset_soft(context):
269 title = N_('Reset Branch (Soft)')
270 ok_text = N_('Reset Branch')
271 ref = choose_ref(context, title, ok_text, default='HEAD^')
272 if ref:
273 cmds.do(cmds.ResetSoft, context, ref)
276 def reset_mixed(context):
277 title = N_('Reset Branch and Stage (Mixed)')
278 ok_text = N_('Reset')
279 ref = choose_ref(context, title, ok_text, default='HEAD^')
280 if ref:
281 cmds.do(cmds.ResetMixed, context, ref)
284 def reset_keep(context):
285 title = N_('Reset All (Keep Unstaged Changes)')
286 ref = choose_ref(context, title, N_('Reset and Restore'))
287 if ref:
288 cmds.do(cmds.ResetKeep, context, ref)
291 def reset_merge(context):
292 title = N_('Restore Worktree and Reset All (Merge)')
293 ok_text = N_('Reset and Restore')
294 ref = choose_ref(context, title, ok_text, default='HEAD^')
295 if ref:
296 cmds.do(cmds.ResetMerge, context, ref)
299 def reset_hard(context):
300 title = N_('Restore Worktree and Reset All (Hard)')
301 ok_text = N_('Reset and Restore')
302 ref = choose_ref(context, title, ok_text, default='HEAD^')
303 if ref:
304 cmds.do(cmds.ResetHard, context, ref)
307 def restore_worktree(context):
308 title = N_('Restore Worktree')
309 ok_text = N_('Restore Worktree')
310 ref = choose_ref(context, title, ok_text, default='HEAD^')
311 if ref:
312 cmds.do(cmds.RestoreWorktree, context, ref)
315 def install():
316 """Install the GUI-model interaction hooks"""
317 Interaction.choose_ref = staticmethod(choose_ref)