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