Mercurial > public > mercurial-scm > hg
comparison mercurial/help.py @ 51840:76387080f238
help: add :config-doc:`section.key` shorthand to insert documentation
The config items defined in the configitems.toml file can already hold their
documentation. Having some way to automatically insert it was a long standing
low hanging fruit. So I did a first implementation on that. It fairly simple,
but it open the door to more.
It will be used in the next changeset.
author | Pierre-Yves David <pierre-yves.david@octobus.net> |
---|---|
date | Thu, 05 Sep 2024 12:28:12 +0200 |
parents | 18c8c18993f0 |
children | 607e94e01851 |
comparison
equal
deleted
inserted
replaced
51839:fe08a0bfa9fd | 51840:76387080f238 |
---|---|
155 continue | 155 continue |
156 rst.append(b'%s:%s: %s\n' % (b' ' * indent, name, desc)) | 156 rst.append(b'%s:%s: %s\n' % (b' ' * indent, name, desc)) |
157 if rst: | 157 if rst: |
158 rst.insert(0, b'\n%s\n\n' % header) | 158 rst.insert(0, b'\n%s\n\n' % header) |
159 return rst | 159 return rst |
160 | |
161 | |
162 def ext_help(ui: uimod.ui, ext) -> bytes: | |
163 doc = pycompat.getdoc(ext) | |
164 if doc is None: | |
165 return b"" | |
166 assert doc is not None | |
167 doc = gettext(doc) | |
168 return sub_config_item_help(ui, doc) | |
160 | 169 |
161 | 170 |
162 def extshelp(ui: uimod.ui) -> bytes: | 171 def extshelp(ui: uimod.ui) -> bytes: |
163 rst = loaddoc(b'extensions')(ui).splitlines(True) | 172 rst = loaddoc(b'extensions')(ui).splitlines(True) |
164 rst.extend( | 173 rst.extend( |
363 package += b'.' + subdir | 372 package += b'.' + subdir |
364 with resourceutil.open_resource(package, topic + b'.txt') as fp: | 373 with resourceutil.open_resource(package, topic + b'.txt') as fp: |
365 doc = gettext(fp.read()) | 374 doc = gettext(fp.read()) |
366 for rewriter in helphooks.get(topic, []): | 375 for rewriter in helphooks.get(topic, []): |
367 doc = rewriter(ui, topic, doc) | 376 doc = rewriter(ui, topic, doc) |
377 doc = sub_config_item_help(ui, doc) | |
368 return doc | 378 return doc |
369 | 379 |
370 return loader | 380 return loader |
371 | 381 |
372 | 382 |
693 return b'\n'.join(lines) | 703 return b'\n'.join(lines) |
694 | 704 |
695 return re.sub(br'( *)%s' % re.escape(marker), sub, doc) | 705 return re.sub(br'( *)%s' % re.escape(marker), sub, doc) |
696 | 706 |
697 | 707 |
708 _CONFIG_DOC_RE = re.compile(b'(^ *)?:config-doc:`([^`]+)`', flags=re.MULTILINE) | |
709 | |
710 | |
711 def sub_config_item_help(ui: uimod.ui, doc: bytes) -> bytes: | |
712 """replace :config-doc:`foo.bar` markup with the item documentation | |
713 | |
714 This allow grouping config item declaration and help without having to | |
715 repeat it in the help text file and keep that in sync. | |
716 """ | |
717 pieces = [] | |
718 last_match_end = 0 | |
719 for match in _CONFIG_DOC_RE.finditer(doc): | |
720 # finditer is expected to yield result in order | |
721 start = match.start() | |
722 assert last_match_end <= match.start() | |
723 pieces.append(doc[last_match_end:start]) | |
724 item_name = match.group(2) | |
725 section, key = item_name.split(b'.', 1) | |
726 section_items = ui._knownconfig.get(section) | |
727 if section_items is None: | |
728 item = None | |
729 else: | |
730 item = section_items.get(key) | |
731 if item is None or not item.documentation: | |
732 item_doc = b'<missing help text for `%s`>' % item_name | |
733 else: | |
734 item_doc = gettext(item.documentation) | |
735 item_doc = sub_config_item_help(ui, item_doc) | |
736 indent = match.group(1) | |
737 if indent: # either None or 0 should be ignored | |
738 indent = indent | |
739 item_doc = indent + item_doc.replace(b'\n', b'\n' + indent) | |
740 pieces.append(item_doc) | |
741 last_match_end = match.end() | |
742 pieces.append(doc[last_match_end:]) | |
743 return b''.join(pieces) | |
744 | |
745 | |
698 def _getcategorizedhelpcmds( | 746 def _getcategorizedhelpcmds( |
699 ui: uimod.ui, cmdtable, name: bytes, select: Optional[_SelectFn] = None | 747 ui: uimod.ui, cmdtable, name: bytes, select: Optional[_SelectFn] = None |
700 ) -> Tuple[Dict[bytes, List[bytes]], Dict[bytes, bytes], _SynonymTable]: | 748 ) -> Tuple[Dict[bytes, List[bytes]], Dict[bytes, bytes], _SynonymTable]: |
701 # Category -> list of commands | 749 # Category -> list of commands |
702 cats = {} | 750 cats = {} |
820 doc = _(b'alias for: hg %s\n\n%s\n\ndefined by: %s\n') % ( | 868 doc = _(b'alias for: hg %s\n\n%s\n\ndefined by: %s\n') % ( |
821 entry[0].definition, | 869 entry[0].definition, |
822 doc, | 870 doc, |
823 source, | 871 source, |
824 ) | 872 ) |
873 doc = sub_config_item_help(ui, doc) | |
825 doc = doc.splitlines(True) | 874 doc = doc.splitlines(True) |
826 if ui.quiet or not full: | 875 if ui.quiet or not full: |
827 rst.append(doc[0]) | 876 rst.append(doc[0]) |
828 else: | 877 else: |
829 rst.extend(doc) | 878 rst.extend(doc) |
1040 return rst | 1089 return rst |
1041 | 1090 |
1042 def helpext(name: bytes, subtopic: Optional[bytes] = None) -> List[bytes]: | 1091 def helpext(name: bytes, subtopic: Optional[bytes] = None) -> List[bytes]: |
1043 try: | 1092 try: |
1044 mod = extensions.find(name) | 1093 mod = extensions.find(name) |
1045 doc = gettext(pycompat.getdoc(mod)) or _(b'no help text available') | 1094 doc = ext_help(ui, mod) |
1095 if not doc: | |
1096 doc = _(b'no help text available') | |
1046 except KeyError: | 1097 except KeyError: |
1047 mod = None | 1098 mod = None |
1048 doc = extensions.disabled_help(name) | 1099 doc = extensions.disabled_help(name) |
1049 if not doc: | 1100 if not doc: |
1050 raise error.UnknownCommand(name) | 1101 raise error.UnknownCommand(name) |
1102 doc = sub_config_item_help(ui, doc) | |
1051 | 1103 |
1052 if b'\n' not in doc: | 1104 if b'\n' not in doc: |
1053 head, tail = doc, b"" | 1105 head, tail = doc, b"" |
1054 else: | 1106 else: |
1055 head, tail = doc.split(b'\n', 1) | 1107 head, tail = doc.split(b'\n', 1) |