diff --git a/snooty/diagnostics.py b/snooty/diagnostics.py index 0ef6d879..c1d43652 100644 --- a/snooty/diagnostics.py +++ b/snooty/diagnostics.py @@ -1042,3 +1042,19 @@ def __init__( start, end, ) + + +class UnknownDefaultTabId(Diagnostic): + severity = Diagnostic.Level.warning + + def __init__( + self, + unknown_id: str, + start: Union[int, Tuple[int, int]], + end: Union[None, int, Tuple[int, int]] = None, + ): + super().__init__( + f"Option :default-tabid: '{unknown_id}' is not present in tabs on page.", + start, + end, + ) diff --git a/snooty/postprocess.py b/snooty/postprocess.py index 6b27e80d..d44c5a7d 100644 --- a/snooty/postprocess.py +++ b/snooty/postprocess.py @@ -63,6 +63,7 @@ SubstitutionRefError, TargetNotFound, UnexpectedDirectiveOrder, + UnknownDefaultTabId, UnnamedPage, UnsupportedFormat, ) @@ -578,6 +579,7 @@ def exit_node(self, fileid_stack: FileIdStack, node: n.Node) -> None: class TabsSelectorHandler(Handler): def __init__(self, context: Context) -> None: super().__init__(context) + self.default_tabs: Dict[str, str] = {} self.selectors: Dict[str, List[Dict[str, MutableSequence[n.Text]]]] = {} self.scanned_pattern: List[str] = [] self.target_pattern = ["tabs", "tabs", "procedure"] @@ -619,6 +621,9 @@ def enter_node(self, fileid_stack: FileIdStack, node: n.Node) -> None: ) return + if tabset_name == "drivers" and "default-tabid" in node.options: + self.default_tabs[tabset_name] = node.options.get("default-tabid", "") + self.selectors[tabset_name] = [] return @@ -677,6 +682,26 @@ def exit_page(self, fileid_stack: FileIdStack, page: Page) -> None: for tabid, title in tabsets[0].items() } + # If default_tabs are present, append to page options + if tabset_name in self.default_tabs: + default_tab_is_in_selectors = ( + self.default_tabs[tabset_name] + in page.ast.options["selectors"][tabset_name].keys() + ) + if not default_tab_is_in_selectors: + self.context.diagnostics[fileid_stack.current].append( + UnknownDefaultTabId(self.default_tabs[tabset_name] or "", 0) + ) + return + + if not page.ast.options.get("default_tabs"): + page.ast.options["default_tabs"] = {} + + assert isinstance(page.ast.options["default_tabs"], Dict) + page.ast.options["default_tabs"][tabset_name] = self.default_tabs[ + tabset_name + ] + class TargetHandler(Handler): def __init__(self, context: Context) -> None: diff --git a/snooty/rstspec.toml b/snooty/rstspec.toml index 60b4c355..d2cf0db4 100644 --- a/snooty/rstspec.toml +++ b/snooty/rstspec.toml @@ -344,6 +344,10 @@ options.glob = "flag" [directive.tabs-selector] help = """Add dropdown selector used to select the specified tabset.""" argument_type = "string" +options.default-tabid = "string" +example = """.. tabs-selector:: ${1: string} + :default-tabid: ${2:id of the default tab (Optional for drivers)} +""" [directive.tabs-pillstrip] deprecated = true diff --git a/snooty/test_postprocess.py b/snooty/test_postprocess.py index e7e7117d..5582a03e 100644 --- a/snooty/test_postprocess.py +++ b/snooty/test_postprocess.py @@ -32,6 +32,7 @@ TabMustBeDirective, TargetNotFound, UnexpectedDirectiveOrder, + UnknownDefaultTabId, ) from .n import FileId from .util_test import ( @@ -4529,3 +4530,76 @@ def test_footnote_id_numbers() -> None: """, ) + + +def test_default_tabs() -> None: + with make_test( + { + Path( + "source/index.txt" + ): """ +=================== +Heading of the page +=================== + +.. tabs-selector:: drivers + :default-tabid: python + +.. tabs-drivers:: + + .. tab:: + :tabid: c + + C + + .. tab:: + :tabid: nodejs + + Node.js + + .. tab:: + :tabid: python + + Python +""", + } + ) as result: + page = result.pages[FileId("index.txt")] + assert (page.ast.options.get("default_tabs")) == {"drivers": "python"} + + +def test_default_tabs_not_present() -> None: + with make_test( + { + Path( + "source/index.txt" + ): """ +=================== +Heading of the page +=================== + +.. tabs-selector:: drivers + :default-tabid: no-language + +.. tabs-drivers:: + + .. tab:: + :tabid: c + + C + + .. tab:: + :tabid: nodejs + + Node.js + + .. tab:: + :tabid: python + + Python +""", + } + ) as result: + diagnostics = result.diagnostics[FileId("index.txt")] + assert len(diagnostics) == 1 + assert isinstance(diagnostics[0], UnknownDefaultTabId)