|
1 # show.py - Extension implementing `hg show` |
|
2 # |
|
3 # Copyright 2017 Gregory Szorc <gregory.szorc@gmail.com> |
|
4 # |
|
5 # This software may be used and distributed according to the terms of the |
|
6 # GNU General Public License version 2 or any later version. |
|
7 |
|
8 """unified command to show various repository information (EXPERIMENTAL) |
|
9 |
|
10 This extension provides the :hg:`show` command, which provides a central |
|
11 command for displaying commonly-accessed repository data and views of that |
|
12 data. |
|
13 """ |
|
14 |
|
15 from __future__ import absolute_import |
|
16 |
|
17 from mercurial.i18n import _ |
|
18 from mercurial import ( |
|
19 cmdutil, |
|
20 commands, |
|
21 error, |
|
22 registrar, |
|
23 ) |
|
24 |
|
25 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for |
|
26 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
27 # be specifying the version(s) of Mercurial they are tested with, or |
|
28 # leave the attribute unspecified. |
|
29 testedwith = 'ships-with-hg-core' |
|
30 |
|
31 cmdtable = {} |
|
32 command = cmdutil.command(cmdtable) |
|
33 |
|
34 class showcmdfunc(registrar._funcregistrarbase): |
|
35 """Register a function to be invoked for an `hg show <thing>`.""" |
|
36 |
|
37 # Used by _formatdoc(). |
|
38 _docformat = '%s -- %s' |
|
39 |
|
40 def _extrasetup(self, name, func, fmtopic=None): |
|
41 """Called with decorator arguments to register a show view. |
|
42 |
|
43 ``name`` is the sub-command name. |
|
44 |
|
45 ``func`` is the function being decorated. |
|
46 |
|
47 ``fmtopic`` is the topic in the style that will be rendered for |
|
48 this view. |
|
49 """ |
|
50 func._fmtopic = fmtopic |
|
51 |
|
52 showview = showcmdfunc() |
|
53 |
|
54 @command('show', commands.formatteropts, _('VIEW')) |
|
55 def show(ui, repo, view=None, template=None): |
|
56 """show various repository information |
|
57 |
|
58 A requested view of repository data is displayed. |
|
59 |
|
60 If no view is requested, the list of available views is shown and the |
|
61 command aborts. |
|
62 |
|
63 .. note:: |
|
64 |
|
65 There are no backwards compatibility guarantees for the output of this |
|
66 command. Output may change in any future Mercurial release. |
|
67 |
|
68 Consumers wanting stable command output should specify a template via |
|
69 ``-T/--template``. |
|
70 |
|
71 List of available views: |
|
72 |
|
73 """ |
|
74 if ui.plain() and not template: |
|
75 raise error.Abort(_('"hg show" cannot be used in plain mode because ' |
|
76 'output is not stable'), |
|
77 hint=_('unset HGPLAIN and invoke with -T/--template ' |
|
78 'to control output')) |
|
79 |
|
80 views = showview._table |
|
81 |
|
82 if not view: |
|
83 ui.pager('show') |
|
84 # TODO consider using formatter here so available views can be |
|
85 # rendered to custom format. |
|
86 ui.write(_('available views:\n')) |
|
87 ui.write('\n') |
|
88 |
|
89 for name, func in sorted(views.items()): |
|
90 ui.write(('%s\n') % func.__doc__) |
|
91 |
|
92 ui.write('\n') |
|
93 raise error.Abort(_('no view requested'), |
|
94 hint=_('use "hg show VIEW" to choose a view')) |
|
95 |
|
96 # TODO use same logic as dispatch to perform prefix matching. |
|
97 if view not in views: |
|
98 raise error.Abort(_('unknown view: %s') % view, |
|
99 hint=_('run "hg show" to see available views')) |
|
100 |
|
101 template = template or 'show' |
|
102 fmtopic = 'show%s' % views[view]._fmtopic |
|
103 |
|
104 ui.pager('show') |
|
105 with ui.formatter(fmtopic, {'template': template}) as fm: |
|
106 return views[view](ui, repo, fm) |
|
107 |
|
108 @showview('bookmarks', fmtopic='bookmarks') |
|
109 def showbookmarks(ui, repo, fm): |
|
110 """bookmarks and their associated changeset""" |
|
111 marks = repo._bookmarks |
|
112 if not len(marks): |
|
113 # TODO json output is corrupted; consider using formatter |
|
114 ui.write(_('(no bookmarks set)\n')) |
|
115 return |
|
116 |
|
117 active = repo._activebookmark |
|
118 longestname = max(len(b) for b in marks) |
|
119 # TODO consider exposing longest shortest(node). |
|
120 |
|
121 for bm, node in sorted(marks.items()): |
|
122 fm.startitem() |
|
123 fm.context(ctx=repo[node]) |
|
124 fm.write('bookmark', '%s', bm) |
|
125 fm.write('node', fm.hexfunc(node), fm.hexfunc(node)) |
|
126 fm.data(active=bm == active, |
|
127 longestbookmarklen=longestname) |
|
128 |
|
129 # Adjust the docstring of the show command so it shows all registered views. |
|
130 # This is a bit hacky because it runs at the end of module load. When moved |
|
131 # into core or when another extension wants to provide a view, we'll need |
|
132 # to do this more robustly. |
|
133 # TODO make this more robust. |
|
134 longest = max(map(len, showview._table.keys())) |
|
135 for key in sorted(showview._table.keys()): |
|
136 cmdtable['show'][0].__doc__ += ' %s %s\n' % ( |
|
137 key.ljust(longest), showview._table[key]._origdoc) |