From 6490e0b98ca7d9f333283fc9cc8d2a5404244e88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 27 Feb 2025 08:06:59 +0100 Subject: [PATCH 1/2] doc: _extensions: simplify legend creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use raw HTML as there's no point in having lots of docutils boilerplate for what's effectively static content Signed-off-by: Benjamin Cabé --- doc/_extensions/zephyr/domain/__init__.py | 75 +++++++------------ .../zephyr/domain/static/css/board.css | 1 - 2 files changed, 26 insertions(+), 50 deletions(-) diff --git a/doc/_extensions/zephyr/domain/__init__.py b/doc/_extensions/zephyr/domain/__init__.py index 3081460254a2..6dafa972e355 100644 --- a/doc/_extensions/zephyr/domain/__init__.py +++ b/doc/_extensions/zephyr/domain/__init__.py @@ -797,55 +797,32 @@ def run(self): result_nodes.append(note) return result_nodes - # Add the note before any tables - note = nodes.admonition(classes=["legend"]) - note += nodes.title(text="Table Legend", classes=["note"]) - - legend = nodes.definition_list(classes=["supported-hardware field-list"]) - - def add_legend_item(legend_list, term_text, term_classes, definition_text): - dl_item = nodes.definition_list_item() - dt = nodes.term() - dt += nodes.inline("", term_text, classes=term_classes) - dd = nodes.definition() - dd += nodes.Text(definition_text) - dl_item += dt - dl_item += dd - legend_list += dl_item - - add_legend_item( - legend, "on-chip", ["location-chip", "onchip"], "Feature integrated in the SoC." - ) - add_legend_item( - legend, "on-board", ["location-chip", "onboard"], "Feature present on the board." - ) - add_legend_item( - legend, - "2", - ["count", "okay-count"], - "Number of instances of the feature that are present and enabled.", - ) - add_legend_item( - legend, - "2", - ["count", "disabled-count"], - "Number of instances of the feature that are present but initially disabled.", - ) - - dl_item = nodes.definition_list_item() - dt = nodes.term() - dt += nodes.literal(text="vnd,foo") - dd = nodes.definition() - dd += nodes.Text( - "Compatible string for the Devicetree binding matching the feature. " - "Click on the link to checkout the binding documentation." - ) - dl_item += dt - dl_item += dd - legend += dl_item - - note += legend - result_nodes.append(note) + html_contents = """
+
+
+ on-chip / + on-board +
+
+ Feature integrated in the SoC / present on the board. +
+
+ 2 / + 2 +
+
+ Number of instances that are enabled / disabled. +
+
+ vnd,foo +
+
+ Compatible string for the Devicetree binding matching the feature.
+ Click on the link to view the binding documentation. +
+
+
""" + result_nodes.append(nodes.raw("", html_contents, format="html")) for target, features in sorted(supported_features.items()): if not features: diff --git a/doc/_extensions/zephyr/domain/static/css/board.css b/doc/_extensions/zephyr/domain/static/css/board.css index 1224067bfff2..26492e0a1d94 100644 --- a/doc/_extensions/zephyr/domain/static/css/board.css +++ b/doc/_extensions/zephyr/domain/static/css/board.css @@ -83,7 +83,6 @@ .legend { font-size: 0.9em; - max-width: 600px; border-radius: 6px; margin: auto; From cae6dc082887ee5af9d8fb8aefd2261d772730ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 27 Feb 2025 12:21:39 +0100 Subject: [PATCH 2/2] doc: extensions: Navigate to DTS entries from supported hardware list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update the gen_board_catalog.py logic to also capture lineno for each devicetree node. Use that info in the supported hardware list to create clickable elements that directly take the user to the corresponding line in the devicetree file on Github. Signed-off-by: Benjamin Cabé --- doc/_extensions/zephyr/domain/__init__.py | 50 +++++++++++++------ .../zephyr/domain/static/css/board.css | 1 + doc/_scripts/gen_boards_catalog.py | 32 +++++++----- 3 files changed, 55 insertions(+), 28 deletions(-) diff --git a/doc/_extensions/zephyr/domain/__init__.py b/doc/_extensions/zephyr/domain/__init__.py index 6dafa972e355..38cacd20d119 100644 --- a/doc/_extensions/zephyr/domain/__init__.py +++ b/doc/_extensions/zephyr/domain/__init__.py @@ -36,7 +36,7 @@ from anytree import ChildResolverError, Node, PreOrderIter, Resolver, search from docutils import nodes -from docutils.parsers.rst import directives +from docutils.parsers.rst import directives, roles from docutils.statemachine import StringList from sphinx import addnodes from sphinx.application import Sphinx @@ -811,7 +811,8 @@ def run(self): 2
- Number of instances that are enabled / disabled. + Number of instances that are enabled / disabled.
+ Click on the label to see the first instance of this feature in DTS source files.
vnd,foo @@ -870,7 +871,7 @@ def feature_sort_key(feature): for i, (key, value) in enumerate(items): row = nodes.row() - if value.get("disabled_count", 0) > 0 and value.get("okay_count", 0) == 0: + if value.get("disabled_nodes", []) and not value.get("okay_nodes", []): row["classes"].append("disabled") # TYPE column @@ -911,22 +912,39 @@ def feature_sort_key(feature): desc_para += nodes.Text(value["description"]) # Add count indicators for okay and not-okay instances - okay_count = value.get("okay_count", 0) - disabled_count = value.get("disabled_count", 0) + okay_nodes = value.get("okay_nodes", []) + disabled_nodes = value.get("disabled_nodes", []) - if okay_count > 0: - okay_count_indicator = nodes.inline( - classes=["count", "okay-count"], - text=str(okay_count), - ) - desc_para += okay_count_indicator + role_fn, _ = roles.role( + "zephyr_file", self.state_machine.language, self.lineno, self.state.reporter + ) + + def create_count_indicator(nodes_list, class_type, role_function=role_fn): + if not nodes_list: + return None + + count = len(nodes_list) + + if role_function is None: + return nodes.inline( + classes=["count", f"{class_type}-count"], text=str(count) + ) - if disabled_count > 0: - disabled_count_indicator = nodes.inline( - classes=["count", "disabled-count"], - text=str(disabled_count), + # Create a reference to the first node in the list + first_node = nodes_list[0] + file_ref = f"{count} <{first_node['filename']}#L{first_node['lineno']}>" + + role_nodes, _ = role_function( + "zephyr_file", file_ref, file_ref, self.lineno, self.state.inliner ) - desc_para += disabled_count_indicator + + count_node = role_nodes[0] + count_node["classes"] = ["count", f"{class_type}-count"] + + return count_node + + desc_para += create_count_indicator(okay_nodes, "okay") + desc_para += create_count_indicator(disabled_nodes, "disabled") desc_entry += desc_para row += desc_entry diff --git a/doc/_extensions/zephyr/domain/static/css/board.css b/doc/_extensions/zephyr/domain/static/css/board.css index 26492e0a1d94..5a50c419fb03 100644 --- a/doc/_extensions/zephyr/domain/static/css/board.css +++ b/doc/_extensions/zephyr/domain/static/css/board.css @@ -178,6 +178,7 @@ font-size: 0.7em; font-weight: 600; margin-left: 4px; + padding-right: 6px !important; &::before { content: "×"; diff --git a/doc/_scripts/gen_boards_catalog.py b/doc/_scripts/gen_boards_catalog.py index 681b7a735b6c..482fbf208f57 100755 --- a/doc/_scripts/gen_boards_catalog.py +++ b/doc/_scripts/gen_boards_catalog.py @@ -254,7 +254,7 @@ def get_catalog(generate_hw_features=False): # Use pre-gathered build info and DTS files if board.name in board_devicetrees: for board_target, edt in board_devicetrees[board.name].items(): - target_features = {} + features = {} for node in edt.nodes: if node.binding_path is None: continue @@ -271,6 +271,7 @@ def get_catalog(generate_hw_features=False): description = DeviceTreeUtils.get_cached_description(node) filename = node.filename + lineno = node.lineno locations = set() if Path(filename).is_relative_to(ZEPHYR_BASE): filename = Path(filename).relative_to(ZEPHYR_BASE) @@ -279,23 +280,30 @@ def get_catalog(generate_hw_features=False): else: locations.add("soc") - existing_feature = target_features.get(binding_type, {}).get( + existing_feature = features.get(binding_type, {}).get( node.matching_compat ) + + node_info = {"filename": str(filename), "lineno": lineno} + node_list_key = "okay_nodes" if node.status == "okay" else "disabled_nodes" + if existing_feature: locations.update(existing_feature["locations"]) - key = "okay_count" if node.status == "okay" else "disabled_count" - existing_feature[key] = existing_feature.get(key, 0) + 1 - else: - key = "okay_count" if node.status == "okay" else "disabled_count" - target_features.setdefault(binding_type, {})[node.matching_compat] = { - "description": description, - "locations": locations, - key: 1 - } + existing_feature.setdefault(node_list_key, []).append(node_info) + continue + + feature_data = { + "description": description, + "locations": locations, + "okay_nodes": [], + "disabled_nodes": [], + } + feature_data[node_list_key].append(node_info) + + features.setdefault(binding_type, {})[node.matching_compat] = feature_data # Store features for this specific target - supported_features[board_target] = target_features + supported_features[board_target] = features # Grab all the twister files for this board and use them to figure out all the archs it # supports.