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