Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/help.py @ 49763:2a70d1fc70c4
typing: add type hints to mercurial/help.py
Was hoping to find more issues like f09bc2ed9100, but it may be that nothing
checks the args to that operation. In any event, the work is done and pytype
doesn't do a very good job inferring the types. A few of th emore complicated
things like the command table are left untyped, because they come from modules
that aren't typed yet.
author | Matt Harbison <matt_harbison@yahoo.com> |
---|---|
date | Sun, 20 Nov 2022 22:54:43 -0500 |
parents | 04e6add9e4dc |
children | f56873a7284c |
comparison
equal
deleted
inserted
replaced
49762:5744ceeb9067 | 49763:2a70d1fc70c4 |
---|---|
7 | 7 |
8 | 8 |
9 import itertools | 9 import itertools |
10 import re | 10 import re |
11 import textwrap | 11 import textwrap |
12 | |
13 from typing import ( | |
14 Callable, | |
15 Dict, | |
16 Iterable, | |
17 List, | |
18 Optional, | |
19 Set, | |
20 Tuple, | |
21 Union, | |
22 cast, | |
23 ) | |
12 | 24 |
13 from .i18n import ( | 25 from .i18n import ( |
14 _, | 26 _, |
15 gettext, | 27 gettext, |
16 ) | 28 ) |
38 compression, | 50 compression, |
39 resourceutil, | 51 resourceutil, |
40 stringutil, | 52 stringutil, |
41 ) | 53 ) |
42 | 54 |
43 _exclkeywords = { | 55 _DocLoader = Callable[[uimod.ui], bytes] |
56 # Old extensions may not register with a category | |
57 _HelpEntry = Union["_HelpEntryNoCategory", "_HelpEntryWithCategory"] | |
58 _HelpEntryNoCategory = Tuple[List[bytes], bytes, _DocLoader] | |
59 _HelpEntryWithCategory = Tuple[List[bytes], bytes, _DocLoader, bytes] | |
60 _SelectFn = Callable[[object], bool] | |
61 _SynonymTable = Dict[bytes, List[bytes]] | |
62 _TopicHook = Callable[[uimod.ui, bytes, bytes], bytes] | |
63 | |
64 _exclkeywords: Set[bytes] = { | |
44 b"(ADVANCED)", | 65 b"(ADVANCED)", |
45 b"(DEPRECATED)", | 66 b"(DEPRECATED)", |
46 b"(EXPERIMENTAL)", | 67 b"(EXPERIMENTAL)", |
47 # i18n: "(ADVANCED)" is a keyword, must be translated consistently | 68 # i18n: "(ADVANCED)" is a keyword, must be translated consistently |
48 _(b"(ADVANCED)"), | 69 _(b"(ADVANCED)"), |
54 | 75 |
55 # The order in which command categories will be displayed. | 76 # The order in which command categories will be displayed. |
56 # Extensions with custom categories should insert them into this list | 77 # Extensions with custom categories should insert them into this list |
57 # after/before the appropriate item, rather than replacing the list or | 78 # after/before the appropriate item, rather than replacing the list or |
58 # assuming absolute positions. | 79 # assuming absolute positions. |
59 CATEGORY_ORDER = [ | 80 CATEGORY_ORDER: List[bytes] = [ |
60 registrar.command.CATEGORY_REPO_CREATION, | 81 registrar.command.CATEGORY_REPO_CREATION, |
61 registrar.command.CATEGORY_REMOTE_REPO_MANAGEMENT, | 82 registrar.command.CATEGORY_REMOTE_REPO_MANAGEMENT, |
62 registrar.command.CATEGORY_COMMITTING, | 83 registrar.command.CATEGORY_COMMITTING, |
63 registrar.command.CATEGORY_CHANGE_MANAGEMENT, | 84 registrar.command.CATEGORY_CHANGE_MANAGEMENT, |
64 registrar.command.CATEGORY_CHANGE_ORGANIZATION, | 85 registrar.command.CATEGORY_CHANGE_ORGANIZATION, |
72 registrar.command.CATEGORY_NONE, | 93 registrar.command.CATEGORY_NONE, |
73 ] | 94 ] |
74 | 95 |
75 # Human-readable category names. These are translated. | 96 # Human-readable category names. These are translated. |
76 # Extensions with custom categories should add their names here. | 97 # Extensions with custom categories should add their names here. |
77 CATEGORY_NAMES = { | 98 CATEGORY_NAMES: Dict[bytes, bytes] = { |
78 registrar.command.CATEGORY_REPO_CREATION: b'Repository creation', | 99 registrar.command.CATEGORY_REPO_CREATION: b'Repository creation', |
79 registrar.command.CATEGORY_REMOTE_REPO_MANAGEMENT: b'Remote repository management', | 100 registrar.command.CATEGORY_REMOTE_REPO_MANAGEMENT: b'Remote repository management', |
80 registrar.command.CATEGORY_COMMITTING: b'Change creation', | 101 registrar.command.CATEGORY_COMMITTING: b'Change creation', |
81 registrar.command.CATEGORY_CHANGE_NAVIGATION: b'Change navigation', | 102 registrar.command.CATEGORY_CHANGE_NAVIGATION: b'Change navigation', |
82 registrar.command.CATEGORY_CHANGE_MANAGEMENT: b'Change manipulation', | 103 registrar.command.CATEGORY_CHANGE_MANAGEMENT: b'Change manipulation', |
100 | 121 |
101 # The order in which topic categories will be displayed. | 122 # The order in which topic categories will be displayed. |
102 # Extensions with custom categories should insert them into this list | 123 # Extensions with custom categories should insert them into this list |
103 # after/before the appropriate item, rather than replacing the list or | 124 # after/before the appropriate item, rather than replacing the list or |
104 # assuming absolute positions. | 125 # assuming absolute positions. |
105 TOPIC_CATEGORY_ORDER = [ | 126 TOPIC_CATEGORY_ORDER: List[bytes] = [ |
106 TOPIC_CATEGORY_IDS, | 127 TOPIC_CATEGORY_IDS, |
107 TOPIC_CATEGORY_OUTPUT, | 128 TOPIC_CATEGORY_OUTPUT, |
108 TOPIC_CATEGORY_CONFIG, | 129 TOPIC_CATEGORY_CONFIG, |
109 TOPIC_CATEGORY_CONCEPTS, | 130 TOPIC_CATEGORY_CONCEPTS, |
110 TOPIC_CATEGORY_MISC, | 131 TOPIC_CATEGORY_MISC, |
111 TOPIC_CATEGORY_NONE, | 132 TOPIC_CATEGORY_NONE, |
112 ] | 133 ] |
113 | 134 |
114 # Human-readable topic category names. These are translated. | 135 # Human-readable topic category names. These are translated. |
115 TOPIC_CATEGORY_NAMES = { | 136 TOPIC_CATEGORY_NAMES: Dict[bytes, bytes] = { |
116 TOPIC_CATEGORY_IDS: b'Mercurial identifiers', | 137 TOPIC_CATEGORY_IDS: b'Mercurial identifiers', |
117 TOPIC_CATEGORY_OUTPUT: b'Mercurial output', | 138 TOPIC_CATEGORY_OUTPUT: b'Mercurial output', |
118 TOPIC_CATEGORY_CONFIG: b'Mercurial configuration', | 139 TOPIC_CATEGORY_CONFIG: b'Mercurial configuration', |
119 TOPIC_CATEGORY_CONCEPTS: b'Concepts', | 140 TOPIC_CATEGORY_CONCEPTS: b'Concepts', |
120 TOPIC_CATEGORY_MISC: b'Miscellaneous', | 141 TOPIC_CATEGORY_MISC: b'Miscellaneous', |
121 TOPIC_CATEGORY_NONE: b'Uncategorized topics', | 142 TOPIC_CATEGORY_NONE: b'Uncategorized topics', |
122 } | 143 } |
123 | 144 |
124 | 145 |
125 def listexts(header, exts, indent=1, showdeprecated=False): | 146 def listexts( |
147 header: bytes, | |
148 exts: Dict[bytes, bytes], | |
149 indent: int = 1, | |
150 showdeprecated: bool = False, | |
151 ) -> List[bytes]: | |
126 '''return a text listing of the given extensions''' | 152 '''return a text listing of the given extensions''' |
127 rst = [] | 153 rst = [] |
128 if exts: | 154 if exts: |
129 for name, desc in sorted(exts.items()): | 155 for name, desc in sorted(exts.items()): |
130 if not showdeprecated and any(w in desc for w in _exclkeywords): | 156 if not showdeprecated and any(w in desc for w in _exclkeywords): |
133 if rst: | 159 if rst: |
134 rst.insert(0, b'\n%s\n\n' % header) | 160 rst.insert(0, b'\n%s\n\n' % header) |
135 return rst | 161 return rst |
136 | 162 |
137 | 163 |
138 def extshelp(ui): | 164 def extshelp(ui: uimod.ui) -> bytes: |
139 rst = loaddoc(b'extensions')(ui).splitlines(True) | 165 rst = loaddoc(b'extensions')(ui).splitlines(True) |
140 rst.extend( | 166 rst.extend( |
141 listexts( | 167 listexts( |
142 _(b'enabled extensions:'), extensions.enabled(), showdeprecated=True | 168 _(b'enabled extensions:'), extensions.enabled(), showdeprecated=True |
143 ) | 169 ) |
151 ) | 177 ) |
152 doc = b''.join(rst) | 178 doc = b''.join(rst) |
153 return doc | 179 return doc |
154 | 180 |
155 | 181 |
156 def parsedefaultmarker(text): | 182 def parsedefaultmarker(text: bytes) -> Optional[Tuple[bytes, List[bytes]]]: |
157 """given a text 'abc (DEFAULT: def.ghi)', | 183 """given a text 'abc (DEFAULT: def.ghi)', |
158 returns (b'abc', (b'def', b'ghi')). Otherwise return None""" | 184 returns (b'abc', (b'def', b'ghi')). Otherwise return None""" |
159 if text[-1:] == b')': | 185 if text[-1:] == b')': |
160 marker = b' (DEFAULT: ' | 186 marker = b' (DEFAULT: ' |
161 pos = text.find(marker) | 187 pos = text.find(marker) |
162 if pos >= 0: | 188 if pos >= 0: |
163 item = text[pos + len(marker) : -1] | 189 item = text[pos + len(marker) : -1] |
164 return text[:pos], item.split(b'.', 2) | 190 return text[:pos], item.split(b'.', 2) |
165 | 191 |
166 | 192 |
167 def optrst(header, options, verbose, ui): | 193 def optrst(header: bytes, options, verbose: bool, ui: uimod.ui) -> bytes: |
168 data = [] | 194 data = [] |
169 multioccur = False | 195 multioccur = False |
170 for option in options: | 196 for option in options: |
171 if len(option) == 5: | 197 if len(option) == 5: |
172 shortopt, longopt, default, desc, optlabel = option | 198 shortopt, longopt, default, desc, optlabel = option |
218 rst.extend(minirst.maketable(data, 1)) | 244 rst.extend(minirst.maketable(data, 1)) |
219 | 245 |
220 return b''.join(rst) | 246 return b''.join(rst) |
221 | 247 |
222 | 248 |
223 def indicateomitted(rst, omitted, notomitted=None): | 249 def indicateomitted( |
250 rst: List[bytes], omitted: bytes, notomitted: Optional[bytes] = None | |
251 ) -> None: | |
224 rst.append(b'\n\n.. container:: omitted\n\n %s\n\n' % omitted) | 252 rst.append(b'\n\n.. container:: omitted\n\n %s\n\n' % omitted) |
225 if notomitted: | 253 if notomitted: |
226 rst.append(b'\n\n.. container:: notomitted\n\n %s\n\n' % notomitted) | 254 rst.append(b'\n\n.. container:: notomitted\n\n %s\n\n' % notomitted) |
227 | 255 |
228 | 256 |
229 def filtercmd(ui, cmd, func, kw, doc): | 257 def filtercmd(ui: uimod.ui, cmd: bytes, func, kw: bytes, doc: bytes) -> bool: |
230 if not ui.debugflag and cmd.startswith(b"debug") and kw != b"debug": | 258 if not ui.debugflag and cmd.startswith(b"debug") and kw != b"debug": |
231 # Debug command, and user is not looking for those. | 259 # Debug command, and user is not looking for those. |
232 return True | 260 return True |
233 if not ui.verbose: | 261 if not ui.verbose: |
234 if not kw and not doc: | 262 if not kw and not doc: |
247 # Configuration explicitly hides the command. | 275 # Configuration explicitly hides the command. |
248 return True | 276 return True |
249 return False | 277 return False |
250 | 278 |
251 | 279 |
252 def filtertopic(ui, topic): | 280 def filtertopic(ui: uimod.ui, topic: bytes) -> bool: |
253 return ui.configbool(b'help', b'hidden-topic.%s' % topic, False) | 281 return ui.configbool(b'help', b'hidden-topic.%s' % topic, False) |
254 | 282 |
255 | 283 |
256 def topicmatch(ui, commands, kw): | 284 def topicmatch( |
285 ui: uimod.ui, commands, kw: bytes | |
286 ) -> Dict[bytes, List[Tuple[bytes, bytes]]]: | |
257 """Return help topics matching kw. | 287 """Return help topics matching kw. |
258 | 288 |
259 Returns {'section': [(name, summary), ...], ...} where section is | 289 Returns {'section': [(name, summary), ...], ...} where section is |
260 one of topics, commands, extensions, or extensioncommands. | 290 one of topics, commands, extensions, or extensioncommands. |
261 """ | 291 """ |
324 continue | 354 continue |
325 results[b'extensioncommands'].append((cmdname, cmddoc)) | 355 results[b'extensioncommands'].append((cmdname, cmddoc)) |
326 return results | 356 return results |
327 | 357 |
328 | 358 |
329 def loaddoc(topic, subdir=None): | 359 def loaddoc(topic: bytes, subdir: Optional[bytes] = None) -> _DocLoader: |
330 """Return a delayed loader for help/topic.txt.""" | 360 """Return a delayed loader for help/topic.txt.""" |
331 | 361 |
332 def loader(ui): | 362 def loader(ui: uimod.ui) -> bytes: |
333 package = b'mercurial.helptext' | 363 package = b'mercurial.helptext' |
334 if subdir: | 364 if subdir: |
335 package += b'.' + subdir | 365 package += b'.' + subdir |
336 with resourceutil.open_resource(package, topic + b'.txt') as fp: | 366 with resourceutil.open_resource(package, topic + b'.txt') as fp: |
337 doc = gettext(fp.read()) | 367 doc = gettext(fp.read()) |
340 return doc | 370 return doc |
341 | 371 |
342 return loader | 372 return loader |
343 | 373 |
344 | 374 |
345 internalstable = sorted( | 375 internalstable: List[_HelpEntryNoCategory] = sorted( |
346 [ | 376 [ |
347 ( | 377 ( |
348 [b'bid-merge'], | 378 [b'bid-merge'], |
349 _(b'Bid Merge Algorithm'), | 379 _(b'Bid Merge Algorithm'), |
350 loaddoc(b'bid-merge', subdir=b'internals'), | 380 loaddoc(b'bid-merge', subdir=b'internals'), |
405 ), | 435 ), |
406 ] | 436 ] |
407 ) | 437 ) |
408 | 438 |
409 | 439 |
410 def internalshelp(ui): | 440 def internalshelp(ui: uimod.ui) -> bytes: |
411 """Generate the index for the "internals" topic.""" | 441 """Generate the index for the "internals" topic.""" |
412 lines = [ | 442 lines = [ |
413 b'To access a subtopic, use "hg help internals.{subtopic-name}"\n', | 443 b'To access a subtopic, use "hg help internals.{subtopic-name}"\n', |
414 b'\n', | 444 b'\n', |
415 ] | 445 ] |
417 lines.append(b' :%s: %s\n' % (names[0], header)) | 447 lines.append(b' :%s: %s\n' % (names[0], header)) |
418 | 448 |
419 return b''.join(lines) | 449 return b''.join(lines) |
420 | 450 |
421 | 451 |
422 helptable = sorted( | 452 helptable: List[_HelpEntryWithCategory] = sorted( |
423 [ | 453 [ |
424 ( | 454 ( |
425 [b'bundlespec'], | 455 [b'bundlespec'], |
426 _(b"Bundle File Formats"), | 456 _(b"Bundle File Formats"), |
427 loaddoc(b'bundlespec'), | 457 loaddoc(b'bundlespec'), |
579 ), | 609 ), |
580 ] | 610 ] |
581 ) | 611 ) |
582 | 612 |
583 # Maps topics with sub-topics to a list of their sub-topics. | 613 # Maps topics with sub-topics to a list of their sub-topics. |
584 subtopics = { | 614 subtopics: Dict[bytes, List[_HelpEntryNoCategory]] = { |
585 b'internals': internalstable, | 615 b'internals': internalstable, |
586 } | 616 } |
587 | 617 |
588 # Map topics to lists of callable taking the current topic help and | 618 # Map topics to lists of callable taking the current topic help and |
589 # returning the updated version | 619 # returning the updated version |
590 helphooks = {} | 620 helphooks: Dict[bytes, List[_TopicHook]] = {} |
591 | 621 |
592 | 622 |
593 def addtopichook(topic, rewriter): | 623 def addtopichook(topic: bytes, rewriter: _TopicHook) -> None: |
594 helphooks.setdefault(topic, []).append(rewriter) | 624 helphooks.setdefault(topic, []).append(rewriter) |
595 | 625 |
596 | 626 |
597 def makeitemsdoc(ui, topic, doc, marker, items, dedent=False): | 627 def makeitemsdoc( |
628 ui: uimod.ui, | |
629 topic: bytes, | |
630 doc: bytes, | |
631 marker: bytes, | |
632 items: Dict[bytes, bytes], | |
633 dedent: bool = False, | |
634 ) -> bytes: | |
598 """Extract docstring from the items key to function mapping, build a | 635 """Extract docstring from the items key to function mapping, build a |
599 single documentation block and use it to overwrite the marker in doc. | 636 single documentation block and use it to overwrite the marker in doc. |
600 """ | 637 """ |
601 entries = [] | 638 entries = [] |
602 for name in sorted(items): | 639 for name in sorted(items): |
620 entries.append(b'\n'.join(doclines)) | 657 entries.append(b'\n'.join(doclines)) |
621 entries = b'\n\n'.join(entries) | 658 entries = b'\n\n'.join(entries) |
622 return doc.replace(marker, entries) | 659 return doc.replace(marker, entries) |
623 | 660 |
624 | 661 |
625 def addtopicsymbols(topic, marker, symbols, dedent=False): | 662 def addtopicsymbols( |
626 def add(ui, topic, doc): | 663 topic: bytes, marker: bytes, symbols, dedent: bool = False |
664 ) -> None: | |
665 def add(ui: uimod.ui, topic: bytes, doc: bytes): | |
627 return makeitemsdoc(ui, topic, doc, marker, symbols, dedent=dedent) | 666 return makeitemsdoc(ui, topic, doc, marker, symbols, dedent=dedent) |
628 | 667 |
629 addtopichook(topic, add) | 668 addtopichook(topic, add) |
630 | 669 |
631 | 670 |
645 addtopicsymbols( | 684 addtopicsymbols( |
646 b'hgweb', b'.. webcommandsmarker', webcommands.commands, dedent=True | 685 b'hgweb', b'.. webcommandsmarker', webcommands.commands, dedent=True |
647 ) | 686 ) |
648 | 687 |
649 | 688 |
650 def inserttweakrc(ui, topic, doc): | 689 def inserttweakrc(ui: uimod.ui, topic: bytes, doc: bytes) -> bytes: |
651 marker = b'.. tweakdefaultsmarker' | 690 marker = b'.. tweakdefaultsmarker' |
652 repl = uimod.tweakrc | 691 repl = uimod.tweakrc |
653 | 692 |
654 def sub(m): | 693 def sub(m): |
655 lines = [m.group(1) + s for s in repl.splitlines()] | 694 lines = [m.group(1) + s for s in repl.splitlines()] |
656 return b'\n'.join(lines) | 695 return b'\n'.join(lines) |
657 | 696 |
658 return re.sub(br'( *)%s' % re.escape(marker), sub, doc) | 697 return re.sub(br'( *)%s' % re.escape(marker), sub, doc) |
659 | 698 |
660 | 699 |
661 def _getcategorizedhelpcmds(ui, cmdtable, name, select=None): | 700 def _getcategorizedhelpcmds( |
701 ui: uimod.ui, cmdtable, name: bytes, select: Optional[_SelectFn] = None | |
702 ) -> Tuple[Dict[bytes, List[bytes]], Dict[bytes, bytes], _SynonymTable]: | |
662 # Category -> list of commands | 703 # Category -> list of commands |
663 cats = {} | 704 cats = {} |
664 # Command -> short description | 705 # Command -> short description |
665 h = {} | 706 h = {} |
666 # Command -> string showing synonyms | 707 # Command -> string showing synonyms |
685 ) | 726 ) |
686 cats.setdefault(cat, []).append(f) | 727 cats.setdefault(cat, []).append(f) |
687 return cats, h, syns | 728 return cats, h, syns |
688 | 729 |
689 | 730 |
690 def _getcategorizedhelptopics(ui, topictable): | 731 def _getcategorizedhelptopics( |
732 ui: uimod.ui, topictable: List[_HelpEntry] | |
733 ) -> Tuple[Dict[bytes, List[Tuple[bytes, bytes]]], Dict[bytes, List[bytes]]]: | |
691 # Group commands by category. | 734 # Group commands by category. |
692 topiccats = {} | 735 topiccats = {} |
693 syns = {} | 736 syns = {} |
694 for topic in topictable: | 737 for topic in topictable: |
695 names, header, doc = topic[0:3] | 738 names, header, doc = topic[0:3] |
696 if len(topic) > 3 and topic[3]: | 739 if len(topic) > 3 and topic[3]: |
697 category = topic[3] | 740 category: bytes = cast(bytes, topic[3]) # help pytype |
698 else: | 741 else: |
699 category = TOPIC_CATEGORY_NONE | 742 category: bytes = TOPIC_CATEGORY_NONE |
700 | 743 |
701 topicname = names[0] | 744 topicname = names[0] |
702 syns[topicname] = list(names) | 745 syns[topicname] = list(names) |
703 if not filtertopic(ui, topicname): | 746 if not filtertopic(ui, topicname): |
704 topiccats.setdefault(category, []).append((topicname, header)) | 747 topiccats.setdefault(category, []).append((topicname, header)) |
707 | 750 |
708 addtopichook(b'config', inserttweakrc) | 751 addtopichook(b'config', inserttweakrc) |
709 | 752 |
710 | 753 |
711 def help_( | 754 def help_( |
712 ui, | 755 ui: uimod.ui, |
713 commands, | 756 commands, |
714 name, | 757 name: bytes, |
715 unknowncmd=False, | 758 unknowncmd: bool = False, |
716 full=True, | 759 full: bool = True, |
717 subtopic=None, | 760 subtopic: Optional[bytes] = None, |
718 fullname=None, | 761 fullname: Optional[bytes] = None, |
719 **opts | 762 **opts |
720 ): | 763 ) -> bytes: |
721 """ | 764 """ |
722 Generate the help for 'name' as unformatted restructured text. If | 765 Generate the help for 'name' as unformatted restructured text. If |
723 'name' is None, describe the commands available. | 766 'name' is None, describe the commands available. |
724 """ | 767 """ |
725 | 768 |
726 opts = pycompat.byteskwargs(opts) | 769 opts = pycompat.byteskwargs(opts) |
727 | 770 |
728 def helpcmd(name, subtopic=None): | 771 def helpcmd(name: bytes, subtopic: Optional[bytes]) -> List[bytes]: |
729 try: | 772 try: |
730 aliases, entry = cmdutil.findcmd( | 773 aliases, entry = cmdutil.findcmd( |
731 name, commands.table, strict=unknowncmd | 774 name, commands.table, strict=unknowncmd |
732 ) | 775 ) |
733 except error.AmbiguousCommand as inst: | 776 except error.AmbiguousCommand as inst: |
824 ) | 867 ) |
825 ) | 868 ) |
826 | 869 |
827 return rst | 870 return rst |
828 | 871 |
829 def helplist(select=None, **opts): | 872 def helplist(select: Optional[_SelectFn] = None, **opts) -> List[bytes]: |
830 cats, h, syns = _getcategorizedhelpcmds( | 873 cats, h, syns = _getcategorizedhelpcmds( |
831 ui, commands.table, name, select | 874 ui, commands.table, name, select |
832 ) | 875 ) |
833 | 876 |
834 rst = [] | 877 rst = [] |
844 elif name == b"debug": | 887 elif name == b"debug": |
845 rst.append(_(b'debug commands (internal and unsupported):\n\n')) | 888 rst.append(_(b'debug commands (internal and unsupported):\n\n')) |
846 else: | 889 else: |
847 rst.append(_(b'list of commands:\n')) | 890 rst.append(_(b'list of commands:\n')) |
848 | 891 |
849 def appendcmds(cmds): | 892 def appendcmds(cmds: Iterable[bytes]) -> None: |
850 cmds = sorted(cmds) | 893 cmds = sorted(cmds) |
851 for c in cmds: | 894 for c in cmds: |
852 display_cmd = c | 895 display_cmd = c |
853 if ui.verbose: | 896 if ui.verbose: |
854 display_cmd = b', '.join(syns[c]) | 897 display_cmd = b', '.join(syns[c]) |
953 ) | 996 ) |
954 % (name and b" " + name or b"") | 997 % (name and b" " + name or b"") |
955 ) | 998 ) |
956 return rst | 999 return rst |
957 | 1000 |
958 def helptopic(name, subtopic=None): | 1001 def helptopic(name: bytes, subtopic: Optional[bytes] = None) -> List[bytes]: |
959 # Look for sub-topic entry first. | 1002 # Look for sub-topic entry first. |
960 header, doc = None, None | 1003 header, doc = None, None |
961 if subtopic and name in subtopics: | 1004 if subtopic and name in subtopics: |
962 for names, header, doc in subtopics[name]: | 1005 for names, header, doc in subtopics[name]: |
963 if subtopic in names: | 1006 if subtopic in names: |
996 ) | 1039 ) |
997 except error.UnknownCommand: | 1040 except error.UnknownCommand: |
998 pass | 1041 pass |
999 return rst | 1042 return rst |
1000 | 1043 |
1001 def helpext(name, subtopic=None): | 1044 def helpext(name: bytes, subtopic: Optional[bytes] = None) -> List[bytes]: |
1002 try: | 1045 try: |
1003 mod = extensions.find(name) | 1046 mod = extensions.find(name) |
1004 doc = gettext(pycompat.getdoc(mod)) or _(b'no help text available') | 1047 doc = gettext(pycompat.getdoc(mod)) or _(b'no help text available') |
1005 except KeyError: | 1048 except KeyError: |
1006 mod = None | 1049 mod = None |
1038 b" extensions)\n" | 1081 b" extensions)\n" |
1039 ) | 1082 ) |
1040 ) | 1083 ) |
1041 return rst | 1084 return rst |
1042 | 1085 |
1043 def helpextcmd(name, subtopic=None): | 1086 def helpextcmd( |
1087 name: bytes, subtopic: Optional[bytes] = None | |
1088 ) -> List[bytes]: | |
1044 cmd, ext, doc = extensions.disabledcmd( | 1089 cmd, ext, doc = extensions.disabledcmd( |
1045 ui, name, ui.configbool(b'ui', b'strict') | 1090 ui, name, ui.configbool(b'ui', b'strict') |
1046 ) | 1091 ) |
1047 doc = stringutil.firstline(doc) | 1092 doc = stringutil.firstline(doc) |
1048 | 1093 |
1125 | 1170 |
1126 return b''.join(rst) | 1171 return b''.join(rst) |
1127 | 1172 |
1128 | 1173 |
1129 def formattedhelp( | 1174 def formattedhelp( |
1130 ui, commands, fullname, keep=None, unknowncmd=False, full=True, **opts | 1175 ui: uimod.ui, |
1131 ): | 1176 commands, |
1177 fullname: Optional[bytes], | |
1178 keep: Optional[Iterable[bytes]] = None, | |
1179 unknowncmd: bool = False, | |
1180 full: bool = True, | |
1181 **opts | |
1182 ) -> bytes: | |
1132 """get help for a given topic (as a dotted name) as rendered rst | 1183 """get help for a given topic (as a dotted name) as rendered rst |
1133 | 1184 |
1134 Either returns the rendered help text or raises an exception. | 1185 Either returns the rendered help text or raises an exception. |
1135 """ | 1186 """ |
1136 if keep is None: | 1187 if keep is None: |