From 31a66e186a3a4a9ad663e19116860639216bf23d Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Thu, 28 Sep 2023 20:11:31 -0400 Subject: [PATCH] doc: add ability to disambiguate clicmds Multiple daemons have the same CLI commands defined, but the current directive used to document CLI commands only takes the command definition string. Since CLI command objects can be cross-referenced using the :clicmd: directive, and are placed in the index, each object needs to be unique. To accomplish this, add a custom directive. This directive extends the directive class used by sphinx's add_object_type to add a :daemon: option. By specifying this option where needed, the object name becomes "() ", disambiguating it. Signed-off-by: Quentin Young --- doc/user/conf.py | 48 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/doc/user/conf.py b/doc/user/conf.py index 728f9c936486..574bfd0a4d4e 100644 --- a/doc/user/conf.py +++ b/doc/user/conf.py @@ -18,6 +18,8 @@ import pygments import sphinx from sphinx.highlighting import lexers +from sphinx.domains.std import GenericObject +from docutils.parsers.rst import directives # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -372,11 +374,49 @@ def vparse(s): return a[:3] -# custom extensions here +class ClicmdDirective(GenericObject): + """ + Directive for documenting CLI commands. + + The xref string, if no option is provided, will be the verbatim command + string. If the :daemon: option is provided, then it's + "() )". + + Options: + :daemon: - specify the daemon this command belongs to. Useful for + disambiguating multiple definitions of the same command. + """ + + has_content = True + required_arguments = 1 + optional_arguments = 0 + option_spec = { + **GenericObject.option_spec, + "daemon": directives.unchanged, + } + + def handle_signature(self, sig, signode): + name = super().handle_signature(sig, signode) + daemon = self.options["daemon"] if "daemon" in self.options else "" + prefix = f"({daemon}) " if daemon else "" + return prefix + name + + def run(self): + daemon = self.options["daemon"] if "daemon" in self.options else "" + if daemon: + self.indextemplate = f"pair: ({daemon}) %s; configuration command" + else: + self.indextemplate = f"pair: %s; configuration command" + + nodes = super().run() + + return nodes + + def setup(app): - # object type for FRR CLI commands, can be extended to document parent CLI - # node later on - app.add_object_type("clicmd", "clicmd", indextemplate="pair: %s; configuration command") + app.add_object_type("clicmd", "clicmd", objname="CLI command") + # Override the directive that was just created for us + app.add_directive_to_domain("std", "clicmd", ClicmdDirective, override=True) # I dont care how stupid this is if "add_js_file" in dir(app):