##// END OF EJS Templates
internals: copy-edit "register" -> "registrar" in configitem docs
Kevin Bullock -
r34952:fb7f58da stable
parent child Browse files
Show More
@@ -1,678 +1,678 b''
1 1 # help.py - help data for mercurial
2 2 #
3 3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import itertools
11 11 import os
12 12 import textwrap
13 13
14 14 from .i18n import (
15 15 _,
16 16 gettext,
17 17 )
18 18 from . import (
19 19 cmdutil,
20 20 encoding,
21 21 error,
22 22 extensions,
23 23 filemerge,
24 24 fileset,
25 25 minirst,
26 26 pycompat,
27 27 revset,
28 28 templatefilters,
29 29 templatekw,
30 30 templater,
31 31 util,
32 32 )
33 33 from .hgweb import (
34 34 webcommands,
35 35 )
36 36
37 37 _exclkeywords = {
38 38 "(ADVANCED)",
39 39 "(DEPRECATED)",
40 40 "(EXPERIMENTAL)",
41 41 # i18n: "(ADVANCED)" is a keyword, must be translated consistently
42 42 _("(ADVANCED)"),
43 43 # i18n: "(DEPRECATED)" is a keyword, must be translated consistently
44 44 _("(DEPRECATED)"),
45 45 # i18n: "(EXPERIMENTAL)" is a keyword, must be translated consistently
46 46 _("(EXPERIMENTAL)"),
47 47 }
48 48
49 49 def listexts(header, exts, indent=1, showdeprecated=False):
50 50 '''return a text listing of the given extensions'''
51 51 rst = []
52 52 if exts:
53 53 for name, desc in sorted(exts.iteritems()):
54 54 if not showdeprecated and any(w in desc for w in _exclkeywords):
55 55 continue
56 56 rst.append('%s:%s: %s\n' % (' ' * indent, name, desc))
57 57 if rst:
58 58 rst.insert(0, '\n%s\n\n' % header)
59 59 return rst
60 60
61 61 def extshelp(ui):
62 62 rst = loaddoc('extensions')(ui).splitlines(True)
63 63 rst.extend(listexts(
64 64 _('enabled extensions:'), extensions.enabled(), showdeprecated=True))
65 65 rst.extend(listexts(_('disabled extensions:'), extensions.disabled()))
66 66 doc = ''.join(rst)
67 67 return doc
68 68
69 69 def optrst(header, options, verbose):
70 70 data = []
71 71 multioccur = False
72 72 for option in options:
73 73 if len(option) == 5:
74 74 shortopt, longopt, default, desc, optlabel = option
75 75 else:
76 76 shortopt, longopt, default, desc = option
77 77 optlabel = _("VALUE") # default label
78 78
79 79 if not verbose and any(w in desc for w in _exclkeywords):
80 80 continue
81 81
82 82 so = ''
83 83 if shortopt:
84 84 so = '-' + shortopt
85 85 lo = '--' + longopt
86 86 if default:
87 87 # default is of unknown type, and in Python 2 we abused
88 88 # the %s-shows-repr property to handle integers etc. To
89 89 # match that behavior on Python 3, we do str(default) and
90 90 # then convert it to bytes.
91 91 desc += _(" (default: %s)") % pycompat.bytestr(default)
92 92
93 93 if isinstance(default, list):
94 94 lo += " %s [+]" % optlabel
95 95 multioccur = True
96 96 elif (default is not None) and not isinstance(default, bool):
97 97 lo += " %s" % optlabel
98 98
99 99 data.append((so, lo, desc))
100 100
101 101 if multioccur:
102 102 header += (_(" ([+] can be repeated)"))
103 103
104 104 rst = ['\n%s:\n\n' % header]
105 105 rst.extend(minirst.maketable(data, 1))
106 106
107 107 return ''.join(rst)
108 108
109 109 def indicateomitted(rst, omitted, notomitted=None):
110 110 rst.append('\n\n.. container:: omitted\n\n %s\n\n' % omitted)
111 111 if notomitted:
112 112 rst.append('\n\n.. container:: notomitted\n\n %s\n\n' % notomitted)
113 113
114 114 def filtercmd(ui, cmd, kw, doc):
115 115 if not ui.debugflag and cmd.startswith("debug") and kw != "debug":
116 116 return True
117 117 if not ui.verbose and doc and any(w in doc for w in _exclkeywords):
118 118 return True
119 119 return False
120 120
121 121 def topicmatch(ui, commands, kw):
122 122 """Return help topics matching kw.
123 123
124 124 Returns {'section': [(name, summary), ...], ...} where section is
125 125 one of topics, commands, extensions, or extensioncommands.
126 126 """
127 127 kw = encoding.lower(kw)
128 128 def lowercontains(container):
129 129 return kw in encoding.lower(container) # translated in helptable
130 130 results = {'topics': [],
131 131 'commands': [],
132 132 'extensions': [],
133 133 'extensioncommands': [],
134 134 }
135 135 for names, header, doc in helptable:
136 136 # Old extensions may use a str as doc.
137 137 if (sum(map(lowercontains, names))
138 138 or lowercontains(header)
139 139 or (callable(doc) and lowercontains(doc(ui)))):
140 140 results['topics'].append((names[0], header))
141 141 for cmd, entry in commands.table.iteritems():
142 142 if len(entry) == 3:
143 143 summary = entry[2]
144 144 else:
145 145 summary = ''
146 146 # translate docs *before* searching there
147 147 docs = _(pycompat.getdoc(entry[0])) or ''
148 148 if kw in cmd or lowercontains(summary) or lowercontains(docs):
149 149 doclines = docs.splitlines()
150 150 if doclines:
151 151 summary = doclines[0]
152 152 cmdname = cmd.partition('|')[0].lstrip('^')
153 153 if filtercmd(ui, cmdname, kw, docs):
154 154 continue
155 155 results['commands'].append((cmdname, summary))
156 156 for name, docs in itertools.chain(
157 157 extensions.enabled(False).iteritems(),
158 158 extensions.disabled().iteritems()):
159 159 if not docs:
160 160 continue
161 161 name = name.rpartition('.')[-1]
162 162 if lowercontains(name) or lowercontains(docs):
163 163 # extension docs are already translated
164 164 results['extensions'].append((name, docs.splitlines()[0]))
165 165 try:
166 166 mod = extensions.load(ui, name, '')
167 167 except ImportError:
168 168 # debug message would be printed in extensions.load()
169 169 continue
170 170 for cmd, entry in getattr(mod, 'cmdtable', {}).iteritems():
171 171 if kw in cmd or (len(entry) > 2 and lowercontains(entry[2])):
172 172 cmdname = cmd.partition('|')[0].lstrip('^')
173 173 cmddoc = pycompat.getdoc(entry[0])
174 174 if cmddoc:
175 175 cmddoc = gettext(cmddoc).splitlines()[0]
176 176 else:
177 177 cmddoc = _('(no help text available)')
178 178 if filtercmd(ui, cmdname, kw, cmddoc):
179 179 continue
180 180 results['extensioncommands'].append((cmdname, cmddoc))
181 181 return results
182 182
183 183 def loaddoc(topic, subdir=None):
184 184 """Return a delayed loader for help/topic.txt."""
185 185
186 186 def loader(ui):
187 187 docdir = os.path.join(util.datapath, 'help')
188 188 if subdir:
189 189 docdir = os.path.join(docdir, subdir)
190 190 path = os.path.join(docdir, topic + ".txt")
191 191 doc = gettext(util.readfile(path))
192 192 for rewriter in helphooks.get(topic, []):
193 193 doc = rewriter(ui, topic, doc)
194 194 return doc
195 195
196 196 return loader
197 197
198 198 internalstable = sorted([
199 199 (['bundles'], _('Bundles'),
200 200 loaddoc('bundles', subdir='internals')),
201 201 (['censor'], _('Censor'),
202 202 loaddoc('censor', subdir='internals')),
203 203 (['changegroups'], _('Changegroups'),
204 204 loaddoc('changegroups', subdir='internals')),
205 (['config'], _('Config Register'),
205 (['config'], _('Config Registrar'),
206 206 loaddoc('config', subdir='internals')),
207 207 (['requirements'], _('Repository Requirements'),
208 208 loaddoc('requirements', subdir='internals')),
209 209 (['revlogs'], _('Revision Logs'),
210 210 loaddoc('revlogs', subdir='internals')),
211 211 (['wireprotocol'], _('Wire Protocol'),
212 212 loaddoc('wireprotocol', subdir='internals')),
213 213 ])
214 214
215 215 def internalshelp(ui):
216 216 """Generate the index for the "internals" topic."""
217 217 lines = ['To access a subtopic, use "hg help internals.{subtopic-name}"\n',
218 218 '\n']
219 219 for names, header, doc in internalstable:
220 220 lines.append(' :%s: %s\n' % (names[0], header))
221 221
222 222 return ''.join(lines)
223 223
224 224 helptable = sorted([
225 225 (['bundlespec'], _("Bundle File Formats"), loaddoc('bundlespec')),
226 226 (['color'], _("Colorizing Outputs"), loaddoc('color')),
227 227 (["config", "hgrc"], _("Configuration Files"), loaddoc('config')),
228 228 (["dates"], _("Date Formats"), loaddoc('dates')),
229 229 (["patterns"], _("File Name Patterns"), loaddoc('patterns')),
230 230 (['environment', 'env'], _('Environment Variables'),
231 231 loaddoc('environment')),
232 232 (['revisions', 'revs', 'revsets', 'revset', 'multirevs', 'mrevs'],
233 233 _('Specifying Revisions'), loaddoc('revisions')),
234 234 (['filesets', 'fileset'], _("Specifying File Sets"), loaddoc('filesets')),
235 235 (['diffs'], _('Diff Formats'), loaddoc('diffs')),
236 236 (['merge-tools', 'mergetools', 'mergetool'], _('Merge Tools'),
237 237 loaddoc('merge-tools')),
238 238 (['templating', 'templates', 'template', 'style'], _('Template Usage'),
239 239 loaddoc('templates')),
240 240 (['urls'], _('URL Paths'), loaddoc('urls')),
241 241 (["extensions"], _("Using Additional Features"), extshelp),
242 242 (["subrepos", "subrepo"], _("Subrepositories"), loaddoc('subrepos')),
243 243 (["hgweb"], _("Configuring hgweb"), loaddoc('hgweb')),
244 244 (["glossary"], _("Glossary"), loaddoc('glossary')),
245 245 (["hgignore", "ignore"], _("Syntax for Mercurial Ignore Files"),
246 246 loaddoc('hgignore')),
247 247 (["phases"], _("Working with Phases"), loaddoc('phases')),
248 248 (['scripting'], _('Using Mercurial from scripts and automation'),
249 249 loaddoc('scripting')),
250 250 (['internals'], _("Technical implementation topics"),
251 251 internalshelp),
252 252 (['pager'], _("Pager Support"), loaddoc('pager')),
253 253 ])
254 254
255 255 # Maps topics with sub-topics to a list of their sub-topics.
256 256 subtopics = {
257 257 'internals': internalstable,
258 258 }
259 259
260 260 # Map topics to lists of callable taking the current topic help and
261 261 # returning the updated version
262 262 helphooks = {}
263 263
264 264 def addtopichook(topic, rewriter):
265 265 helphooks.setdefault(topic, []).append(rewriter)
266 266
267 267 def makeitemsdoc(ui, topic, doc, marker, items, dedent=False):
268 268 """Extract docstring from the items key to function mapping, build a
269 269 single documentation block and use it to overwrite the marker in doc.
270 270 """
271 271 entries = []
272 272 for name in sorted(items):
273 273 text = (pycompat.getdoc(items[name]) or '').rstrip()
274 274 if (not text
275 275 or not ui.verbose and any(w in text for w in _exclkeywords)):
276 276 continue
277 277 text = gettext(text)
278 278 if dedent:
279 279 # Abuse latin1 to use textwrap.dedent() on bytes.
280 280 text = textwrap.dedent(text.decode('latin1')).encode('latin1')
281 281 lines = text.splitlines()
282 282 doclines = [(lines[0])]
283 283 for l in lines[1:]:
284 284 # Stop once we find some Python doctest
285 285 if l.strip().startswith('>>>'):
286 286 break
287 287 if dedent:
288 288 doclines.append(l.rstrip())
289 289 else:
290 290 doclines.append(' ' + l.strip())
291 291 entries.append('\n'.join(doclines))
292 292 entries = '\n\n'.join(entries)
293 293 return doc.replace(marker, entries)
294 294
295 295 def addtopicsymbols(topic, marker, symbols, dedent=False):
296 296 def add(ui, topic, doc):
297 297 return makeitemsdoc(ui, topic, doc, marker, symbols, dedent=dedent)
298 298 addtopichook(topic, add)
299 299
300 300 addtopicsymbols('bundlespec', '.. bundlecompressionmarker',
301 301 util.bundlecompressiontopics())
302 302 addtopicsymbols('filesets', '.. predicatesmarker', fileset.symbols)
303 303 addtopicsymbols('merge-tools', '.. internaltoolsmarker',
304 304 filemerge.internalsdoc)
305 305 addtopicsymbols('revisions', '.. predicatesmarker', revset.symbols)
306 306 addtopicsymbols('templates', '.. keywordsmarker', templatekw.keywords)
307 307 addtopicsymbols('templates', '.. filtersmarker', templatefilters.filters)
308 308 addtopicsymbols('templates', '.. functionsmarker', templater.funcs)
309 309 addtopicsymbols('hgweb', '.. webcommandsmarker', webcommands.commands,
310 310 dedent=True)
311 311
312 312 def help_(ui, commands, name, unknowncmd=False, full=True, subtopic=None,
313 313 **opts):
314 314 '''
315 315 Generate the help for 'name' as unformatted restructured text. If
316 316 'name' is None, describe the commands available.
317 317 '''
318 318
319 319 opts = pycompat.byteskwargs(opts)
320 320
321 321 def helpcmd(name, subtopic=None):
322 322 try:
323 323 aliases, entry = cmdutil.findcmd(name, commands.table,
324 324 strict=unknowncmd)
325 325 except error.AmbiguousCommand as inst:
326 326 # py3k fix: except vars can't be used outside the scope of the
327 327 # except block, nor can be used inside a lambda. python issue4617
328 328 prefix = inst.args[0]
329 329 select = lambda c: c.lstrip('^').startswith(prefix)
330 330 rst = helplist(select)
331 331 return rst
332 332
333 333 rst = []
334 334
335 335 # check if it's an invalid alias and display its error if it is
336 336 if getattr(entry[0], 'badalias', None):
337 337 rst.append(entry[0].badalias + '\n')
338 338 if entry[0].unknowncmd:
339 339 try:
340 340 rst.extend(helpextcmd(entry[0].cmdname))
341 341 except error.UnknownCommand:
342 342 pass
343 343 return rst
344 344
345 345 # synopsis
346 346 if len(entry) > 2:
347 347 if entry[2].startswith('hg'):
348 348 rst.append("%s\n" % entry[2])
349 349 else:
350 350 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
351 351 else:
352 352 rst.append('hg %s\n' % aliases[0])
353 353 # aliases
354 354 if full and not ui.quiet and len(aliases) > 1:
355 355 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
356 356 rst.append('\n')
357 357
358 358 # description
359 359 doc = gettext(pycompat.getdoc(entry[0]))
360 360 if not doc:
361 361 doc = _("(no help text available)")
362 362 if util.safehasattr(entry[0], 'definition'): # aliased command
363 363 source = entry[0].source
364 364 if entry[0].definition.startswith('!'): # shell alias
365 365 doc = (_('shell alias for::\n\n %s\n\ndefined by: %s\n') %
366 366 (entry[0].definition[1:], source))
367 367 else:
368 368 doc = (_('alias for: hg %s\n\n%s\n\ndefined by: %s\n') %
369 369 (entry[0].definition, doc, source))
370 370 doc = doc.splitlines(True)
371 371 if ui.quiet or not full:
372 372 rst.append(doc[0])
373 373 else:
374 374 rst.extend(doc)
375 375 rst.append('\n')
376 376
377 377 # check if this command shadows a non-trivial (multi-line)
378 378 # extension help text
379 379 try:
380 380 mod = extensions.find(name)
381 381 doc = gettext(pycompat.getdoc(mod)) or ''
382 382 if '\n' in doc.strip():
383 383 msg = _("(use 'hg help -e %s' to show help for "
384 384 "the %s extension)") % (name, name)
385 385 rst.append('\n%s\n' % msg)
386 386 except KeyError:
387 387 pass
388 388
389 389 # options
390 390 if not ui.quiet and entry[1]:
391 391 rst.append(optrst(_("options"), entry[1], ui.verbose))
392 392
393 393 if ui.verbose:
394 394 rst.append(optrst(_("global options"),
395 395 commands.globalopts, ui.verbose))
396 396
397 397 if not ui.verbose:
398 398 if not full:
399 399 rst.append(_("\n(use 'hg %s -h' to show more help)\n")
400 400 % name)
401 401 elif not ui.quiet:
402 402 rst.append(_('\n(some details hidden, use --verbose '
403 403 'to show complete help)'))
404 404
405 405 return rst
406 406
407 407
408 408 def helplist(select=None, **opts):
409 409 # list of commands
410 410 if name == "shortlist":
411 411 header = _('basic commands:\n\n')
412 412 elif name == "debug":
413 413 header = _('debug commands (internal and unsupported):\n\n')
414 414 else:
415 415 header = _('list of commands:\n\n')
416 416
417 417 h = {}
418 418 cmds = {}
419 419 for c, e in commands.table.iteritems():
420 420 f = c.partition("|")[0]
421 421 if select and not select(f):
422 422 continue
423 423 if (not select and name != 'shortlist' and
424 424 e[0].__module__ != commands.__name__):
425 425 continue
426 426 if name == "shortlist" and not f.startswith("^"):
427 427 continue
428 428 f = f.lstrip("^")
429 429 doc = pycompat.getdoc(e[0])
430 430 if filtercmd(ui, f, name, doc):
431 431 continue
432 432 doc = gettext(doc)
433 433 if not doc:
434 434 doc = _("(no help text available)")
435 435 h[f] = doc.splitlines()[0].rstrip()
436 436 cmds[f] = c.lstrip("^")
437 437
438 438 rst = []
439 439 if not h:
440 440 if not ui.quiet:
441 441 rst.append(_('no commands defined\n'))
442 442 return rst
443 443
444 444 if not ui.quiet:
445 445 rst.append(header)
446 446 fns = sorted(h)
447 447 for f in fns:
448 448 if ui.verbose:
449 449 commacmds = cmds[f].replace("|",", ")
450 450 rst.append(" :%s: %s\n" % (commacmds, h[f]))
451 451 else:
452 452 rst.append(' :%s: %s\n' % (f, h[f]))
453 453
454 454 ex = opts.get
455 455 anyopts = (ex('keyword') or not (ex('command') or ex('extension')))
456 456 if not name and anyopts:
457 457 exts = listexts(_('enabled extensions:'), extensions.enabled())
458 458 if exts:
459 459 rst.append('\n')
460 460 rst.extend(exts)
461 461
462 462 rst.append(_("\nadditional help topics:\n\n"))
463 463 topics = []
464 464 for names, header, doc in helptable:
465 465 topics.append((names[0], header))
466 466 for t, desc in topics:
467 467 rst.append(" :%s: %s\n" % (t, desc))
468 468
469 469 if ui.quiet:
470 470 pass
471 471 elif ui.verbose:
472 472 rst.append('\n%s\n' % optrst(_("global options"),
473 473 commands.globalopts, ui.verbose))
474 474 if name == 'shortlist':
475 475 rst.append(_("\n(use 'hg help' for the full list "
476 476 "of commands)\n"))
477 477 else:
478 478 if name == 'shortlist':
479 479 rst.append(_("\n(use 'hg help' for the full list of commands "
480 480 "or 'hg -v' for details)\n"))
481 481 elif name and not full:
482 482 rst.append(_("\n(use 'hg help %s' to show the full help "
483 483 "text)\n") % name)
484 484 elif name and cmds and name in cmds.keys():
485 485 rst.append(_("\n(use 'hg help -v -e %s' to show built-in "
486 486 "aliases and global options)\n") % name)
487 487 else:
488 488 rst.append(_("\n(use 'hg help -v%s' to show built-in aliases "
489 489 "and global options)\n")
490 490 % (name and " " + name or ""))
491 491 return rst
492 492
493 493 def helptopic(name, subtopic=None):
494 494 # Look for sub-topic entry first.
495 495 header, doc = None, None
496 496 if subtopic and name in subtopics:
497 497 for names, header, doc in subtopics[name]:
498 498 if subtopic in names:
499 499 break
500 500
501 501 if not header:
502 502 for names, header, doc in helptable:
503 503 if name in names:
504 504 break
505 505 else:
506 506 raise error.UnknownCommand(name)
507 507
508 508 rst = [minirst.section(header)]
509 509
510 510 # description
511 511 if not doc:
512 512 rst.append(" %s\n" % _("(no help text available)"))
513 513 if callable(doc):
514 514 rst += [" %s\n" % l for l in doc(ui).splitlines()]
515 515
516 516 if not ui.verbose:
517 517 omitted = _('(some details hidden, use --verbose'
518 518 ' to show complete help)')
519 519 indicateomitted(rst, omitted)
520 520
521 521 try:
522 522 cmdutil.findcmd(name, commands.table)
523 523 rst.append(_("\nuse 'hg help -c %s' to see help for "
524 524 "the %s command\n") % (name, name))
525 525 except error.UnknownCommand:
526 526 pass
527 527 return rst
528 528
529 529 def helpext(name, subtopic=None):
530 530 try:
531 531 mod = extensions.find(name)
532 532 doc = gettext(pycompat.getdoc(mod)) or _('no help text available')
533 533 except KeyError:
534 534 mod = None
535 535 doc = extensions.disabledext(name)
536 536 if not doc:
537 537 raise error.UnknownCommand(name)
538 538
539 539 if '\n' not in doc:
540 540 head, tail = doc, ""
541 541 else:
542 542 head, tail = doc.split('\n', 1)
543 543 rst = [_('%s extension - %s\n\n') % (name.rpartition('.')[-1], head)]
544 544 if tail:
545 545 rst.extend(tail.splitlines(True))
546 546 rst.append('\n')
547 547
548 548 if not ui.verbose:
549 549 omitted = _('(some details hidden, use --verbose'
550 550 ' to show complete help)')
551 551 indicateomitted(rst, omitted)
552 552
553 553 if mod:
554 554 try:
555 555 ct = mod.cmdtable
556 556 except AttributeError:
557 557 ct = {}
558 558 modcmds = set([c.partition('|')[0] for c in ct])
559 559 rst.extend(helplist(modcmds.__contains__))
560 560 else:
561 561 rst.append(_("(use 'hg help extensions' for information on enabling"
562 562 " extensions)\n"))
563 563 return rst
564 564
565 565 def helpextcmd(name, subtopic=None):
566 566 cmd, ext, mod = extensions.disabledcmd(ui, name,
567 567 ui.configbool('ui', 'strict'))
568 568 doc = gettext(pycompat.getdoc(mod)).splitlines()[0]
569 569
570 570 rst = listexts(_("'%s' is provided by the following "
571 571 "extension:") % cmd, {ext: doc}, indent=4,
572 572 showdeprecated=True)
573 573 rst.append('\n')
574 574 rst.append(_("(use 'hg help extensions' for information on enabling "
575 575 "extensions)\n"))
576 576 return rst
577 577
578 578
579 579 rst = []
580 580 kw = opts.get('keyword')
581 581 if kw or name is None and any(opts[o] for o in opts):
582 582 matches = topicmatch(ui, commands, name or '')
583 583 helpareas = []
584 584 if opts.get('extension'):
585 585 helpareas += [('extensions', _('Extensions'))]
586 586 if opts.get('command'):
587 587 helpareas += [('commands', _('Commands'))]
588 588 if not helpareas:
589 589 helpareas = [('topics', _('Topics')),
590 590 ('commands', _('Commands')),
591 591 ('extensions', _('Extensions')),
592 592 ('extensioncommands', _('Extension Commands'))]
593 593 for t, title in helpareas:
594 594 if matches[t]:
595 595 rst.append('%s:\n\n' % title)
596 596 rst.extend(minirst.maketable(sorted(matches[t]), 1))
597 597 rst.append('\n')
598 598 if not rst:
599 599 msg = _('no matches')
600 600 hint = _("try 'hg help' for a list of topics")
601 601 raise error.Abort(msg, hint=hint)
602 602 elif name and name != 'shortlist':
603 603 queries = []
604 604 if unknowncmd:
605 605 queries += [helpextcmd]
606 606 if opts.get('extension'):
607 607 queries += [helpext]
608 608 if opts.get('command'):
609 609 queries += [helpcmd]
610 610 if not queries:
611 611 queries = (helptopic, helpcmd, helpext, helpextcmd)
612 612 for f in queries:
613 613 try:
614 614 rst = f(name, subtopic)
615 615 break
616 616 except error.UnknownCommand:
617 617 pass
618 618 else:
619 619 if unknowncmd:
620 620 raise error.UnknownCommand(name)
621 621 else:
622 622 msg = _('no such help topic: %s') % name
623 623 hint = _("try 'hg help --keyword %s'") % name
624 624 raise error.Abort(msg, hint=hint)
625 625 else:
626 626 # program name
627 627 if not ui.quiet:
628 628 rst = [_("Mercurial Distributed SCM\n"), '\n']
629 629 rst.extend(helplist(None, **pycompat.strkwargs(opts)))
630 630
631 631 return ''.join(rst)
632 632
633 633 def formattedhelp(ui, commands, name, keep=None, unknowncmd=False, full=True,
634 634 **opts):
635 635 """get help for a given topic (as a dotted name) as rendered rst
636 636
637 637 Either returns the rendered help text or raises an exception.
638 638 """
639 639 if keep is None:
640 640 keep = []
641 641 else:
642 642 keep = list(keep) # make a copy so we can mutate this later
643 643 fullname = name
644 644 section = None
645 645 subtopic = None
646 646 if name and '.' in name:
647 647 name, remaining = name.split('.', 1)
648 648 remaining = encoding.lower(remaining)
649 649 if '.' in remaining:
650 650 subtopic, section = remaining.split('.', 1)
651 651 else:
652 652 if name in subtopics:
653 653 subtopic = remaining
654 654 else:
655 655 section = remaining
656 656 textwidth = ui.configint('ui', 'textwidth')
657 657 termwidth = ui.termwidth() - 2
658 658 if textwidth <= 0 or termwidth < textwidth:
659 659 textwidth = termwidth
660 660 text = help_(ui, commands, name,
661 661 subtopic=subtopic, unknowncmd=unknowncmd, full=full, **opts)
662 662
663 663 formatted, pruned = minirst.format(text, textwidth, keep=keep,
664 664 section=section)
665 665
666 666 # We could have been given a weird ".foo" section without a name
667 667 # to look for, or we could have simply failed to found "foo.bar"
668 668 # because bar isn't a section of foo
669 669 if section and not (formatted and name):
670 670 raise error.Abort(_("help section not found: %s") % fullname)
671 671
672 672 if 'verbose' in pruned:
673 673 keep.append('omitted')
674 674 else:
675 675 keep.append('notomitted')
676 676 formatted, pruned = minirst.format(text, textwidth, keep=keep,
677 677 section=section)
678 678 return formatted
@@ -1,108 +1,108 b''
1 1 All config options used within Mercurial should be registered.
2 2
3 3 Config Option in Core
4 4 =====================
5 5
6 6 Config options used by Mercurial core are registered in the
7 7 ``mercurial.configitems`` module.
8 8
9 9 Simple entry
10 10 ------------
11 11
12 12 A registration entry typically looks like::
13 13
14 14 coreconfigitem('section', 'option',
15 15 default=MyDefaultValue,
16 16 )
17 17
18 18 Once registered, Mercurial will know that ``section.option`` is a legitimate
19 19 config option and that ``MyDefaultValue`` should be used if no other values are
20 20 defined in configuration files.
21 21
22 22 Complex default value
23 23 ---------------------
24 24
25 25 If the default provided is a callable, it is called to retrieve the default
26 26 value when accessing the config option. This is useful for default values that
27 27 are mutable like the empty list::
28 28
29 29 coreconfigitem('pager', 'ignore',
30 30 default=list,
31 31 )
32 32
33 33 In addition, there are cases where the default is not fixed, but computed from
34 34 other properties. In this case, use the ``dynamicdefault`` object as the value
35 35 for the ``default`` parameter. A default value is then explicitly required when
36 36 reading the option::
37 37
38 38 # registration
39 39 coreconfigitem('web', 'name',
40 40 default=dynamicdefault,
41 41 )
42 42
43 43 # usage
44 44 ui.config('web', 'name', dirname)
45 45
46 46 Free form options
47 47 -----------------
48 48
49 49 Some config sections use free form options (e.g. ``paths``). You can register
50 50 them using the ``generic`` parameters::
51 51
52 52 coreconfigitem('paths', '.*',
53 53 default=None,
54 54 generic=True,
55 55 )
56 56
57 57 When ``generic=True`` is set, the option name is matched as a regular expression
58 58 (rooted to string start). It can be used to select specific sub parameters::
59 59
60 60 coreconfigitem('merge-tools', br'.*\.args$',
61 61 default="$local $base $other",
62 62 generic=True,
63 63 priority=-1,
64 64 )
65 65
66 66 The ``priority`` parameter controls the order used to match the generic pattern
67 67 (lower first).
68 68
69 69 Config Option in Extensions
70 70 ===========================
71 71
72 72 General case
73 73 ------------
74 74
75 75 Extensions should register config items through the ``registrar`` API (also used
76 76 for commands and others)::
77 77
78 78 configtable = {}
79 79 configitem = registrar.configitem(configtable)
80 80
81 81 configitem('blackbox', 'dirty',
82 82 default=False,
83 83 )
84 84
85 85 The ``dynamicdefault`` object is then available as
86 86 ``configitem.dynamicdefault``.
87 87
88 88 Supporting older versions
89 89 -------------------------
90 90
91 The registry was introduced in Mercurial 4.3, and the ``generic`` parameter was
91 The registrar was introduced in Mercurial 4.3, and the ``generic`` parameter was
92 92 introduced in 4.4. Starting with Mercurial 4.4, all core options were registered
93 93 and developer warnings are emitted when accessing unregistered option.
94 94
95 95 Extensions supporting versions older than Mercurial 4.3 cannot rely on the
96 96 default value being registered. The simplest way to register an option while
97 97 still supporting an older version is to use ``dynamicdefault`` for options
98 98 requiring a default value. The existing code passing an explicit default can
99 99 then stay in use until compatibility with Mercurial 4.2 is dropped.
100 100
101 101 As reminder, here are the default values for each config type:
102 102 - config: None
103 103 - configbool: False
104 104 - configbytes: 0
105 105 - configdate: None
106 106 - configint: None
107 107 - configlist: []
108 108 - configpath: None
General Comments 0
You need to be logged in to leave comments. Login now