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