##// END OF EJS Templates
help: make "mergetool" an alias for "merge-tools"...
Gregory Szorc -
r30812:98bfce9b default
parent child Browse files
Show More
@@ -1,606 +1,607 b''
1 # help.py - help data for mercurial
1 # help.py - help data for mercurial
2 #
2 #
3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
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.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import itertools
10 import itertools
11 import os
11 import os
12 import textwrap
12 import textwrap
13
13
14 from .i18n import (
14 from .i18n import (
15 _,
15 _,
16 gettext,
16 gettext,
17 )
17 )
18 from . import (
18 from . import (
19 cmdutil,
19 cmdutil,
20 encoding,
20 encoding,
21 error,
21 error,
22 extensions,
22 extensions,
23 filemerge,
23 filemerge,
24 fileset,
24 fileset,
25 minirst,
25 minirst,
26 revset,
26 revset,
27 templatefilters,
27 templatefilters,
28 templatekw,
28 templatekw,
29 templater,
29 templater,
30 util,
30 util,
31 )
31 )
32 from .hgweb import (
32 from .hgweb import (
33 webcommands,
33 webcommands,
34 )
34 )
35
35
36 _exclkeywords = [
36 _exclkeywords = [
37 "(DEPRECATED)",
37 "(DEPRECATED)",
38 "(EXPERIMENTAL)",
38 "(EXPERIMENTAL)",
39 # i18n: "(DEPRECATED)" is a keyword, must be translated consistently
39 # i18n: "(DEPRECATED)" is a keyword, must be translated consistently
40 _("(DEPRECATED)"),
40 _("(DEPRECATED)"),
41 # i18n: "(EXPERIMENTAL)" is a keyword, must be translated consistently
41 # i18n: "(EXPERIMENTAL)" is a keyword, must be translated consistently
42 _("(EXPERIMENTAL)"),
42 _("(EXPERIMENTAL)"),
43 ]
43 ]
44
44
45 def listexts(header, exts, indent=1, showdeprecated=False):
45 def listexts(header, exts, indent=1, showdeprecated=False):
46 '''return a text listing of the given extensions'''
46 '''return a text listing of the given extensions'''
47 rst = []
47 rst = []
48 if exts:
48 if exts:
49 for name, desc in sorted(exts.iteritems()):
49 for name, desc in sorted(exts.iteritems()):
50 if not showdeprecated and any(w in desc for w in _exclkeywords):
50 if not showdeprecated and any(w in desc for w in _exclkeywords):
51 continue
51 continue
52 rst.append('%s:%s: %s\n' % (' ' * indent, name, desc))
52 rst.append('%s:%s: %s\n' % (' ' * indent, name, desc))
53 if rst:
53 if rst:
54 rst.insert(0, '\n%s\n\n' % header)
54 rst.insert(0, '\n%s\n\n' % header)
55 return rst
55 return rst
56
56
57 def extshelp(ui):
57 def extshelp(ui):
58 rst = loaddoc('extensions')(ui).splitlines(True)
58 rst = loaddoc('extensions')(ui).splitlines(True)
59 rst.extend(listexts(
59 rst.extend(listexts(
60 _('enabled extensions:'), extensions.enabled(), showdeprecated=True))
60 _('enabled extensions:'), extensions.enabled(), showdeprecated=True))
61 rst.extend(listexts(_('disabled extensions:'), extensions.disabled()))
61 rst.extend(listexts(_('disabled extensions:'), extensions.disabled()))
62 doc = ''.join(rst)
62 doc = ''.join(rst)
63 return doc
63 return doc
64
64
65 def optrst(header, options, verbose):
65 def optrst(header, options, verbose):
66 data = []
66 data = []
67 multioccur = False
67 multioccur = False
68 for option in options:
68 for option in options:
69 if len(option) == 5:
69 if len(option) == 5:
70 shortopt, longopt, default, desc, optlabel = option
70 shortopt, longopt, default, desc, optlabel = option
71 else:
71 else:
72 shortopt, longopt, default, desc = option
72 shortopt, longopt, default, desc = option
73 optlabel = _("VALUE") # default label
73 optlabel = _("VALUE") # default label
74
74
75 if not verbose and any(w in desc for w in _exclkeywords):
75 if not verbose and any(w in desc for w in _exclkeywords):
76 continue
76 continue
77
77
78 so = ''
78 so = ''
79 if shortopt:
79 if shortopt:
80 so = '-' + shortopt
80 so = '-' + shortopt
81 lo = '--' + longopt
81 lo = '--' + longopt
82 if default:
82 if default:
83 desc += _(" (default: %s)") % default
83 desc += _(" (default: %s)") % default
84
84
85 if isinstance(default, list):
85 if isinstance(default, list):
86 lo += " %s [+]" % optlabel
86 lo += " %s [+]" % optlabel
87 multioccur = True
87 multioccur = True
88 elif (default is not None) and not isinstance(default, bool):
88 elif (default is not None) and not isinstance(default, bool):
89 lo += " %s" % optlabel
89 lo += " %s" % optlabel
90
90
91 data.append((so, lo, desc))
91 data.append((so, lo, desc))
92
92
93 if multioccur:
93 if multioccur:
94 header += (_(" ([+] can be repeated)"))
94 header += (_(" ([+] can be repeated)"))
95
95
96 rst = ['\n%s:\n\n' % header]
96 rst = ['\n%s:\n\n' % header]
97 rst.extend(minirst.maketable(data, 1))
97 rst.extend(minirst.maketable(data, 1))
98
98
99 return ''.join(rst)
99 return ''.join(rst)
100
100
101 def indicateomitted(rst, omitted, notomitted=None):
101 def indicateomitted(rst, omitted, notomitted=None):
102 rst.append('\n\n.. container:: omitted\n\n %s\n\n' % omitted)
102 rst.append('\n\n.. container:: omitted\n\n %s\n\n' % omitted)
103 if notomitted:
103 if notomitted:
104 rst.append('\n\n.. container:: notomitted\n\n %s\n\n' % notomitted)
104 rst.append('\n\n.. container:: notomitted\n\n %s\n\n' % notomitted)
105
105
106 def filtercmd(ui, cmd, kw, doc):
106 def filtercmd(ui, cmd, kw, doc):
107 if not ui.debugflag and cmd.startswith("debug") and kw != "debug":
107 if not ui.debugflag and cmd.startswith("debug") and kw != "debug":
108 return True
108 return True
109 if not ui.verbose and doc and any(w in doc for w in _exclkeywords):
109 if not ui.verbose and doc and any(w in doc for w in _exclkeywords):
110 return True
110 return True
111 return False
111 return False
112
112
113 def topicmatch(ui, kw):
113 def topicmatch(ui, kw):
114 """Return help topics matching kw.
114 """Return help topics matching kw.
115
115
116 Returns {'section': [(name, summary), ...], ...} where section is
116 Returns {'section': [(name, summary), ...], ...} where section is
117 one of topics, commands, extensions, or extensioncommands.
117 one of topics, commands, extensions, or extensioncommands.
118 """
118 """
119 kw = encoding.lower(kw)
119 kw = encoding.lower(kw)
120 def lowercontains(container):
120 def lowercontains(container):
121 return kw in encoding.lower(container) # translated in helptable
121 return kw in encoding.lower(container) # translated in helptable
122 results = {'topics': [],
122 results = {'topics': [],
123 'commands': [],
123 'commands': [],
124 'extensions': [],
124 'extensions': [],
125 'extensioncommands': [],
125 'extensioncommands': [],
126 }
126 }
127 for names, header, doc in helptable:
127 for names, header, doc in helptable:
128 # Old extensions may use a str as doc.
128 # Old extensions may use a str as doc.
129 if (sum(map(lowercontains, names))
129 if (sum(map(lowercontains, names))
130 or lowercontains(header)
130 or lowercontains(header)
131 or (callable(doc) and lowercontains(doc(ui)))):
131 or (callable(doc) and lowercontains(doc(ui)))):
132 results['topics'].append((names[0], header))
132 results['topics'].append((names[0], header))
133 from . import commands # avoid cycle
133 from . import commands # avoid cycle
134 for cmd, entry in commands.table.iteritems():
134 for cmd, entry in commands.table.iteritems():
135 if len(entry) == 3:
135 if len(entry) == 3:
136 summary = entry[2]
136 summary = entry[2]
137 else:
137 else:
138 summary = ''
138 summary = ''
139 # translate docs *before* searching there
139 # translate docs *before* searching there
140 docs = _(getattr(entry[0], '__doc__', None)) or ''
140 docs = _(getattr(entry[0], '__doc__', None)) or ''
141 if kw in cmd or lowercontains(summary) or lowercontains(docs):
141 if kw in cmd or lowercontains(summary) or lowercontains(docs):
142 doclines = docs.splitlines()
142 doclines = docs.splitlines()
143 if doclines:
143 if doclines:
144 summary = doclines[0]
144 summary = doclines[0]
145 cmdname = cmd.partition('|')[0].lstrip('^')
145 cmdname = cmd.partition('|')[0].lstrip('^')
146 if filtercmd(ui, cmdname, kw, docs):
146 if filtercmd(ui, cmdname, kw, docs):
147 continue
147 continue
148 results['commands'].append((cmdname, summary))
148 results['commands'].append((cmdname, summary))
149 for name, docs in itertools.chain(
149 for name, docs in itertools.chain(
150 extensions.enabled(False).iteritems(),
150 extensions.enabled(False).iteritems(),
151 extensions.disabled().iteritems()):
151 extensions.disabled().iteritems()):
152 if not docs:
152 if not docs:
153 continue
153 continue
154 mod = extensions.load(ui, name, '')
154 mod = extensions.load(ui, name, '')
155 name = name.rpartition('.')[-1]
155 name = name.rpartition('.')[-1]
156 if lowercontains(name) or lowercontains(docs):
156 if lowercontains(name) or lowercontains(docs):
157 # extension docs are already translated
157 # extension docs are already translated
158 results['extensions'].append((name, docs.splitlines()[0]))
158 results['extensions'].append((name, docs.splitlines()[0]))
159 for cmd, entry in getattr(mod, 'cmdtable', {}).iteritems():
159 for cmd, entry in getattr(mod, 'cmdtable', {}).iteritems():
160 if kw in cmd or (len(entry) > 2 and lowercontains(entry[2])):
160 if kw in cmd or (len(entry) > 2 and lowercontains(entry[2])):
161 cmdname = cmd.partition('|')[0].lstrip('^')
161 cmdname = cmd.partition('|')[0].lstrip('^')
162 if entry[0].__doc__:
162 if entry[0].__doc__:
163 cmddoc = gettext(entry[0].__doc__).splitlines()[0]
163 cmddoc = gettext(entry[0].__doc__).splitlines()[0]
164 else:
164 else:
165 cmddoc = _('(no help text available)')
165 cmddoc = _('(no help text available)')
166 if filtercmd(ui, cmdname, kw, cmddoc):
166 if filtercmd(ui, cmdname, kw, cmddoc):
167 continue
167 continue
168 results['extensioncommands'].append((cmdname, cmddoc))
168 results['extensioncommands'].append((cmdname, cmddoc))
169 return results
169 return results
170
170
171 def loaddoc(topic, subdir=None):
171 def loaddoc(topic, subdir=None):
172 """Return a delayed loader for help/topic.txt."""
172 """Return a delayed loader for help/topic.txt."""
173
173
174 def loader(ui):
174 def loader(ui):
175 docdir = os.path.join(util.datapath, 'help')
175 docdir = os.path.join(util.datapath, 'help')
176 if subdir:
176 if subdir:
177 docdir = os.path.join(docdir, subdir)
177 docdir = os.path.join(docdir, subdir)
178 path = os.path.join(docdir, topic + ".txt")
178 path = os.path.join(docdir, topic + ".txt")
179 doc = gettext(util.readfile(path))
179 doc = gettext(util.readfile(path))
180 for rewriter in helphooks.get(topic, []):
180 for rewriter in helphooks.get(topic, []):
181 doc = rewriter(ui, topic, doc)
181 doc = rewriter(ui, topic, doc)
182 return doc
182 return doc
183
183
184 return loader
184 return loader
185
185
186 internalstable = sorted([
186 internalstable = sorted([
187 (['bundles'], _('Bundles'),
187 (['bundles'], _('Bundles'),
188 loaddoc('bundles', subdir='internals')),
188 loaddoc('bundles', subdir='internals')),
189 (['changegroups'], _('Changegroups'),
189 (['changegroups'], _('Changegroups'),
190 loaddoc('changegroups', subdir='internals')),
190 loaddoc('changegroups', subdir='internals')),
191 (['requirements'], _('Repository Requirements'),
191 (['requirements'], _('Repository Requirements'),
192 loaddoc('requirements', subdir='internals')),
192 loaddoc('requirements', subdir='internals')),
193 (['revlogs'], _('Revision Logs'),
193 (['revlogs'], _('Revision Logs'),
194 loaddoc('revlogs', subdir='internals')),
194 loaddoc('revlogs', subdir='internals')),
195 (['wireprotocol'], _('Wire Protocol'),
195 (['wireprotocol'], _('Wire Protocol'),
196 loaddoc('wireprotocol', subdir='internals')),
196 loaddoc('wireprotocol', subdir='internals')),
197 ])
197 ])
198
198
199 def internalshelp(ui):
199 def internalshelp(ui):
200 """Generate the index for the "internals" topic."""
200 """Generate the index for the "internals" topic."""
201 lines = []
201 lines = []
202 for names, header, doc in internalstable:
202 for names, header, doc in internalstable:
203 lines.append(' :%s: %s\n' % (names[0], header))
203 lines.append(' :%s: %s\n' % (names[0], header))
204
204
205 return ''.join(lines)
205 return ''.join(lines)
206
206
207 helptable = sorted([
207 helptable = sorted([
208 (["config", "hgrc"], _("Configuration Files"), loaddoc('config')),
208 (["config", "hgrc"], _("Configuration Files"), loaddoc('config')),
209 (["dates"], _("Date Formats"), loaddoc('dates')),
209 (["dates"], _("Date Formats"), loaddoc('dates')),
210 (["patterns"], _("File Name Patterns"), loaddoc('patterns')),
210 (["patterns"], _("File Name Patterns"), loaddoc('patterns')),
211 (['environment', 'env'], _('Environment Variables'),
211 (['environment', 'env'], _('Environment Variables'),
212 loaddoc('environment')),
212 loaddoc('environment')),
213 (['revisions', 'revs', 'revsets', 'revset', 'multirevs', 'mrevs'],
213 (['revisions', 'revs', 'revsets', 'revset', 'multirevs', 'mrevs'],
214 _('Specifying Revisions'), loaddoc('revisions')),
214 _('Specifying Revisions'), loaddoc('revisions')),
215 (['filesets', 'fileset'], _("Specifying File Sets"), loaddoc('filesets')),
215 (['filesets', 'fileset'], _("Specifying File Sets"), loaddoc('filesets')),
216 (['diffs'], _('Diff Formats'), loaddoc('diffs')),
216 (['diffs'], _('Diff Formats'), loaddoc('diffs')),
217 (['merge-tools', 'mergetools'], _('Merge Tools'), loaddoc('merge-tools')),
217 (['merge-tools', 'mergetools', 'mergetool'], _('Merge Tools'),
218 loaddoc('merge-tools')),
218 (['templating', 'templates', 'template', 'style'], _('Template Usage'),
219 (['templating', 'templates', 'template', 'style'], _('Template Usage'),
219 loaddoc('templates')),
220 loaddoc('templates')),
220 (['urls'], _('URL Paths'), loaddoc('urls')),
221 (['urls'], _('URL Paths'), loaddoc('urls')),
221 (["extensions"], _("Using Additional Features"), extshelp),
222 (["extensions"], _("Using Additional Features"), extshelp),
222 (["subrepos", "subrepo"], _("Subrepositories"), loaddoc('subrepos')),
223 (["subrepos", "subrepo"], _("Subrepositories"), loaddoc('subrepos')),
223 (["hgweb"], _("Configuring hgweb"), loaddoc('hgweb')),
224 (["hgweb"], _("Configuring hgweb"), loaddoc('hgweb')),
224 (["glossary"], _("Glossary"), loaddoc('glossary')),
225 (["glossary"], _("Glossary"), loaddoc('glossary')),
225 (["hgignore", "ignore"], _("Syntax for Mercurial Ignore Files"),
226 (["hgignore", "ignore"], _("Syntax for Mercurial Ignore Files"),
226 loaddoc('hgignore')),
227 loaddoc('hgignore')),
227 (["phases"], _("Working with Phases"), loaddoc('phases')),
228 (["phases"], _("Working with Phases"), loaddoc('phases')),
228 (['scripting'], _('Using Mercurial from scripts and automation'),
229 (['scripting'], _('Using Mercurial from scripts and automation'),
229 loaddoc('scripting')),
230 loaddoc('scripting')),
230 (['internals'], _("Technical implementation topics"),
231 (['internals'], _("Technical implementation topics"),
231 internalshelp),
232 internalshelp),
232 ])
233 ])
233
234
234 # Maps topics with sub-topics to a list of their sub-topics.
235 # Maps topics with sub-topics to a list of their sub-topics.
235 subtopics = {
236 subtopics = {
236 'internals': internalstable,
237 'internals': internalstable,
237 }
238 }
238
239
239 # Map topics to lists of callable taking the current topic help and
240 # Map topics to lists of callable taking the current topic help and
240 # returning the updated version
241 # returning the updated version
241 helphooks = {}
242 helphooks = {}
242
243
243 def addtopichook(topic, rewriter):
244 def addtopichook(topic, rewriter):
244 helphooks.setdefault(topic, []).append(rewriter)
245 helphooks.setdefault(topic, []).append(rewriter)
245
246
246 def makeitemsdoc(ui, topic, doc, marker, items, dedent=False):
247 def makeitemsdoc(ui, topic, doc, marker, items, dedent=False):
247 """Extract docstring from the items key to function mapping, build a
248 """Extract docstring from the items key to function mapping, build a
248 single documentation block and use it to overwrite the marker in doc.
249 single documentation block and use it to overwrite the marker in doc.
249 """
250 """
250 entries = []
251 entries = []
251 for name in sorted(items):
252 for name in sorted(items):
252 text = (items[name].__doc__ or '').rstrip()
253 text = (items[name].__doc__ or '').rstrip()
253 if (not text
254 if (not text
254 or not ui.verbose and any(w in text for w in _exclkeywords)):
255 or not ui.verbose and any(w in text for w in _exclkeywords)):
255 continue
256 continue
256 text = gettext(text)
257 text = gettext(text)
257 if dedent:
258 if dedent:
258 text = textwrap.dedent(text)
259 text = textwrap.dedent(text)
259 lines = text.splitlines()
260 lines = text.splitlines()
260 doclines = [(lines[0])]
261 doclines = [(lines[0])]
261 for l in lines[1:]:
262 for l in lines[1:]:
262 # Stop once we find some Python doctest
263 # Stop once we find some Python doctest
263 if l.strip().startswith('>>>'):
264 if l.strip().startswith('>>>'):
264 break
265 break
265 if dedent:
266 if dedent:
266 doclines.append(l.rstrip())
267 doclines.append(l.rstrip())
267 else:
268 else:
268 doclines.append(' ' + l.strip())
269 doclines.append(' ' + l.strip())
269 entries.append('\n'.join(doclines))
270 entries.append('\n'.join(doclines))
270 entries = '\n\n'.join(entries)
271 entries = '\n\n'.join(entries)
271 return doc.replace(marker, entries)
272 return doc.replace(marker, entries)
272
273
273 def addtopicsymbols(topic, marker, symbols, dedent=False):
274 def addtopicsymbols(topic, marker, symbols, dedent=False):
274 def add(ui, topic, doc):
275 def add(ui, topic, doc):
275 return makeitemsdoc(ui, topic, doc, marker, symbols, dedent=dedent)
276 return makeitemsdoc(ui, topic, doc, marker, symbols, dedent=dedent)
276 addtopichook(topic, add)
277 addtopichook(topic, add)
277
278
278 addtopicsymbols('filesets', '.. predicatesmarker', fileset.symbols)
279 addtopicsymbols('filesets', '.. predicatesmarker', fileset.symbols)
279 addtopicsymbols('merge-tools', '.. internaltoolsmarker',
280 addtopicsymbols('merge-tools', '.. internaltoolsmarker',
280 filemerge.internalsdoc)
281 filemerge.internalsdoc)
281 addtopicsymbols('revisions', '.. predicatesmarker', revset.symbols)
282 addtopicsymbols('revisions', '.. predicatesmarker', revset.symbols)
282 addtopicsymbols('templates', '.. keywordsmarker', templatekw.keywords)
283 addtopicsymbols('templates', '.. keywordsmarker', templatekw.keywords)
283 addtopicsymbols('templates', '.. filtersmarker', templatefilters.filters)
284 addtopicsymbols('templates', '.. filtersmarker', templatefilters.filters)
284 addtopicsymbols('templates', '.. functionsmarker', templater.funcs)
285 addtopicsymbols('templates', '.. functionsmarker', templater.funcs)
285 addtopicsymbols('hgweb', '.. webcommandsmarker', webcommands.commands,
286 addtopicsymbols('hgweb', '.. webcommandsmarker', webcommands.commands,
286 dedent=True)
287 dedent=True)
287
288
288 def help_(ui, name, unknowncmd=False, full=True, subtopic=None, **opts):
289 def help_(ui, name, unknowncmd=False, full=True, subtopic=None, **opts):
289 '''
290 '''
290 Generate the help for 'name' as unformatted restructured text. If
291 Generate the help for 'name' as unformatted restructured text. If
291 'name' is None, describe the commands available.
292 'name' is None, describe the commands available.
292 '''
293 '''
293
294
294 from . import commands # avoid cycle
295 from . import commands # avoid cycle
295
296
296 def helpcmd(name, subtopic=None):
297 def helpcmd(name, subtopic=None):
297 try:
298 try:
298 aliases, entry = cmdutil.findcmd(name, commands.table,
299 aliases, entry = cmdutil.findcmd(name, commands.table,
299 strict=unknowncmd)
300 strict=unknowncmd)
300 except error.AmbiguousCommand as inst:
301 except error.AmbiguousCommand as inst:
301 # py3k fix: except vars can't be used outside the scope of the
302 # py3k fix: except vars can't be used outside the scope of the
302 # except block, nor can be used inside a lambda. python issue4617
303 # except block, nor can be used inside a lambda. python issue4617
303 prefix = inst.args[0]
304 prefix = inst.args[0]
304 select = lambda c: c.lstrip('^').startswith(prefix)
305 select = lambda c: c.lstrip('^').startswith(prefix)
305 rst = helplist(select)
306 rst = helplist(select)
306 return rst
307 return rst
307
308
308 rst = []
309 rst = []
309
310
310 # check if it's an invalid alias and display its error if it is
311 # check if it's an invalid alias and display its error if it is
311 if getattr(entry[0], 'badalias', None):
312 if getattr(entry[0], 'badalias', None):
312 rst.append(entry[0].badalias + '\n')
313 rst.append(entry[0].badalias + '\n')
313 if entry[0].unknowncmd:
314 if entry[0].unknowncmd:
314 try:
315 try:
315 rst.extend(helpextcmd(entry[0].cmdname))
316 rst.extend(helpextcmd(entry[0].cmdname))
316 except error.UnknownCommand:
317 except error.UnknownCommand:
317 pass
318 pass
318 return rst
319 return rst
319
320
320 # synopsis
321 # synopsis
321 if len(entry) > 2:
322 if len(entry) > 2:
322 if entry[2].startswith('hg'):
323 if entry[2].startswith('hg'):
323 rst.append("%s\n" % entry[2])
324 rst.append("%s\n" % entry[2])
324 else:
325 else:
325 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
326 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
326 else:
327 else:
327 rst.append('hg %s\n' % aliases[0])
328 rst.append('hg %s\n' % aliases[0])
328 # aliases
329 # aliases
329 if full and not ui.quiet and len(aliases) > 1:
330 if full and not ui.quiet and len(aliases) > 1:
330 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
331 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
331 rst.append('\n')
332 rst.append('\n')
332
333
333 # description
334 # description
334 doc = gettext(entry[0].__doc__)
335 doc = gettext(entry[0].__doc__)
335 if not doc:
336 if not doc:
336 doc = _("(no help text available)")
337 doc = _("(no help text available)")
337 if util.safehasattr(entry[0], 'definition'): # aliased command
338 if util.safehasattr(entry[0], 'definition'): # aliased command
338 source = entry[0].source
339 source = entry[0].source
339 if entry[0].definition.startswith('!'): # shell alias
340 if entry[0].definition.startswith('!'): # shell alias
340 doc = (_('shell alias for::\n\n %s\n\ndefined by: %s\n') %
341 doc = (_('shell alias for::\n\n %s\n\ndefined by: %s\n') %
341 (entry[0].definition[1:], source))
342 (entry[0].definition[1:], source))
342 else:
343 else:
343 doc = (_('alias for: hg %s\n\n%s\n\ndefined by: %s\n') %
344 doc = (_('alias for: hg %s\n\n%s\n\ndefined by: %s\n') %
344 (entry[0].definition, doc, source))
345 (entry[0].definition, doc, source))
345 doc = doc.splitlines(True)
346 doc = doc.splitlines(True)
346 if ui.quiet or not full:
347 if ui.quiet or not full:
347 rst.append(doc[0])
348 rst.append(doc[0])
348 else:
349 else:
349 rst.extend(doc)
350 rst.extend(doc)
350 rst.append('\n')
351 rst.append('\n')
351
352
352 # check if this command shadows a non-trivial (multi-line)
353 # check if this command shadows a non-trivial (multi-line)
353 # extension help text
354 # extension help text
354 try:
355 try:
355 mod = extensions.find(name)
356 mod = extensions.find(name)
356 doc = gettext(mod.__doc__) or ''
357 doc = gettext(mod.__doc__) or ''
357 if '\n' in doc.strip():
358 if '\n' in doc.strip():
358 msg = _("(use 'hg help -e %s' to show help for "
359 msg = _("(use 'hg help -e %s' to show help for "
359 "the %s extension)") % (name, name)
360 "the %s extension)") % (name, name)
360 rst.append('\n%s\n' % msg)
361 rst.append('\n%s\n' % msg)
361 except KeyError:
362 except KeyError:
362 pass
363 pass
363
364
364 # options
365 # options
365 if not ui.quiet and entry[1]:
366 if not ui.quiet and entry[1]:
366 rst.append(optrst(_("options"), entry[1], ui.verbose))
367 rst.append(optrst(_("options"), entry[1], ui.verbose))
367
368
368 if ui.verbose:
369 if ui.verbose:
369 rst.append(optrst(_("global options"),
370 rst.append(optrst(_("global options"),
370 commands.globalopts, ui.verbose))
371 commands.globalopts, ui.verbose))
371
372
372 if not ui.verbose:
373 if not ui.verbose:
373 if not full:
374 if not full:
374 rst.append(_("\n(use 'hg %s -h' to show more help)\n")
375 rst.append(_("\n(use 'hg %s -h' to show more help)\n")
375 % name)
376 % name)
376 elif not ui.quiet:
377 elif not ui.quiet:
377 rst.append(_('\n(some details hidden, use --verbose '
378 rst.append(_('\n(some details hidden, use --verbose '
378 'to show complete help)'))
379 'to show complete help)'))
379
380
380 return rst
381 return rst
381
382
382
383
383 def helplist(select=None, **opts):
384 def helplist(select=None, **opts):
384 # list of commands
385 # list of commands
385 if name == "shortlist":
386 if name == "shortlist":
386 header = _('basic commands:\n\n')
387 header = _('basic commands:\n\n')
387 elif name == "debug":
388 elif name == "debug":
388 header = _('debug commands (internal and unsupported):\n\n')
389 header = _('debug commands (internal and unsupported):\n\n')
389 else:
390 else:
390 header = _('list of commands:\n\n')
391 header = _('list of commands:\n\n')
391
392
392 h = {}
393 h = {}
393 cmds = {}
394 cmds = {}
394 for c, e in commands.table.iteritems():
395 for c, e in commands.table.iteritems():
395 f = c.partition("|")[0]
396 f = c.partition("|")[0]
396 if select and not select(f):
397 if select and not select(f):
397 continue
398 continue
398 if (not select and name != 'shortlist' and
399 if (not select and name != 'shortlist' and
399 e[0].__module__ != commands.__name__):
400 e[0].__module__ != commands.__name__):
400 continue
401 continue
401 if name == "shortlist" and not f.startswith("^"):
402 if name == "shortlist" and not f.startswith("^"):
402 continue
403 continue
403 f = f.lstrip("^")
404 f = f.lstrip("^")
404 doc = e[0].__doc__
405 doc = e[0].__doc__
405 if filtercmd(ui, f, name, doc):
406 if filtercmd(ui, f, name, doc):
406 continue
407 continue
407 doc = gettext(doc)
408 doc = gettext(doc)
408 if not doc:
409 if not doc:
409 doc = _("(no help text available)")
410 doc = _("(no help text available)")
410 h[f] = doc.splitlines()[0].rstrip()
411 h[f] = doc.splitlines()[0].rstrip()
411 cmds[f] = c.lstrip("^")
412 cmds[f] = c.lstrip("^")
412
413
413 rst = []
414 rst = []
414 if not h:
415 if not h:
415 if not ui.quiet:
416 if not ui.quiet:
416 rst.append(_('no commands defined\n'))
417 rst.append(_('no commands defined\n'))
417 return rst
418 return rst
418
419
419 if not ui.quiet:
420 if not ui.quiet:
420 rst.append(header)
421 rst.append(header)
421 fns = sorted(h)
422 fns = sorted(h)
422 for f in fns:
423 for f in fns:
423 if ui.verbose:
424 if ui.verbose:
424 commacmds = cmds[f].replace("|",", ")
425 commacmds = cmds[f].replace("|",", ")
425 rst.append(" :%s: %s\n" % (commacmds, h[f]))
426 rst.append(" :%s: %s\n" % (commacmds, h[f]))
426 else:
427 else:
427 rst.append(' :%s: %s\n' % (f, h[f]))
428 rst.append(' :%s: %s\n' % (f, h[f]))
428
429
429 ex = opts.get
430 ex = opts.get
430 anyopts = (ex('keyword') or not (ex('command') or ex('extension')))
431 anyopts = (ex('keyword') or not (ex('command') or ex('extension')))
431 if not name and anyopts:
432 if not name and anyopts:
432 exts = listexts(_('enabled extensions:'), extensions.enabled())
433 exts = listexts(_('enabled extensions:'), extensions.enabled())
433 if exts:
434 if exts:
434 rst.append('\n')
435 rst.append('\n')
435 rst.extend(exts)
436 rst.extend(exts)
436
437
437 rst.append(_("\nadditional help topics:\n\n"))
438 rst.append(_("\nadditional help topics:\n\n"))
438 topics = []
439 topics = []
439 for names, header, doc in helptable:
440 for names, header, doc in helptable:
440 topics.append((names[0], header))
441 topics.append((names[0], header))
441 for t, desc in topics:
442 for t, desc in topics:
442 rst.append(" :%s: %s\n" % (t, desc))
443 rst.append(" :%s: %s\n" % (t, desc))
443
444
444 if ui.quiet:
445 if ui.quiet:
445 pass
446 pass
446 elif ui.verbose:
447 elif ui.verbose:
447 rst.append('\n%s\n' % optrst(_("global options"),
448 rst.append('\n%s\n' % optrst(_("global options"),
448 commands.globalopts, ui.verbose))
449 commands.globalopts, ui.verbose))
449 if name == 'shortlist':
450 if name == 'shortlist':
450 rst.append(_("\n(use 'hg help' for the full list "
451 rst.append(_("\n(use 'hg help' for the full list "
451 "of commands)\n"))
452 "of commands)\n"))
452 else:
453 else:
453 if name == 'shortlist':
454 if name == 'shortlist':
454 rst.append(_("\n(use 'hg help' for the full list of commands "
455 rst.append(_("\n(use 'hg help' for the full list of commands "
455 "or 'hg -v' for details)\n"))
456 "or 'hg -v' for details)\n"))
456 elif name and not full:
457 elif name and not full:
457 rst.append(_("\n(use 'hg help %s' to show the full help "
458 rst.append(_("\n(use 'hg help %s' to show the full help "
458 "text)\n") % name)
459 "text)\n") % name)
459 elif name and cmds and name in cmds.keys():
460 elif name and cmds and name in cmds.keys():
460 rst.append(_("\n(use 'hg help -v -e %s' to show built-in "
461 rst.append(_("\n(use 'hg help -v -e %s' to show built-in "
461 "aliases and global options)\n") % name)
462 "aliases and global options)\n") % name)
462 else:
463 else:
463 rst.append(_("\n(use 'hg help -v%s' to show built-in aliases "
464 rst.append(_("\n(use 'hg help -v%s' to show built-in aliases "
464 "and global options)\n")
465 "and global options)\n")
465 % (name and " " + name or ""))
466 % (name and " " + name or ""))
466 return rst
467 return rst
467
468
468 def helptopic(name, subtopic=None):
469 def helptopic(name, subtopic=None):
469 # Look for sub-topic entry first.
470 # Look for sub-topic entry first.
470 header, doc = None, None
471 header, doc = None, None
471 if subtopic and name in subtopics:
472 if subtopic and name in subtopics:
472 for names, header, doc in subtopics[name]:
473 for names, header, doc in subtopics[name]:
473 if subtopic in names:
474 if subtopic in names:
474 break
475 break
475
476
476 if not header:
477 if not header:
477 for names, header, doc in helptable:
478 for names, header, doc in helptable:
478 if name in names:
479 if name in names:
479 break
480 break
480 else:
481 else:
481 raise error.UnknownCommand(name)
482 raise error.UnknownCommand(name)
482
483
483 rst = [minirst.section(header)]
484 rst = [minirst.section(header)]
484
485
485 # description
486 # description
486 if not doc:
487 if not doc:
487 rst.append(" %s\n" % _("(no help text available)"))
488 rst.append(" %s\n" % _("(no help text available)"))
488 if callable(doc):
489 if callable(doc):
489 rst += [" %s\n" % l for l in doc(ui).splitlines()]
490 rst += [" %s\n" % l for l in doc(ui).splitlines()]
490
491
491 if not ui.verbose:
492 if not ui.verbose:
492 omitted = _('(some details hidden, use --verbose'
493 omitted = _('(some details hidden, use --verbose'
493 ' to show complete help)')
494 ' to show complete help)')
494 indicateomitted(rst, omitted)
495 indicateomitted(rst, omitted)
495
496
496 try:
497 try:
497 cmdutil.findcmd(name, commands.table)
498 cmdutil.findcmd(name, commands.table)
498 rst.append(_("\nuse 'hg help -c %s' to see help for "
499 rst.append(_("\nuse 'hg help -c %s' to see help for "
499 "the %s command\n") % (name, name))
500 "the %s command\n") % (name, name))
500 except error.UnknownCommand:
501 except error.UnknownCommand:
501 pass
502 pass
502 return rst
503 return rst
503
504
504 def helpext(name, subtopic=None):
505 def helpext(name, subtopic=None):
505 try:
506 try:
506 mod = extensions.find(name)
507 mod = extensions.find(name)
507 doc = gettext(mod.__doc__) or _('no help text available')
508 doc = gettext(mod.__doc__) or _('no help text available')
508 except KeyError:
509 except KeyError:
509 mod = None
510 mod = None
510 doc = extensions.disabledext(name)
511 doc = extensions.disabledext(name)
511 if not doc:
512 if not doc:
512 raise error.UnknownCommand(name)
513 raise error.UnknownCommand(name)
513
514
514 if '\n' not in doc:
515 if '\n' not in doc:
515 head, tail = doc, ""
516 head, tail = doc, ""
516 else:
517 else:
517 head, tail = doc.split('\n', 1)
518 head, tail = doc.split('\n', 1)
518 rst = [_('%s extension - %s\n\n') % (name.rpartition('.')[-1], head)]
519 rst = [_('%s extension - %s\n\n') % (name.rpartition('.')[-1], head)]
519 if tail:
520 if tail:
520 rst.extend(tail.splitlines(True))
521 rst.extend(tail.splitlines(True))
521 rst.append('\n')
522 rst.append('\n')
522
523
523 if not ui.verbose:
524 if not ui.verbose:
524 omitted = _('(some details hidden, use --verbose'
525 omitted = _('(some details hidden, use --verbose'
525 ' to show complete help)')
526 ' to show complete help)')
526 indicateomitted(rst, omitted)
527 indicateomitted(rst, omitted)
527
528
528 if mod:
529 if mod:
529 try:
530 try:
530 ct = mod.cmdtable
531 ct = mod.cmdtable
531 except AttributeError:
532 except AttributeError:
532 ct = {}
533 ct = {}
533 modcmds = set([c.partition('|')[0] for c in ct])
534 modcmds = set([c.partition('|')[0] for c in ct])
534 rst.extend(helplist(modcmds.__contains__))
535 rst.extend(helplist(modcmds.__contains__))
535 else:
536 else:
536 rst.append(_("(use 'hg help extensions' for information on enabling"
537 rst.append(_("(use 'hg help extensions' for information on enabling"
537 " extensions)\n"))
538 " extensions)\n"))
538 return rst
539 return rst
539
540
540 def helpextcmd(name, subtopic=None):
541 def helpextcmd(name, subtopic=None):
541 cmd, ext, mod = extensions.disabledcmd(ui, name,
542 cmd, ext, mod = extensions.disabledcmd(ui, name,
542 ui.configbool('ui', 'strict'))
543 ui.configbool('ui', 'strict'))
543 doc = gettext(mod.__doc__).splitlines()[0]
544 doc = gettext(mod.__doc__).splitlines()[0]
544
545
545 rst = listexts(_("'%s' is provided by the following "
546 rst = listexts(_("'%s' is provided by the following "
546 "extension:") % cmd, {ext: doc}, indent=4,
547 "extension:") % cmd, {ext: doc}, indent=4,
547 showdeprecated=True)
548 showdeprecated=True)
548 rst.append('\n')
549 rst.append('\n')
549 rst.append(_("(use 'hg help extensions' for information on enabling "
550 rst.append(_("(use 'hg help extensions' for information on enabling "
550 "extensions)\n"))
551 "extensions)\n"))
551 return rst
552 return rst
552
553
553
554
554 rst = []
555 rst = []
555 kw = opts.get('keyword')
556 kw = opts.get('keyword')
556 if kw or name is None and any(opts[o] for o in opts):
557 if kw or name is None and any(opts[o] for o in opts):
557 matches = topicmatch(ui, name or '')
558 matches = topicmatch(ui, name or '')
558 helpareas = []
559 helpareas = []
559 if opts.get('extension'):
560 if opts.get('extension'):
560 helpareas += [('extensions', _('Extensions'))]
561 helpareas += [('extensions', _('Extensions'))]
561 if opts.get('command'):
562 if opts.get('command'):
562 helpareas += [('commands', _('Commands'))]
563 helpareas += [('commands', _('Commands'))]
563 if not helpareas:
564 if not helpareas:
564 helpareas = [('topics', _('Topics')),
565 helpareas = [('topics', _('Topics')),
565 ('commands', _('Commands')),
566 ('commands', _('Commands')),
566 ('extensions', _('Extensions')),
567 ('extensions', _('Extensions')),
567 ('extensioncommands', _('Extension Commands'))]
568 ('extensioncommands', _('Extension Commands'))]
568 for t, title in helpareas:
569 for t, title in helpareas:
569 if matches[t]:
570 if matches[t]:
570 rst.append('%s:\n\n' % title)
571 rst.append('%s:\n\n' % title)
571 rst.extend(minirst.maketable(sorted(matches[t]), 1))
572 rst.extend(minirst.maketable(sorted(matches[t]), 1))
572 rst.append('\n')
573 rst.append('\n')
573 if not rst:
574 if not rst:
574 msg = _('no matches')
575 msg = _('no matches')
575 hint = _("try 'hg help' for a list of topics")
576 hint = _("try 'hg help' for a list of topics")
576 raise error.Abort(msg, hint=hint)
577 raise error.Abort(msg, hint=hint)
577 elif name and name != 'shortlist':
578 elif name and name != 'shortlist':
578 queries = []
579 queries = []
579 if unknowncmd:
580 if unknowncmd:
580 queries += [helpextcmd]
581 queries += [helpextcmd]
581 if opts.get('extension'):
582 if opts.get('extension'):
582 queries += [helpext]
583 queries += [helpext]
583 if opts.get('command'):
584 if opts.get('command'):
584 queries += [helpcmd]
585 queries += [helpcmd]
585 if not queries:
586 if not queries:
586 queries = (helptopic, helpcmd, helpext, helpextcmd)
587 queries = (helptopic, helpcmd, helpext, helpextcmd)
587 for f in queries:
588 for f in queries:
588 try:
589 try:
589 rst = f(name, subtopic)
590 rst = f(name, subtopic)
590 break
591 break
591 except error.UnknownCommand:
592 except error.UnknownCommand:
592 pass
593 pass
593 else:
594 else:
594 if unknowncmd:
595 if unknowncmd:
595 raise error.UnknownCommand(name)
596 raise error.UnknownCommand(name)
596 else:
597 else:
597 msg = _('no such help topic: %s') % name
598 msg = _('no such help topic: %s') % name
598 hint = _("try 'hg help --keyword %s'") % name
599 hint = _("try 'hg help --keyword %s'") % name
599 raise error.Abort(msg, hint=hint)
600 raise error.Abort(msg, hint=hint)
600 else:
601 else:
601 # program name
602 # program name
602 if not ui.quiet:
603 if not ui.quiet:
603 rst = [_("Mercurial Distributed SCM\n"), '\n']
604 rst = [_("Mercurial Distributed SCM\n"), '\n']
604 rst.extend(helplist(None, **opts))
605 rst.extend(helplist(None, **opts))
605
606
606 return ''.join(rst)
607 return ''.join(rst)
General Comments 0
You need to be logged in to leave comments. Login now