From fdb8b30da72b838b5e5f6c36b1eaa9177f16d7bf 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] 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 6dafa972e35..740979af631 100644 --- a/doc/_extensions/zephyr/domain/__init__.py +++ b/doc/_extensions/zephyr/domain/__init__.py @@ -36,7 +36,7 @@ from typing import Any 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 @@ class BoardSupportedHardwareDirective(SphinxDirective): 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 the board/SoC DTS files.
vnd,foo @@ -870,7 +871,7 @@ class BoardSupportedHardwareDirective(SphinxDirective): 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 @@ class BoardSupportedHardwareDirective(SphinxDirective): 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 + ) - if disabled_count > 0: - disabled_count_indicator = nodes.inline( - classes=["count", "disabled-count"], - text=str(disabled_count), + 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) + ) + + # 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 26492e0a1d9..5a50c419fb0 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 681b7a735b6..482fbf208f5 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.