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.
--- a/doc/gendoc.py Wed Sep 11 20:52:51 2024 +0200
+++ b/doc/gendoc.py Thu Sep 05 12:28:12 2024 +0200
@@ -156,7 +156,8 @@
for extensionname in sorted(allextensionnames()):
mod = extensions.load(ui, extensionname, None)
ui.write(minirst.subsection(extensionname))
- ui.write(b"%s\n\n" % gettext(pycompat.getdoc(mod)))
+ ext_doc = help.ext_help(ui, mod)
+ ui.write(b"%s\n\n" % ext_doc)
cmdtable = getattr(mod, 'cmdtable', None)
if cmdtable:
ui.write(minirst.subsubsection(_(b'Commands')))
--- a/mercurial/help.py Wed Sep 11 20:52:51 2024 +0200
+++ b/mercurial/help.py Thu Sep 05 12:28:12 2024 +0200
@@ -159,6 +159,15 @@
return rst
+def ext_help(ui: uimod.ui, ext) -> bytes:
+ doc = pycompat.getdoc(ext)
+ if doc is None:
+ return b""
+ assert doc is not None
+ doc = gettext(doc)
+ return sub_config_item_help(ui, doc)
+
+
def extshelp(ui: uimod.ui) -> bytes:
rst = loaddoc(b'extensions')(ui).splitlines(True)
rst.extend(
@@ -365,6 +374,7 @@
doc = gettext(fp.read())
for rewriter in helphooks.get(topic, []):
doc = rewriter(ui, topic, doc)
+ doc = sub_config_item_help(ui, doc)
return doc
return loader
@@ -695,6 +705,44 @@
return re.sub(br'( *)%s' % re.escape(marker), sub, doc)
+_CONFIG_DOC_RE = re.compile(b'(^ *)?:config-doc:`([^`]+)`', flags=re.MULTILINE)
+
+
+def sub_config_item_help(ui: uimod.ui, doc: bytes) -> bytes:
+ """replace :config-doc:`foo.bar` markup with the item documentation
+
+ This allow grouping config item declaration and help without having to
+ repeat it in the help text file and keep that in sync.
+ """
+ pieces = []
+ last_match_end = 0
+ for match in _CONFIG_DOC_RE.finditer(doc):
+ # finditer is expected to yield result in order
+ start = match.start()
+ assert last_match_end <= match.start()
+ pieces.append(doc[last_match_end:start])
+ item_name = match.group(2)
+ section, key = item_name.split(b'.', 1)
+ section_items = ui._knownconfig.get(section)
+ if section_items is None:
+ item = None
+ else:
+ item = section_items.get(key)
+ if item is None or not item.documentation:
+ item_doc = b'<missing help text for `%s`>' % item_name
+ else:
+ item_doc = gettext(item.documentation)
+ item_doc = sub_config_item_help(ui, item_doc)
+ indent = match.group(1)
+ if indent: # either None or 0 should be ignored
+ indent = indent
+ item_doc = indent + item_doc.replace(b'\n', b'\n' + indent)
+ pieces.append(item_doc)
+ last_match_end = match.end()
+ pieces.append(doc[last_match_end:])
+ return b''.join(pieces)
+
+
def _getcategorizedhelpcmds(
ui: uimod.ui, cmdtable, name: bytes, select: Optional[_SelectFn] = None
) -> Tuple[Dict[bytes, List[bytes]], Dict[bytes, bytes], _SynonymTable]:
@@ -822,6 +870,7 @@
doc,
source,
)
+ doc = sub_config_item_help(ui, doc)
doc = doc.splitlines(True)
if ui.quiet or not full:
rst.append(doc[0])
@@ -1042,12 +1091,15 @@
def helpext(name: bytes, subtopic: Optional[bytes] = None) -> List[bytes]:
try:
mod = extensions.find(name)
- doc = gettext(pycompat.getdoc(mod)) or _(b'no help text available')
+ doc = ext_help(ui, mod)
+ if not doc:
+ doc = _(b'no help text available')
except KeyError:
mod = None
doc = extensions.disabled_help(name)
if not doc:
raise error.UnknownCommand(name)
+ doc = sub_config_item_help(ui, doc)
if b'\n' not in doc:
head, tail = doc, b""