##// END OF EJS Templates
help: fix search with `-k` option in non-ASCII locales...
Nikolaj Sjujskij -
r16845:4594729c default
parent child Browse files
Show More
@@ -1,199 +1,201
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, sys, os
9 import itertools, sys, os
10 import extensions, revset, fileset, templatekw, templatefilters, filemerge
10 import extensions, revset, fileset, templatekw, templatefilters, filemerge
11 import encoding, util, minirst
11 import encoding, util, minirst
12
12
13 def listexts(header, exts, indent=1):
13 def listexts(header, exts, indent=1):
14 '''return a text listing of the given extensions'''
14 '''return a text listing of the given extensions'''
15 if not exts:
15 if not exts:
16 return ''
16 return ''
17 maxlength = max(len(e) for e in exts)
17 maxlength = max(len(e) for e in exts)
18 result = '\n%s\n\n' % header
18 result = '\n%s\n\n' % header
19 for name, desc in sorted(exts.iteritems()):
19 for name, desc in sorted(exts.iteritems()):
20 result += '%s%-*s %s\n' % (' ' * indent, maxlength + 2,
20 result += '%s%-*s %s\n' % (' ' * indent, maxlength + 2,
21 ':%s:' % name, desc)
21 ':%s:' % name, desc)
22 return result
22 return result
23
23
24 def extshelp():
24 def extshelp():
25 doc = loaddoc('extensions')()
25 doc = loaddoc('extensions')()
26 doc += listexts(_('enabled extensions:'), extensions.enabled())
26 doc += listexts(_('enabled extensions:'), extensions.enabled())
27 doc += listexts(_('disabled extensions:'), extensions.disabled())
27 doc += listexts(_('disabled extensions:'), extensions.disabled())
28 return doc
28 return doc
29
29
30 def optrst(options, verbose):
30 def optrst(options, verbose):
31 data = []
31 data = []
32 multioccur = False
32 multioccur = False
33 for option in options:
33 for option in options:
34 if len(option) == 5:
34 if len(option) == 5:
35 shortopt, longopt, default, desc, optlabel = option
35 shortopt, longopt, default, desc, optlabel = option
36 else:
36 else:
37 shortopt, longopt, default, desc = option
37 shortopt, longopt, default, desc = option
38 optlabel = _("VALUE") # default label
38 optlabel = _("VALUE") # default label
39
39
40 if _("DEPRECATED") in desc and not verbose:
40 if _("DEPRECATED") in desc and not verbose:
41 continue
41 continue
42
42
43 so = ''
43 so = ''
44 if shortopt:
44 if shortopt:
45 so = '-' + shortopt
45 so = '-' + shortopt
46 lo = '--' + longopt
46 lo = '--' + longopt
47 if default:
47 if default:
48 desc += _(" (default: %s)") % default
48 desc += _(" (default: %s)") % default
49
49
50 if isinstance(default, list):
50 if isinstance(default, list):
51 lo += " %s [+]" % optlabel
51 lo += " %s [+]" % optlabel
52 multioccur = True
52 multioccur = True
53 elif (default is not None) and not isinstance(default, bool):
53 elif (default is not None) and not isinstance(default, bool):
54 lo += " %s" % optlabel
54 lo += " %s" % optlabel
55
55
56 data.append((so, lo, desc))
56 data.append((so, lo, desc))
57
57
58 rst = minirst.maketable(data, 1)
58 rst = minirst.maketable(data, 1)
59
59
60 if multioccur:
60 if multioccur:
61 rst.append(_("\n[+] marked option can be specified multiple times\n"))
61 rst.append(_("\n[+] marked option can be specified multiple times\n"))
62
62
63 return ''.join(rst)
63 return ''.join(rst)
64
64
65 def topicmatch(kw):
65 def topicmatch(kw):
66 """Return help topics matching kw.
66 """Return help topics matching kw.
67
67
68 Returns {'section': [(name, summary), ...], ...} where section is
68 Returns {'section': [(name, summary), ...], ...} where section is
69 one of topics, commands, extensions, or extensioncommands.
69 one of topics, commands, extensions, or extensioncommands.
70 """
70 """
71 kw = encoding.lower(kw)
71 kw = encoding.lower(kw)
72 def lowercontains(container):
72 def lowercontains(container):
73 return kw in encoding.lower(_(container))
73 return kw in encoding.lower(container) # translated in helptable
74 results = {'topics': [],
74 results = {'topics': [],
75 'commands': [],
75 'commands': [],
76 'extensions': [],
76 'extensions': [],
77 'extensioncommands': [],
77 'extensioncommands': [],
78 }
78 }
79 for names, header, doc in helptable:
79 for names, header, doc in helptable:
80 if (sum(map(lowercontains, names))
80 if (sum(map(lowercontains, names))
81 or lowercontains(header)
81 or lowercontains(header)
82 or lowercontains(doc())):
82 or lowercontains(doc())):
83 results['topics'].append((names[0], header))
83 results['topics'].append((names[0], header))
84 import commands # avoid cycle
84 import commands # avoid cycle
85 for cmd, entry in commands.table.iteritems():
85 for cmd, entry in commands.table.iteritems():
86 if cmd.startswith('debug'):
86 if cmd.startswith('debug'):
87 continue
87 continue
88 if len(entry) == 3:
88 if len(entry) == 3:
89 summary = entry[2]
89 summary = entry[2]
90 else:
90 else:
91 summary = ''
91 summary = ''
92 docs = getattr(entry[0], '__doc__', None) or ''
92 # translate docs *before* searching there
93 docs = _(getattr(entry[0], '__doc__', None)) or ''
93 if kw in cmd or lowercontains(summary) or lowercontains(docs):
94 if kw in cmd or lowercontains(summary) or lowercontains(docs):
94 doclines = _(docs).splitlines()
95 doclines = docs.splitlines()
95 if doclines:
96 if doclines:
96 summary = doclines[0]
97 summary = doclines[0]
97 cmdname = cmd.split('|')[0].lstrip('^')
98 cmdname = cmd.split('|')[0].lstrip('^')
98 results['commands'].append((cmdname, summary))
99 results['commands'].append((cmdname, summary))
99 for name, docs in itertools.chain(
100 for name, docs in itertools.chain(
100 extensions.enabled().iteritems(),
101 extensions.enabled().iteritems(),
101 extensions.disabled().iteritems()):
102 extensions.disabled().iteritems()):
102 # extensions.load ignores the UI argument
103 # extensions.load ignores the UI argument
103 mod = extensions.load(None, name, '')
104 mod = extensions.load(None, name, '')
104 if lowercontains(name) or lowercontains(docs):
105 if lowercontains(name) or lowercontains(docs):
105 results['extensions'].append((name, _(docs).splitlines()[0]))
106 # extension docs are already translated
107 results['extensions'].append((name, docs.splitlines()[0]))
106 for cmd, entry in getattr(mod, 'cmdtable', {}).iteritems():
108 for cmd, entry in getattr(mod, 'cmdtable', {}).iteritems():
107 if kw in cmd or (len(entry) > 2 and lowercontains(entry[2])):
109 if kw in cmd or (len(entry) > 2 and lowercontains(entry[2])):
108 cmdname = cmd.split('|')[0].lstrip('^')
110 cmdname = cmd.split('|')[0].lstrip('^')
109 results['extensioncommands'].append(
111 results['extensioncommands'].append(
110 (cmdname, _(getattr(cmd, '__doc__', ''))))
112 (cmdname, _(getattr(cmd, '__doc__', ''))))
111 return results
113 return results
112
114
113 def loaddoc(topic):
115 def loaddoc(topic):
114 """Return a delayed loader for help/topic.txt."""
116 """Return a delayed loader for help/topic.txt."""
115
117
116 def loader():
118 def loader():
117 if util.mainfrozen():
119 if util.mainfrozen():
118 module = sys.executable
120 module = sys.executable
119 else:
121 else:
120 module = __file__
122 module = __file__
121 base = os.path.dirname(module)
123 base = os.path.dirname(module)
122
124
123 for dir in ('.', '..'):
125 for dir in ('.', '..'):
124 docdir = os.path.join(base, dir, 'help')
126 docdir = os.path.join(base, dir, 'help')
125 if os.path.isdir(docdir):
127 if os.path.isdir(docdir):
126 break
128 break
127
129
128 path = os.path.join(docdir, topic + ".txt")
130 path = os.path.join(docdir, topic + ".txt")
129 doc = gettext(util.readfile(path))
131 doc = gettext(util.readfile(path))
130 for rewriter in helphooks.get(topic, []):
132 for rewriter in helphooks.get(topic, []):
131 doc = rewriter(topic, doc)
133 doc = rewriter(topic, doc)
132 return doc
134 return doc
133
135
134 return loader
136 return loader
135
137
136 helptable = sorted([
138 helptable = sorted([
137 (["config", "hgrc"], _("Configuration Files"), loaddoc('config')),
139 (["config", "hgrc"], _("Configuration Files"), loaddoc('config')),
138 (["dates"], _("Date Formats"), loaddoc('dates')),
140 (["dates"], _("Date Formats"), loaddoc('dates')),
139 (["patterns"], _("File Name Patterns"), loaddoc('patterns')),
141 (["patterns"], _("File Name Patterns"), loaddoc('patterns')),
140 (['environment', 'env'], _('Environment Variables'),
142 (['environment', 'env'], _('Environment Variables'),
141 loaddoc('environment')),
143 loaddoc('environment')),
142 (['revs', 'revisions'], _('Specifying Single Revisions'),
144 (['revs', 'revisions'], _('Specifying Single Revisions'),
143 loaddoc('revisions')),
145 loaddoc('revisions')),
144 (['mrevs', 'multirevs'], _('Specifying Multiple Revisions'),
146 (['mrevs', 'multirevs'], _('Specifying Multiple Revisions'),
145 loaddoc('multirevs')),
147 loaddoc('multirevs')),
146 (['revset', 'revsets'], _("Specifying Revision Sets"), loaddoc('revsets')),
148 (['revset', 'revsets'], _("Specifying Revision Sets"), loaddoc('revsets')),
147 (['fileset', 'filesets'], _("Specifying File Sets"), loaddoc('filesets')),
149 (['fileset', 'filesets'], _("Specifying File Sets"), loaddoc('filesets')),
148 (['diffs'], _('Diff Formats'), loaddoc('diffs')),
150 (['diffs'], _('Diff Formats'), loaddoc('diffs')),
149 (['merge-tools'], _('Merge Tools'), loaddoc('merge-tools')),
151 (['merge-tools'], _('Merge Tools'), loaddoc('merge-tools')),
150 (['templating', 'templates', 'template', 'style'], _('Template Usage'),
152 (['templating', 'templates', 'template', 'style'], _('Template Usage'),
151 loaddoc('templates')),
153 loaddoc('templates')),
152 (['urls'], _('URL Paths'), loaddoc('urls')),
154 (['urls'], _('URL Paths'), loaddoc('urls')),
153 (["extensions"], _("Using Additional Features"), extshelp),
155 (["extensions"], _("Using Additional Features"), extshelp),
154 (["subrepo", "subrepos"], _("Subrepositories"), loaddoc('subrepos')),
156 (["subrepo", "subrepos"], _("Subrepositories"), loaddoc('subrepos')),
155 (["hgweb"], _("Configuring hgweb"), loaddoc('hgweb')),
157 (["hgweb"], _("Configuring hgweb"), loaddoc('hgweb')),
156 (["glossary"], _("Glossary"), loaddoc('glossary')),
158 (["glossary"], _("Glossary"), loaddoc('glossary')),
157 (["hgignore", "ignore"], _("Syntax for Mercurial Ignore Files"),
159 (["hgignore", "ignore"], _("Syntax for Mercurial Ignore Files"),
158 loaddoc('hgignore')),
160 loaddoc('hgignore')),
159 (["phases"], _("Working with Phases"), loaddoc('phases')),
161 (["phases"], _("Working with Phases"), loaddoc('phases')),
160 ])
162 ])
161
163
162 # Map topics to lists of callable taking the current topic help and
164 # Map topics to lists of callable taking the current topic help and
163 # returning the updated version
165 # returning the updated version
164 helphooks = {}
166 helphooks = {}
165
167
166 def addtopichook(topic, rewriter):
168 def addtopichook(topic, rewriter):
167 helphooks.setdefault(topic, []).append(rewriter)
169 helphooks.setdefault(topic, []).append(rewriter)
168
170
169 def makeitemsdoc(topic, doc, marker, items):
171 def makeitemsdoc(topic, doc, marker, items):
170 """Extract docstring from the items key to function mapping, build a
172 """Extract docstring from the items key to function mapping, build a
171 .single documentation block and use it to overwrite the marker in doc
173 .single documentation block and use it to overwrite the marker in doc
172 """
174 """
173 entries = []
175 entries = []
174 for name in sorted(items):
176 for name in sorted(items):
175 text = (items[name].__doc__ or '').rstrip()
177 text = (items[name].__doc__ or '').rstrip()
176 if not text:
178 if not text:
177 continue
179 continue
178 text = gettext(text)
180 text = gettext(text)
179 lines = text.splitlines()
181 lines = text.splitlines()
180 doclines = [(lines[0])]
182 doclines = [(lines[0])]
181 for l in lines[1:]:
183 for l in lines[1:]:
182 # Stop once we find some Python doctest
184 # Stop once we find some Python doctest
183 if l.strip().startswith('>>>'):
185 if l.strip().startswith('>>>'):
184 break
186 break
185 doclines.append(' ' + l.strip())
187 doclines.append(' ' + l.strip())
186 entries.append('\n'.join(doclines))
188 entries.append('\n'.join(doclines))
187 entries = '\n\n'.join(entries)
189 entries = '\n\n'.join(entries)
188 return doc.replace(marker, entries)
190 return doc.replace(marker, entries)
189
191
190 def addtopicsymbols(topic, marker, symbols):
192 def addtopicsymbols(topic, marker, symbols):
191 def add(topic, doc):
193 def add(topic, doc):
192 return makeitemsdoc(topic, doc, marker, symbols)
194 return makeitemsdoc(topic, doc, marker, symbols)
193 addtopichook(topic, add)
195 addtopichook(topic, add)
194
196
195 addtopicsymbols('filesets', '.. predicatesmarker', fileset.symbols)
197 addtopicsymbols('filesets', '.. predicatesmarker', fileset.symbols)
196 addtopicsymbols('merge-tools', '.. internaltoolsmarker', filemerge.internals)
198 addtopicsymbols('merge-tools', '.. internaltoolsmarker', filemerge.internals)
197 addtopicsymbols('revsets', '.. predicatesmarker', revset.symbols)
199 addtopicsymbols('revsets', '.. predicatesmarker', revset.symbols)
198 addtopicsymbols('templates', '.. keywordsmarker', templatekw.keywords)
200 addtopicsymbols('templates', '.. keywordsmarker', templatekw.keywords)
199 addtopicsymbols('templates', '.. filtersmarker', templatefilters.filters)
201 addtopicsymbols('templates', '.. filtersmarker', templatefilters.filters)
General Comments 0
You need to be logged in to leave comments. Login now