5 from cStringIO
import StringIO
10 from cola
import errors
11 from cola
import gitcfg
12 from cola
import gitcmds
13 from cola
import utils
14 from cola
import signals
15 from cola
import cmdfactory
16 from cola
import difftool
17 from cola
.diffparse
import DiffParser
18 from cola
.models
import selection
20 _notifier
= cola
.notifier()
21 _factory
= cmdfactory
.factory()
22 _config
= gitcfg
.instance()
25 class BaseCommand(object):
26 """Base class for all commands; provides the command pattern"""
30 def is_undoable(self
):
31 """Can this be undone?"""
35 """Return this command's name."""
36 return self
.__class
__.__name
__
39 raise NotImplementedError('%s.do() is unimplemented' % self
.name())
42 raise NotImplementedError('%s.undo() is unimplemented' % self
.name())
45 class Command(BaseCommand
):
46 """Base class for commands that modify the main model"""
48 """Initialize the command and stash away values for use in do()"""
49 # These are commonly used so let's make it easier to write new commands.
50 BaseCommand
.__init
__(self
)
51 self
.model
= cola
.model()
53 self
.old_diff_text
= self
.model
.diff_text
54 self
.old_filename
= self
.model
.filename
55 self
.old_mode
= self
.model
.mode
56 self
.old_head
= self
.model
.head
58 self
.new_diff_text
= self
.old_diff_text
59 self
.new_filename
= self
.old_filename
60 self
.new_head
= self
.old_head
61 self
.new_mode
= self
.old_mode
64 """Perform the operation."""
65 self
.model
.set_diff_text(self
.new_diff_text
)
66 self
.model
.set_filename(self
.new_filename
)
67 self
.model
.set_head(self
.new_head
)
68 self
.model
.set_mode(self
.new_mode
)
71 """Undo the operation."""
72 self
.model
.set_diff_text(self
.old_diff_text
)
73 self
.model
.set_filename(self
.old_filename
)
74 self
.model
.set_head(self
.old_head
)
75 self
.model
.set_mode(self
.old_mode
)
78 class AmendMode(Command
):
79 """Try to amend a commit."""
80 def __init__(self
, amend
):
81 Command
.__init
__(self
)
85 self
.old_commitmsg
= self
.model
.commitmsg
88 self
.new_mode
= self
.model
.mode_amend
89 self
.new_head
= 'HEAD^'
90 self
.new_commitmsg
= self
.model
.prev_commitmsg()
92 # else, amend unchecked, regular commit
93 self
.new_mode
= self
.model
.mode_none
94 self
.new_head
= 'HEAD'
95 self
.new_diff_text
= ''
96 self
.new_commitmsg
= self
.model
.commitmsg
97 # If we're going back into new-commit-mode then search the
98 # undo stack for a previous amend-commit-mode and grab the
99 # commit message at that point in time.
100 if not _factory
.undostack
:
102 undo_count
= len(_factory
.undostack
)
103 for i
in xrange(undo_count
):
104 # Find the latest AmendMode command
105 idx
= undo_count
- i
- 1
106 cmdobj
= _factory
.undostack
[idx
]
107 if type(cmdobj
) is not AmendMode
:
110 self
.new_commitmsg
= cmdobj
.old_commitmsg
114 """Leave/enter amend mode."""
115 """Attempt to enter amend mode. Do not allow this when merging."""
117 if os
.path
.exists(self
.model
.git
.git_path('MERGE_HEAD')):
119 _notifier
.broadcast(signals
.amend
, False)
120 _factory
.prompt_user(signals
.information
,
122 'You are in the middle of a merge.\n'
123 'You cannot amend while merging.')
126 _notifier
.broadcast(signals
.amend
, self
.amending
)
127 self
.model
.set_commitmsg(self
.new_commitmsg
)
129 self
.model
.update_file_status()
134 self
.model
.set_commitmsg(self
.old_commitmsg
)
136 self
.model
.update_file_status()
139 class ApplyDiffSelection(Command
):
140 def __init__(self
, staged
, selected
, offset
, selection
, apply_to_worktree
):
141 Command
.__init
__(self
)
143 self
.selected
= selected
145 self
.selection
= selection
146 self
.apply_to_worktree
= apply_to_worktree
149 if self
.model
.mode
== self
.model
.mode_branch
:
150 # We're applying changes from a different branch!
151 parser
= DiffParser(self
.model
,
152 filename
=self
.model
.filename
,
154 branch
=self
.model
.head
)
156 parser
.process_diff_selection(self
.selected
,
159 apply_to_worktree
=True)
161 # The normal worktree vs index scenario
162 parser
= DiffParser(self
.model
,
163 filename
=self
.model
.filename
,
165 reverse
=self
.apply_to_worktree
)
167 parser
.process_diff_selection(self
.selected
,
171 self
.apply_to_worktree
)
172 _notifier
.broadcast(signals
.log_cmd
, status
, output
)
173 # Redo the diff to show changes
175 diffcmd
= DiffStaged([self
.model
.filename
])
177 diffcmd
= Diff([self
.model
.filename
])
179 self
.model
.update_file_status()
182 class ApplyPatches(Command
):
183 def __init__(self
, patches
):
184 Command
.__init
__(self
)
186 self
.patches
= patches
190 num_patches
= len(self
.patches
)
191 orig_head
= self
.model
.git
.rev_parse('HEAD')
193 for idx
, patch
in enumerate(self
.patches
):
194 status
, output
= self
.model
.git
.am(patch
,
197 # Log the git-am command
198 _notifier
.broadcast(signals
.log_cmd
, status
, output
)
201 diff
= self
.model
.git
.diff('HEAD^!', stat
=True)
202 diff_text
+= 'Patch %d/%d - ' % (idx
+1, num_patches
)
203 diff_text
+= '%s:\n%s\n\n' % (os
.path
.basename(patch
), diff
)
205 diff_text
+= 'Summary:\n'
206 diff_text
+= self
.model
.git
.diff(orig_head
, stat
=True)
209 self
.model
.set_diff_text(diff_text
)
211 self
.model
.update_file_status()
213 _factory
.prompt_user(signals
.information
,
215 '%d patch(es) applied:\n\n%s' %
217 '\n'.join(map(os
.path
.basename
, self
.patches
))))
220 class HeadChangeCommand(Command
):
221 """Changes the model's current head."""
222 def __init__(self
, treeish
):
223 Command
.__init
__(self
)
224 self
.new_head
= treeish
225 self
.new_diff_text
= ''
229 self
.model
.update_file_status()
232 class BranchMode(HeadChangeCommand
):
233 """Enter into diff-branch mode."""
234 def __init__(self
, treeish
, filename
):
235 HeadChangeCommand
.__init
__(self
, treeish
)
236 self
.old_filename
= self
.model
.filename
237 self
.new_filename
= filename
238 self
.new_mode
= self
.model
.mode_branch
239 self
.new_diff_text
= gitcmds
.diff_helper(filename
=filename
,
243 class Checkout(Command
):
245 A command object for git-checkout.
247 'argv' is handed off directly to git.
250 def __init__(self
, argv
, checkout_branch
=False):
251 Command
.__init
__(self
)
253 self
.checkout_branch
= checkout_branch
254 self
.new_diff_text
= ''
257 status
, output
= self
.model
.git
.checkout(with_stderr
=True,
258 with_status
=True, *self
.argv
)
259 _notifier
.broadcast(signals
.log_cmd
, status
, output
)
260 if self
.checkout_branch
:
261 self
.model
.update_status()
263 self
.model
.update_file_status()
266 class CheckoutBranch(Checkout
):
267 """Checkout a branch."""
268 def __init__(self
, branch
, checkout_branch
=True):
269 Checkout
.__init
__(self
, [branch
])
272 class CherryPick(Command
):
273 """Cherry pick commits into the current branch."""
274 def __init__(self
, commits
):
275 Command
.__init
__(self
)
276 self
.commits
= commits
279 self
.model
.cherry_pick_list(self
.commits
)
280 self
.model
.update_file_status()
283 class ResetMode(Command
):
284 """Reset the mode and clear the model's diff text."""
286 Command
.__init
__(self
)
287 self
.new_mode
= self
.model
.mode_none
288 self
.new_head
= 'HEAD'
289 self
.new_diff_text
= ''
293 self
.model
.update_file_status()
296 class Commit(ResetMode
):
297 """Attempt to create a new commit."""
298 def __init__(self
, amend
, msg
):
299 ResetMode
.__init
__(self
)
301 self
.msg
= core
.encode(msg
)
302 self
.old_commitmsg
= self
.model
.commitmsg
303 self
.new_commitmsg
= ''
306 status
, output
= self
.model
.commit_with_msg(self
.msg
, amend
=self
.amend
)
309 self
.model
.set_commitmsg(self
.new_commitmsg
)
312 title
= 'Commit failed: '
313 _notifier
.broadcast(signals
.log_cmd
, status
, title
+output
)
316 class Ignore(Command
):
317 """Add files to .gitignore"""
318 def __init__(self
, filenames
):
319 Command
.__init
__(self
)
320 self
.filenames
= filenames
324 for fname
in self
.filenames
:
325 new_additions
= new_additions
+ fname
+ '\n'
326 for_status
= new_additions
328 if os
.path
.exists('.gitignore'):
329 current_list
= utils
.slurp('.gitignore')
330 new_additions
= new_additions
+ current_list
331 utils
.write('.gitignore', new_additions
)
332 _notifier
.broadcast(signals
.log_cmd
,
334 'Added to .gitignore:\n%s' % for_status
)
335 self
.model
.update_file_status()
338 class Delete(Command
):
339 """Simply delete files."""
340 def __init__(self
, filenames
):
341 Command
.__init
__(self
)
342 self
.filenames
= filenames
343 # We could git-hash-object stuff and provide undo-ability
347 for filename
in self
.filenames
:
353 _factory
.prompt_user(signals
.information
,
355 'Deleting "%s" failed.' % filename
)
357 self
.model
.update_file_status()
359 class DeleteBranch(Command
):
360 """Delete a git branch."""
361 def __init__(self
, branch
):
362 Command
.__init
__(self
)
366 status
, output
= self
.model
.delete_branch(self
.branch
)
368 if output
.startswith('error:'):
369 output
= 'E' + output
[1:]
372 _notifier
.broadcast(signals
.log_cmd
, status
, title
+ output
)
376 """Perform a diff and set the model's current text."""
377 def __init__(self
, filenames
, cached
=False):
378 Command
.__init
__(self
)
379 # Guard against the list of files being empty
384 cached
= not self
.model
.read_only()
385 opts
= dict(ref
=self
.model
.head
)
387 self
.new_filename
= filenames
[0]
388 self
.old_filename
= self
.model
.filename
389 if not self
.model
.read_only():
390 if self
.model
.mode
!= self
.model
.mode_amend
:
391 self
.new_mode
= self
.model
.mode_worktree
392 self
.new_diff_text
= gitcmds
.diff_helper(filename
=self
.new_filename
,
393 cached
=cached
, **opts
)
396 class DiffMode(HeadChangeCommand
):
397 """Enter diff mode and clear the model's diff text."""
398 def __init__(self
, treeish
):
399 HeadChangeCommand
.__init
__(self
, treeish
)
400 self
.new_mode
= self
.model
.mode_diff
403 class DiffExprMode(HeadChangeCommand
):
404 """Enter diff-expr mode and clear the model's diff text."""
405 def __init__(self
, treeish
):
406 HeadChangeCommand
.__init
__(self
, treeish
)
407 self
.new_mode
= self
.model
.mode_diff_expr
410 class Diffstat(Command
):
411 """Perform a diffstat and set the model's diff text."""
413 Command
.__init
__(self
)
414 diff
= self
.model
.git
.diff(self
.model
.head
,
415 unified
=_config
.get('diff.context', 3),
419 self
.new_diff_text
= core
.decode(diff
)
420 self
.new_mode
= self
.model
.mode_worktree
423 class DiffStaged(Diff
):
424 """Perform a staged diff on a file."""
425 def __init__(self
, filenames
):
426 Diff
.__init
__(self
, filenames
, cached
=True)
427 if not self
.model
.read_only():
428 if self
.model
.mode
!= self
.model
.mode_amend
:
429 self
.new_mode
= self
.model
.mode_index
432 class DiffStagedSummary(Command
):
434 Command
.__init
__(self
)
435 cached
= not self
.model
.read_only()
436 diff
= self
.model
.git
.diff(self
.model
.head
,
439 patch_with_stat
=True,
441 self
.new_diff_text
= core
.decode(diff
)
442 if not self
.model
.read_only():
443 if self
.model
.mode
!= self
.model
.mode_amend
:
444 self
.new_mode
= self
.model
.mode_index
447 class Difftool(Command
):
448 """Run git-difftool limited by path."""
449 def __init__(self
, staged
, filenames
):
450 Command
.__init
__(self
)
452 self
.filenames
= filenames
455 if not self
.filenames
:
458 if self
.staged
and not self
.model
.read_only():
459 args
.append('--cached')
460 if self
.model
.head
!= 'HEAD':
461 args
.append(self
.model
.head
)
463 args
.extend(self
.filenames
)
464 difftool
.launch(args
)
468 """Edit a file using the configured gui.editor."""
469 def __init__(self
, filenames
, line_number
=None):
470 Command
.__init
__(self
)
471 self
.filenames
= filenames
472 self
.line_number
= line_number
475 filename
= self
.filenames
[0]
476 if not os
.path
.exists(filename
):
478 editor
= self
.model
.editor()
479 if 'vi' in editor
and self
.line_number
:
480 utils
.fork([editor
, filename
, '+'+self
.line_number
])
482 utils
.fork([editor
, filename
])
485 class FormatPatch(Command
):
486 """Output a patch series given all revisions and a selected subset."""
487 def __init__(self
, to_export
, revs
):
488 Command
.__init
__(self
)
489 self
.to_export
= to_export
493 status
, output
= gitcmds
.format_patchsets(self
.to_export
, self
.revs
)
494 _notifier
.broadcast(signals
.log_cmd
, status
, output
)
497 class GrepMode(Command
):
498 def __init__(self
, txt
):
499 """Perform a git-grep."""
500 Command
.__init
__(self
)
501 self
.new_mode
= self
.model
.mode_grep
502 self
.new_diff_text
= core
.decode(self
.model
.git
.grep(txt
, n
=True))
505 class LoadCommitMessage(Command
):
506 """Loads a commit message from a path."""
507 def __init__(self
, path
):
508 Command
.__init
__(self
)
511 self
.old_commitmsg
= self
.model
.commitmsg
512 self
.old_directory
= self
.model
.directory
516 if not path
or not os
.path
.isfile(path
):
517 raise errors
.UsageError('Error: cannot find commit template',
518 '%s: No such file or directory.' % path
)
519 self
.model
.set_directory(os
.path
.dirname(path
))
520 self
.model
.set_commitmsg(utils
.slurp(path
))
523 self
.model
.set_commitmsg(self
.old_commitmsg
)
524 self
.model
.set_directory(self
.old_directory
)
527 class LoadCommitTemplate(LoadCommitMessage
):
528 """Loads the commit message template specified by commit.template."""
530 LoadCommitMessage
.__init
__(self
, _config
.get('commit.template'))
533 if self
.path
is None:
534 raise errors
.UsageError('Error: unconfigured commit template',
535 'A commit template has not been configured.\n'
536 'Use "git config" to define "commit.template"\n'
537 'so that it points to a commit template.')
538 return LoadCommitMessage
.do(self
)
541 class LoadPreviousMessage(Command
):
542 """Try to amend a commit."""
543 def __init__(self
, sha1
):
544 Command
.__init
__(self
)
546 self
.old_commitmsg
= self
.model
.commitmsg
547 self
.new_commitmsg
= self
.model
.prev_commitmsg(sha1
)
551 self
.model
.set_commitmsg(self
.new_commitmsg
)
554 self
.model
.set_commitmsg(self
.old_commitmsg
)
557 class Mergetool(Command
):
558 """Launch git-mergetool on a list of paths."""
559 def __init__(self
, paths
):
560 Command
.__init
__(self
)
566 utils
.fork(['git', 'mergetool', '--no-prompt', '--'] + self
.paths
)
569 class OpenRepo(Command
):
570 """Launches git-cola on a repo."""
571 def __init__(self
, dirname
):
572 Command
.__init
__(self
)
573 self
.new_directory
= dirname
576 self
.model
.set_directory(self
.new_directory
)
577 utils
.fork([sys
.executable
, sys
.argv
[0], '--repo', self
.new_directory
])
580 class Clone(Command
):
581 """Clones a repository and optionally spawns a new cola session."""
582 def __init__(self
, url
, destdir
, spawn
=True):
583 Command
.__init
__(self
)
585 self
.new_directory
= destdir
589 self
.model
.git
.clone(self
.url
, self
.new_directory
,
590 with_stderr
=True, with_status
=True)
592 utils
.fork(['python', sys
.argv
[0], '--repo', self
.new_directory
])
597 class Rescan(Command
):
598 """Rescans for changes."""
600 self
.model
.update_status()
603 rescan_and_refresh
= 'rescan_and_refresh'
605 class RescanAndRefresh(Command
):
606 """Rescans for changes."""
608 self
.model
.update_status(update_index
=True)
611 class ReviewBranchMode(Command
):
612 """Enter into review-branch mode."""
613 def __init__(self
, branch
):
614 Command
.__init
__(self
)
615 self
.new_mode
= self
.model
.mode_review
616 self
.new_head
= gitcmds
.merge_base_parent(branch
)
617 self
.new_diff_text
= ''
621 self
.model
.update_status()
624 class RunConfigAction(Command
):
625 """Run a user-configured action, typically from the "Tools" menu"""
626 def __init__(self
, name
):
627 Command
.__init
__(self
)
629 self
.model
= cola
.model()
632 for env
in ('FILENAME', 'REVISION', 'ARGS'):
639 opts
= _config
.get_guitool_opts(self
.name
)
640 cmd
= opts
.get('cmd')
641 if 'title' not in opts
:
644 if 'prompt' not in opts
or opts
.get('prompt') is True:
645 prompt
= i18n
.gettext('Are you sure you want to run %s?') % cmd
646 opts
['prompt'] = prompt
648 if opts
.get('needsfile'):
649 filename
= selection
.filename()
651 _factory
.prompt_user(signals
.information
,
652 'Please select a file',
653 '"%s" requires a selected file' % cmd
)
655 os
.environ
['FILENAME'] = filename
657 if opts
.get('revprompt') or opts
.get('argprompt'):
659 ok
= _factory
.prompt_user(signals
.run_config_action
, cmd
, opts
)
662 rev
= opts
.get('revision')
663 args
= opts
.get('args')
664 if opts
.get('revprompt') and not rev
:
665 title
= 'Invalid Revision'
666 msg
= 'The revision expression cannot be empty.'
667 _factory
.prompt_user(signals
.critical
, title
, msg
)
671 elif opts
.get('confirm'):
672 title
= os
.path
.expandvars(opts
.get('title'))
673 prompt
= os
.path
.expandvars(opts
.get('prompt'))
674 if not _factory
.prompt_user(signals
.question
, title
, prompt
):
677 os
.environ
['REVISION'] = rev
679 os
.environ
['ARGS'] = args
680 title
= os
.path
.expandvars(cmd
)
681 _notifier
.broadcast(signals
.log_cmd
, 0, 'running: ' + title
)
682 cmd
= ['sh', '-c', cmd
]
684 if opts
.get('noconsole'):
685 status
, out
, err
= utils
.run_command(cmd
, flag_error
=False)
687 status
, out
, err
= _factory
.prompt_user(signals
.run_command
,
690 _notifier
.broadcast(signals
.log_cmd
, status
,
691 'stdout: %s\nstatus: %s\nstderr: %s' %
692 (out
.rstrip(), status
, err
.rstrip()))
694 if not opts
.get('norescan'):
695 self
.model
.update_status()
699 class SetDiffText(Command
):
700 def __init__(self
, text
):
701 Command
.__init
__(self
)
703 self
.new_diff_text
= text
706 class ShowUntracked(Command
):
707 """Show an untracked file."""
708 # We don't actually do anything other than set the mode right now.
709 # TODO check the mimetype for the file and handle things
711 def __init__(self
, filenames
):
712 Command
.__init
__(self
)
713 self
.new_mode
= self
.model
.mode_worktree
714 # TODO new_diff_text = utils.file_preview(filenames[0])
717 class SignOff(Command
):
719 Command
.__init
__(self
)
721 self
.old_commitmsg
= self
.model
.commitmsg
724 signoff
= self
.signoff()
725 if signoff
in self
.model
.commitmsg
:
727 self
.model
.set_commitmsg(self
.model
.commitmsg
+ '\n' + signoff
)
730 self
.model
.set_commitmsg(self
.old_commitmsg
)
735 user
= pwd
.getpwuid(os
.getuid()).pw_name
737 user
= os
.getenv('USER', 'unknown')
739 name
= _config
.get('user.name', user
)
740 email
= _config
.get('user.email', '%s@%s' % (user
, platform
.node()))
741 return '\nSigned-off-by: %s <%s>' % (name
, email
)
744 class Stage(Command
):
745 """Stage a set of paths."""
746 def __init__(self
, paths
):
747 Command
.__init
__(self
)
751 msg
= 'Staging: %s' % (', '.join(self
.paths
))
752 _notifier
.broadcast(signals
.log_cmd
, 0, msg
)
753 self
.model
.stage_paths(self
.paths
)
756 class StageModified(Stage
):
757 """Stage all modified files."""
759 Stage
.__init
__(self
, None)
760 self
.paths
= self
.model
.modified
763 class StageUntracked(Stage
):
764 """Stage all untracked files."""
766 Stage
.__init
__(self
, None)
767 self
.paths
= self
.model
.untracked
771 """Create a tag object."""
772 def __init__(self
, name
, revision
, sign
=False, message
=''):
773 Command
.__init
__(self
)
775 self
._message
= core
.encode(message
)
776 self
._revision
= revision
780 log_msg
= 'Tagging: "%s" as "%s"' % (self
._revision
, self
._name
)
783 opts
['F'] = self
.model
.tmp_filename()
784 utils
.write(opts
['F'], self
._message
)
787 log_msg
+= ', GPG-signed'
789 status
, output
= self
.model
.git
.tag(self
._name
,
795 opts
['a'] = bool(self
._message
)
796 status
, output
= self
.model
.git
.tag(self
._name
,
805 log_msg
+= '\nOutput:\n%s' % output
807 _notifier
.broadcast(signals
.log_cmd
, status
, log_msg
)
809 self
.model
.update_status()
812 class Unstage(Command
):
813 """Unstage a set of paths."""
814 def __init__(self
, paths
):
815 Command
.__init
__(self
)
819 msg
= 'Unstaging: %s' % (', '.join(self
.paths
))
820 _notifier
.broadcast(signals
.log_cmd
, 0, msg
)
821 self
.model
.unstage_paths(self
.paths
)
824 class UnstageAll(Command
):
825 """Unstage all files; resets the index."""
827 self
.model
.unstage_all()
830 class UnstageSelected(Unstage
):
831 """Unstage selected files."""
833 Unstage
.__init
__(self
, cola
.selection_model().staged
)
836 class UntrackedSummary(Command
):
837 """List possible .gitignore rules as the diff text."""
839 Command
.__init
__(self
)
840 untracked
= self
.model
.untracked
841 suffix
= len(untracked
) > 1 and 's' or ''
843 io
.write('# %s untracked file%s\n' % (len(untracked
), suffix
))
845 io
.write('# possible .gitignore rule%s:\n' % suffix
)
847 io
.write('/'+core
.encode(u
))
848 self
.new_diff_text
= core
.decode(io
.getvalue())
851 class UpdateStatus(Command
):
852 """Update the status of a list of files."""
853 def __init__(self
, files
):
854 Command
.__init
__(self
)
858 self
.model
.update_status_of_files(self
.files
)
861 class VisualizeAll(Command
):
862 """Visualize all branches."""
864 browser
= self
.model
.history_browser()
865 utils
.fork([browser
, '--all'])
868 class VisualizeCurrent(Command
):
869 """Visualize all branches."""
871 browser
= self
.model
.history_browser()
872 utils
.fork([browser
, self
.model
.currentbranch
])
875 class VisualizePaths(Command
):
876 """Path-limited visualization."""
877 def __init__(self
, paths
):
878 Command
.__init
__(self
)
879 browser
= self
.model
.history_browser()
881 self
.argv
= [browser
] + paths
883 self
.argv
= [browser
]
886 utils
.fork(self
.argv
)
889 visualize_revision
= 'visualize_revision'
891 class VisualizeRevision(Command
):
892 """Visualize a specific revision."""
893 def __init__(self
, revision
, paths
=None):
894 Command
.__init
__(self
)
895 self
.revision
= revision
899 argv
= [self
.model
.history_browser()]
901 argv
.append(self
.revision
)
904 argv
.extend(self
.paths
)
910 Register signal mappings with the factory.
912 These commands are automatically created and run when
913 their corresponding signal is broadcast by the notifier.
916 signal_to_command_map
= {
917 signals
.amend_mode
: AmendMode
,
918 signals
.apply_diff_selection
: ApplyDiffSelection
,
919 signals
.apply_patches
: ApplyPatches
,
920 signals
.branch_mode
: BranchMode
,
921 signals
.clone
: Clone
,
922 signals
.checkout
: Checkout
,
923 signals
.checkout_branch
: CheckoutBranch
,
924 signals
.cherry_pick
: CherryPick
,
925 signals
.commit
: Commit
,
926 signals
.delete
: Delete
,
927 signals
.delete_branch
: DeleteBranch
,
929 signals
.diff_mode
: DiffMode
,
930 signals
.diff_expr_mode
: DiffExprMode
,
931 signals
.diff_staged
: DiffStaged
,
932 signals
.diffstat
: Diffstat
,
933 signals
.difftool
: Difftool
,
935 signals
.format_patch
: FormatPatch
,
936 signals
.grep
: GrepMode
,
937 signals
.ignore
: Ignore
,
938 signals
.load_commit_message
: LoadCommitMessage
,
939 signals
.load_commit_template
: LoadCommitTemplate
,
940 signals
.load_previous_message
: LoadPreviousMessage
,
941 signals
.modified_summary
: Diffstat
,
942 signals
.mergetool
: Mergetool
,
943 signals
.open_repo
: OpenRepo
,
944 signals
.rescan
: Rescan
,
945 signals
.rescan_and_refresh
: RescanAndRefresh
,
946 signals
.reset_mode
: ResetMode
,
947 signals
.review_branch_mode
: ReviewBranchMode
,
948 signals
.run_config_action
: RunConfigAction
,
949 signals
.set_diff_text
: SetDiffText
,
950 signals
.show_untracked
: ShowUntracked
,
951 signals
.signoff
: SignOff
,
952 signals
.stage
: Stage
,
953 signals
.stage_modified
: StageModified
,
954 signals
.stage_untracked
: StageUntracked
,
955 signals
.staged_summary
: DiffStagedSummary
,
957 signals
.unstage
: Unstage
,
958 signals
.unstage_all
: UnstageAll
,
959 signals
.unstage_selected
: UnstageSelected
,
960 signals
.untracked_summary
: UntrackedSummary
,
961 signals
.update_status
: UpdateStatus
,
962 signals
.visualize_all
: VisualizeAll
,
963 signals
.visualize_current
: VisualizeCurrent
,
964 signals
.visualize_paths
: VisualizePaths
,
965 signals
.visualize_revision
: VisualizeRevision
,
968 for signal
, cmd
in signal_to_command_map
.iteritems():
969 _factory
.add_global_command(signal
, cmd
)