Merge pull request #884 from cclauss/patch-2
[git-cola.git] / cola / guicmds.py
blob90d4659473f7cf6d289deb67643e4183701e560a
1 from __future__ import division, absolute_import, 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(
23 context, N_('Delete Branch'), N_('Delete'), icon=icon)
24 if not branch:
25 return
26 cmds.do(cmds.DeleteBranch, context, branch)
29 def delete_remote_branch(context):
30 """Launch the 'Delete Remote Branch' dialog."""
31 remote_branch = choose_remote_branch(
32 context, N_('Delete Remote Branch'), N_('Delete'),
33 icon=icons.discard())
34 if not remote_branch:
35 return
36 remote, branch = gitcmds.parse_remote_branch(remote_branch)
37 if remote and branch:
38 cmds.do(cmds.DeleteRemoteBranch, context, remote, branch)
41 def browse_current(context):
42 """Launch the 'Browse Current Branch' dialog."""
43 branch = gitcmds.current_branch(context)
44 BrowseBranch.browse(context, branch)
47 def browse_other(context):
48 """Prompt for a branch and inspect content at that point in time."""
49 # Prompt for a branch to browse
50 branch = choose_ref(context, N_('Browse Commits...'), N_('Browse'))
51 if not branch:
52 return
53 BrowseBranch.browse(context, branch)
56 def checkout_branch(context):
57 """Launch the 'Checkout Branch' dialog."""
58 branch = choose_potential_branch(
59 context, N_('Checkout Branch'), N_('Checkout'))
60 if not branch:
61 return
62 cmds.do(cmds.CheckoutBranch, context, branch)
65 def cherry_pick(context):
66 """Launch the 'Cherry-Pick' dialog."""
67 revs, summaries = gitcmds.log_helper(context, all=True)
68 commits = select_commits(
69 context, N_('Cherry-Pick Commit'), revs, summaries, multiselect=False)
70 if not commits:
71 return
72 cmds.do(cmds.CherryPick, context, commits)
75 def new_repo(context):
76 """Prompt for a new directory and create a new Git repository
78 :returns str: repository path or None if no repository was created.
80 """
81 git = context.git
82 path = qtutils.opendir_dialog(N_('New Repository...'), core.getcwd())
83 if not path:
84 return None
85 # Avoid needlessly calling `git init`.
86 if git.is_git_repository(path):
87 # We could prompt here and confirm that they really didn't
88 # mean to open an existing repository, but I think
89 # treating it like an "Open" is a sensible DWIM answer.
90 return path
92 status, out, err = git.init(path)
93 if status == 0:
94 return path
96 title = N_('Error Creating Repository')
97 Interaction.command_error(title, 'git init', status, out, err)
98 return None
101 def open_new_repo(context):
102 dirname = new_repo(context)
103 if not dirname:
104 return
105 cmds.do(cmds.OpenRepo, context, dirname)
108 def new_bare_repo(context):
109 result = None
110 repo = prompt_for_new_bare_repo()
111 if not repo:
112 return result
113 # Create bare repo
114 ok = cmds.do(cmds.NewBareRepo, context, repo)
115 if not ok:
116 return result
117 # Add a new remote pointing to the bare repo
118 parent = qtutils.active_window()
119 add_remote = editremotes.add_remote(
120 context, parent, name=os.path.basename(repo),
121 url=repo, readonly_url=True)
122 if add_remote:
123 result = repo
125 return result
128 def prompt_for_new_bare_repo():
129 path = qtutils.opendir_dialog(N_('Select Directory...'), core.getcwd())
130 if not path:
131 return None
133 bare_repo = None
134 default = os.path.basename(core.getcwd())
135 if not default.endswith('.git'):
136 default += '.git'
137 while not bare_repo:
138 name, ok = qtutils.prompt(
139 N_('Enter a name for the new bare repo'),
140 title=N_('New Bare Repository...'),
141 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(
149 N_('Error'), N_('"%s" already exists') % repo)
150 else:
151 bare_repo = repo
153 return bare_repo
156 def export_patches(context):
157 """Run 'git format-patch' on a list of commits."""
158 revs, summaries = gitcmds.log_helper(context)
159 to_export_and_output = select_commits_and_output(
160 context, N_('Export Patches'), revs, summaries)
161 if not to_export_and_output['to_export']:
162 return
164 cmds.do(
165 cmds.FormatPatch, context,
166 reversed(to_export_and_output['to_export']), reversed(revs),
167 to_export_and_output['output'])
170 def diff_expression(context):
171 """Diff using an arbitrary expression."""
172 tracked = gitcmds.tracked_branch(context)
173 current = gitcmds.current_branch(context)
174 if tracked and current:
175 ref = tracked + '..' + current
176 else:
177 ref = 'origin/master..'
178 difftool.diff_expression(context, qtutils.active_window(), ref)
181 def open_repo(context):
182 model = context.model
183 dirname = qtutils.opendir_dialog(
184 N_('Open Git Repository...'), model.getcwd())
185 if not dirname:
186 return
187 cmds.do(cmds.OpenRepo, context, dirname)
190 def open_repo_in_new_window(context):
191 """Spawn a new cola session."""
192 model = context.model
193 dirname = qtutils.opendir_dialog(
194 N_('Open Git Repository...'), model.getcwd())
195 if not dirname:
196 return
197 cmds.do(cmds.OpenNewRepo, context, dirname)
200 def load_commitmsg(context):
201 """Load a commit message from a file."""
202 model = context.model
203 filename = qtutils.open_file(
204 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(completion.GitRefDialog.get,
216 context, title, button_text, default, icon=icon)
219 def choose_branch(context, title, button_text, default=None, icon=None):
220 return choose_from_dialog(completion.GitBranchDialog.get,
221 context, title, button_text, default, icon=icon)
224 def choose_potential_branch(context, title, button_text,
225 default=None, icon=None):
226 return choose_from_dialog(completion.GitCheckoutBranchDialog.get,
227 context, title, button_text, default, icon=icon)
230 def choose_remote_branch(context, title, button_text, default=None, icon=None):
231 return choose_from_dialog(completion.GitRemoteBranchDialog.get,
232 context, title, button_text, default, icon=icon)
235 def review_branch(context):
236 """Diff against an arbitrary revision, branch, tag, etc."""
237 branch = choose_ref(context, N_('Select Branch to Review'), N_('Review'))
238 if not branch:
239 return
240 merge_base = gitcmds.merge_base_parent(context, branch)
241 difftool.diff_commits(context, qtutils.active_window(), merge_base, branch)
244 def rename_branch(context):
245 """Launch the 'Rename Branch' dialogs."""
246 branch = choose_branch(context, N_('Rename Existing Branch'), N_('Select'))
247 if not branch:
248 return
249 new_branch = choose_branch(
250 context, N_('Enter New Branch Name'), N_('Rename'))
251 if not new_branch:
252 return
253 cmds.do(cmds.RenameBranch, context, branch, new_branch)
256 def reset_branch_head(context):
257 ref = choose_ref(
258 context, N_('Reset Branch Head'), N_('Reset'), default='HEAD^')
259 if ref:
260 cmds.do(cmds.ResetBranchHead, context, ref)
263 def reset_worktree(context):
264 ref = choose_ref(
265 context, N_('Reset Worktree'), N_('Reset'))
266 if ref:
267 cmds.do(cmds.ResetWorktree, context, ref)
270 def install():
271 """Install the GUI-model interaction hooks"""
272 Interaction.choose_ref = staticmethod(choose_ref)