##// END OF EJS Templates
gendoc: group commands by category in man page and HTML help...
Sietse Brouwer -
r42435:3816e361 default
parent child Browse files
Show More
@@ -1,241 +1,266 b''
1 1 #!/usr/bin/env python
2 2 """usage: %s DOC ...
3 3
4 4 where DOC is the name of a document
5 5 """
6 6
7 7 from __future__ import absolute_import
8 8
9 9 import os
10 10 import sys
11 11 import textwrap
12 12
13 13 try:
14 14 import msvcrt
15 15 msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
16 16 msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY)
17 17 except ImportError:
18 18 pass
19 19
20 20 # This script is executed during installs and may not have C extensions
21 21 # available. Relax C module requirements.
22 22 os.environ[r'HGMODULEPOLICY'] = r'allow'
23 23 # import from the live mercurial repo
24 24 sys.path.insert(0, r"..")
25 25 from mercurial import demandimport; demandimport.enable()
26 26 # Load util so that the locale path is set by i18n.setdatapath() before
27 27 # calling _().
28 28 from mercurial import util
29 29 util.datapath
30 30 from mercurial import (
31 31 commands,
32 32 encoding,
33 33 extensions,
34 34 help,
35 35 minirst,
36 36 pycompat,
37 37 ui as uimod,
38 38 )
39 39 from mercurial.i18n import (
40 40 gettext,
41 41 _,
42 42 )
43 43
44 44 table = commands.table
45 45 globalopts = commands.globalopts
46 46 helptable = help.helptable
47 47 loaddoc = help.loaddoc
48 48
49 49 def get_desc(docstr):
50 50 if not docstr:
51 51 return b"", b""
52 52 # sanitize
53 53 docstr = docstr.strip(b"\n")
54 54 docstr = docstr.rstrip()
55 55 shortdesc = docstr.splitlines()[0].strip()
56 56
57 57 i = docstr.find(b"\n")
58 58 if i != -1:
59 59 desc = docstr[i + 2:]
60 60 else:
61 61 desc = shortdesc
62 62
63 63 desc = textwrap.dedent(desc.decode('latin1')).encode('latin1')
64 64
65 65 return (shortdesc, desc)
66 66
67 67 def get_opts(opts):
68 68 for opt in opts:
69 69 if len(opt) == 5:
70 70 shortopt, longopt, default, desc, optlabel = opt
71 71 else:
72 72 shortopt, longopt, default, desc = opt
73 73 optlabel = _(b"VALUE")
74 74 allopts = []
75 75 if shortopt:
76 76 allopts.append(b"-%s" % shortopt)
77 77 if longopt:
78 78 allopts.append(b"--%s" % longopt)
79 79 if isinstance(default, list):
80 80 allopts[-1] += b" <%s[+]>" % optlabel
81 81 elif (default is not None) and not isinstance(default, bool):
82 82 allopts[-1] += b" <%s>" % optlabel
83 83 if b'\n' in desc:
84 84 # only remove line breaks and indentation
85 85 desc = b' '.join(l.lstrip() for l in desc.split(b'\n'))
86 86 desc += default and _(b" (default: %s)") % bytes(default) or b""
87 87 yield (b", ".join(allopts), desc)
88 88
89 89 def get_cmd(cmd, cmdtable):
90 90 d = {}
91 91 attr = cmdtable[cmd]
92 92 cmds = cmd.lstrip(b"^").split(b"|")
93 93
94 94 d[b'cmd'] = cmds[0]
95 95 d[b'aliases'] = cmd.split(b"|")[1:]
96 96 d[b'desc'] = get_desc(gettext(pycompat.getdoc(attr[0])))
97 97 d[b'opts'] = list(get_opts(attr[1]))
98 98
99 99 s = b'hg ' + cmds[0]
100 100 if len(attr) > 2:
101 101 if not attr[2].startswith(b'hg'):
102 102 s += b' ' + attr[2]
103 103 else:
104 104 s = attr[2]
105 105 d[b'synopsis'] = s.strip()
106 106
107 107 return d
108 108
109 109 def showdoc(ui):
110 110 # print options
111 111 ui.write(minirst.section(_(b"Options")))
112 112 multioccur = False
113 113 for optstr, desc in get_opts(globalopts):
114 114 ui.write(b"%s\n %s\n\n" % (optstr, desc))
115 115 if optstr.endswith(b"[+]>"):
116 116 multioccur = True
117 117 if multioccur:
118 118 ui.write(_(b"\n[+] marked option can be specified multiple times\n"))
119 119 ui.write(b"\n")
120 120
121 121 # print cmds
122 122 ui.write(minirst.section(_(b"Commands")))
123 123 commandprinter(ui, table, minirst.subsection)
124 124
125 125 # print help topics
126 126 # The config help topic is included in the hgrc.5 man page.
127 127 helpprinter(ui, helptable, minirst.section, exclude=[b'config'])
128 128
129 129 ui.write(minirst.section(_(b"Extensions")))
130 130 ui.write(_(b"This section contains help for extensions that are "
131 131 b"distributed together with Mercurial. Help for other "
132 132 b"extensions is available in the help system."))
133 133 ui.write((b"\n\n"
134 134 b".. contents::\n"
135 135 b" :class: htmlonly\n"
136 136 b" :local:\n"
137 137 b" :depth: 1\n\n"))
138 138
139 139 for extensionname in sorted(allextensionnames()):
140 140 mod = extensions.load(ui, extensionname, None)
141 141 ui.write(minirst.subsection(extensionname))
142 142 ui.write(b"%s\n\n" % gettext(pycompat.getdoc(mod)))
143 143 cmdtable = getattr(mod, 'cmdtable', None)
144 144 if cmdtable:
145 145 ui.write(minirst.subsubsection(_(b'Commands')))
146 146 commandprinter(ui, cmdtable, minirst.subsubsubsection)
147 147
148 148 def showtopic(ui, topic):
149 149 extrahelptable = [
150 150 ([b"common"], b'', loaddoc(b'common'), help.TOPIC_CATEGORY_MISC),
151 151 ([b"hg.1"], b'', loaddoc(b'hg.1'), help.TOPIC_CATEGORY_CONFIG),
152 152 ([b"hg-ssh.8"], b'', loaddoc(b'hg-ssh.8'), help.TOPIC_CATEGORY_CONFIG),
153 153 ([b"hgignore.5"], b'', loaddoc(b'hgignore.5'),
154 154 help.TOPIC_CATEGORY_CONFIG),
155 155 ([b"hgrc.5"], b'', loaddoc(b'hgrc.5'), help.TOPIC_CATEGORY_CONFIG),
156 156 ([b"hgignore.5.gendoc"], b'', loaddoc(b'hgignore'),
157 157 help.TOPIC_CATEGORY_CONFIG),
158 158 ([b"hgrc.5.gendoc"], b'', loaddoc(b'config'),
159 159 help.TOPIC_CATEGORY_CONFIG),
160 160 ]
161 161 helpprinter(ui, helptable + extrahelptable, None, include=[topic])
162 162
163 163 def helpprinter(ui, helptable, sectionfunc, include=[], exclude=[]):
164 164 for h in helptable:
165 165 names, sec, doc = h[0:3]
166 166 if exclude and names[0] in exclude:
167 167 continue
168 168 if include and names[0] not in include:
169 169 continue
170 170 for name in names:
171 171 ui.write(b".. _%s:\n" % name)
172 172 ui.write(b"\n")
173 173 if sectionfunc:
174 174 ui.write(sectionfunc(sec))
175 175 if callable(doc):
176 176 doc = doc(ui)
177 177 ui.write(doc)
178 178 ui.write(b"\n")
179 179
180 180 def commandprinter(ui, cmdtable, sectionfunc):
181 181 h = {}
182 182 for c, attr in cmdtable.items():
183 183 f = c.split(b"|")[0]
184 184 f = f.lstrip(b"^")
185 185 h[f] = c
186 186 cmds = h.keys()
187 187
188 if True:
189 for f in sorted(cmds):
188 def helpcategory(cmd):
189 """Given a canonical command name from `cmds` (above), retrieve its
190 help category. If helpcategory is None, default to CATEGORY_NONE.
191 """
192 fullname = h[cmd]
193 details = cmdtable[fullname]
194 helpcategory = details[0].helpcategory
195 return helpcategory or help.registrar.command.CATEGORY_NONE
196
197 # Print the help for each command. We present the commands grouped by
198 # category, and we use help.CATEGORY_ORDER as a guide for a helpful order
199 # in which to present the categories.
200 cmdsbycategory = {category: [] for category in help.CATEGORY_ORDER}
201 for cmd in cmds:
202 cmdsbycategory[helpcategory(cmd)].append(cmd)
203
204 for category in help.CATEGORY_ORDER:
205 categorycmds = cmdsbycategory[category]
206 if not categorycmds:
207 # Skip empty categories
208 continue
209 # Print a section header for the category.
210 # For now, the category header is at the same level as the headers for
211 # the commands in the category; this is fixed in the next commit.
212 ui.write(sectionfunc(help.CATEGORY_NAMES[category]))
213 # Print each command in the category
214 for f in sorted(categorycmds):
190 215 if f.startswith(b"debug"):
191 216 continue
192 217 d = get_cmd(h[f], cmdtable)
193 218 ui.write(sectionfunc(d[b'cmd']))
194 219 # short description
195 220 ui.write(d[b'desc'][0])
196 221 # synopsis
197 222 ui.write(b"::\n\n")
198 223 synopsislines = d[b'synopsis'].splitlines()
199 224 for line in synopsislines:
200 225 # some commands (such as rebase) have a multi-line
201 226 # synopsis
202 227 ui.write(b" %s\n" % line)
203 228 ui.write(b'\n')
204 229 # description
205 230 ui.write(b"%s\n\n" % d[b'desc'][1])
206 231 # options
207 232 opt_output = list(d[b'opts'])
208 233 if opt_output:
209 234 opts_len = max([len(line[0]) for line in opt_output])
210 235 ui.write(_(b"Options:\n\n"))
211 236 multioccur = False
212 237 for optstr, desc in opt_output:
213 238 if desc:
214 239 s = b"%-*s %s" % (opts_len, optstr, desc)
215 240 else:
216 241 s = optstr
217 242 ui.write(b"%s\n" % s)
218 243 if optstr.endswith(b"[+]>"):
219 244 multioccur = True
220 245 if multioccur:
221 246 ui.write(_(b"\n[+] marked option can be specified"
222 247 b" multiple times\n"))
223 248 ui.write(b"\n")
224 249 # aliases
225 250 if d[b'aliases']:
226 251 ui.write(_(b" aliases: %s\n\n") % b" ".join(d[b'aliases']))
227 252
228 253
229 254 def allextensionnames():
230 255 return set(extensions.enabled().keys()) | set(extensions.disabled().keys())
231 256
232 257 if __name__ == "__main__":
233 258 doc = b'hg.1.gendoc'
234 259 if len(sys.argv) > 1:
235 260 doc = encoding.strtolocal(sys.argv[1])
236 261
237 262 ui = uimod.ui.load()
238 263 if doc == b'hg.1.gendoc':
239 264 showdoc(ui)
240 265 else:
241 266 showtopic(ui, encoding.strtolocal(sys.argv[1]))
General Comments 0
You need to be logged in to leave comments. Login now