Skip to content

Commit

Permalink
doc: extensions: Navigate to DTS entries from supported hardware list
Browse files Browse the repository at this point in the history
Update the gen_board_catalog.py logic to capture filename/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é <[email protected]>
  • Loading branch information
kartben committed Feb 27, 2025
1 parent 86e7e7d commit 1801ecc
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 31 deletions.
70 changes: 45 additions & 25 deletions doc/_extensions/zephyr/domain/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -798,17 +798,20 @@ def run(self):
return result_nodes

html_contents = """<div class="legend admonition">
<dl class="simple supported-hardware field-list">
<dt><span class="location-chip onchip">on-chip</span></dt>
<dd>Feature integrated in the SoC.</dd>
<dt><span class="location-chip onboard">on-board</span></dt>
<dd>Feature present on the board.</dd>
<dt><span class="count okay-count">2</span></dt>
<dd>Number of instances of the feature that are present and enabled.</dd>
<dt><span class="count disabled-count">2</span></dt>
<dd>Number of instances of the feature that are present but initially disabled.</dd>
<dl class="supported-hardware field-list">
<dt><span class="location-chip onchip">on-chip</span> / <span
class="location-chip onboard">on-board</span></dt>
<dd>
Feature integrated in the SoC / present on the board.
</dd>
<dt><span class="count okay-count">2</span> / <span class="count disabled-count">2</span></dt>
<dd>
Number of instances that are enabled / disabled. <br/>
Click on the label to see the first instance of this feature in DTS source files.
</dd>
<dt><code class="docutils literal notranslate"><span class="pre">vnd,foo</span></code></dt>
<dd>Compatible string for the Devicetree binding matching the feature.
<dd>
Compatible string for the Devicetree binding matching the feature. <br/>
Click on the link to checkout the binding documentation.
</dd>
</dl>
Expand Down Expand Up @@ -861,7 +864,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
Expand Down Expand Up @@ -902,22 +905,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 disabled_count > 0:
disabled_count_indicator = nodes.inline(
classes=["count", "disabled-count"],
text=str(disabled_count),
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
Expand Down
2 changes: 1 addition & 1 deletion doc/_extensions/zephyr/domain/static/css/board.css
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@

.legend {
font-size: 0.9em;
max-width: 600px;
border-radius: 6px;
margin: auto;

Expand Down Expand Up @@ -179,6 +178,7 @@
font-size: 0.7em;
font-weight: 600;
margin-left: 4px;
padding-right: 6px !important;

&::before {
content: "×";
Expand Down
21 changes: 16 additions & 5 deletions doc/_scripts/gen_boards_catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -284,15 +285,25 @@ def get_catalog(generate_hw_features=False):
)
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
node_info = {"filename": str(filename), "lineno": lineno}
if node.status == "okay":
existing_feature.setdefault("okay_nodes", []).append(node_info)
else:
existing_feature.setdefault("disabled_nodes", []).append(node_info)
else:
key = "okay_count" if node.status == "okay" else "disabled_count"
target_features.setdefault(binding_type, {})[node.matching_compat] = {
node_info = {"filename": str(filename), "lineno": lineno}
feature_data = {
"description": description,
"locations": locations,
key: 1
}
if node.status == "okay":
feature_data["okay_nodes"] = [node_info]
feature_data["disabled_nodes"] = []
else:
feature_data["okay_nodes"] = []
feature_data["disabled_nodes"] = [node_info]

target_features.setdefault(binding_type, {})[node.matching_compat] = feature_data

Check failure on line 306 in doc/_scripts/gen_boards_catalog.py

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

Python lint error (E501) see https://docs.astral.sh/ruff/rules/line-too-long

doc/_scripts/gen_boards_catalog.py:306 Line too long (105 > 100)

# Store features for this specific target
supported_features[board_target] = target_features
Expand Down

0 comments on commit 1801ecc

Please sign in to comment.