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