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