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