doc: extensions: Navigate to DTS entries from supported hardware list
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é <benjamin@zephyrproject.org>
This commit is contained in:
parent
235fabb06b
commit
fdb8b30da7
3 changed files with 55 additions and 28 deletions
|
@ -36,7 +36,7 @@ from typing import Any
|
||||||
|
|
||||||
from anytree import ChildResolverError, Node, PreOrderIter, Resolver, search
|
from anytree import ChildResolverError, Node, PreOrderIter, Resolver, search
|
||||||
from docutils import nodes
|
from docutils import nodes
|
||||||
from docutils.parsers.rst import directives
|
from docutils.parsers.rst import directives, roles
|
||||||
from docutils.statemachine import StringList
|
from docutils.statemachine import StringList
|
||||||
from sphinx import addnodes
|
from sphinx import addnodes
|
||||||
from sphinx.application import Sphinx
|
from sphinx.application import Sphinx
|
||||||
|
@ -811,7 +811,8 @@ class BoardSupportedHardwareDirective(SphinxDirective):
|
||||||
<span class="count disabled-count">2</span>
|
<span class="count disabled-count">2</span>
|
||||||
</dt>
|
</dt>
|
||||||
<dd>
|
<dd>
|
||||||
Number of instances that are enabled / disabled.
|
Number of instances that are enabled / disabled. <br/>
|
||||||
|
Click on the label to see the first instance of this feature in the board/SoC DTS files.
|
||||||
</dd>
|
</dd>
|
||||||
<dt>
|
<dt>
|
||||||
<code class="docutils literal notranslate"><span class="pre">vnd,foo</span></code>
|
<code class="docutils literal notranslate"><span class="pre">vnd,foo</span></code>
|
||||||
|
@ -870,7 +871,7 @@ class BoardSupportedHardwareDirective(SphinxDirective):
|
||||||
|
|
||||||
for i, (key, value) in enumerate(items):
|
for i, (key, value) in enumerate(items):
|
||||||
row = nodes.row()
|
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")
|
row["classes"].append("disabled")
|
||||||
|
|
||||||
# TYPE column
|
# TYPE column
|
||||||
|
@ -911,22 +912,39 @@ class BoardSupportedHardwareDirective(SphinxDirective):
|
||||||
desc_para += nodes.Text(value["description"])
|
desc_para += nodes.Text(value["description"])
|
||||||
|
|
||||||
# Add count indicators for okay and not-okay instances
|
# Add count indicators for okay and not-okay instances
|
||||||
okay_count = value.get("okay_count", 0)
|
okay_nodes = value.get("okay_nodes", [])
|
||||||
disabled_count = value.get("disabled_count", 0)
|
disabled_nodes = value.get("disabled_nodes", [])
|
||||||
|
|
||||||
if okay_count > 0:
|
role_fn, _ = roles.role(
|
||||||
okay_count_indicator = nodes.inline(
|
"zephyr_file", self.state_machine.language, self.lineno, self.state.reporter
|
||||||
classes=["count", "okay-count"],
|
)
|
||||||
text=str(okay_count),
|
|
||||||
)
|
|
||||||
desc_para += okay_count_indicator
|
|
||||||
|
|
||||||
if disabled_count > 0:
|
def create_count_indicator(nodes_list, class_type, role_function=role_fn):
|
||||||
disabled_count_indicator = nodes.inline(
|
if not nodes_list:
|
||||||
classes=["count", "disabled-count"],
|
return None
|
||||||
text=str(disabled_count),
|
|
||||||
|
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
|
desc_entry += desc_para
|
||||||
row += desc_entry
|
row += desc_entry
|
||||||
|
|
|
@ -178,6 +178,7 @@
|
||||||
font-size: 0.7em;
|
font-size: 0.7em;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
|
padding-right: 6px !important;
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
content: "×";
|
content: "×";
|
||||||
|
|
|
@ -254,7 +254,7 @@ def get_catalog(generate_hw_features=False):
|
||||||
# Use pre-gathered build info and DTS files
|
# Use pre-gathered build info and DTS files
|
||||||
if board.name in board_devicetrees:
|
if board.name in board_devicetrees:
|
||||||
for board_target, edt in board_devicetrees[board.name].items():
|
for board_target, edt in board_devicetrees[board.name].items():
|
||||||
target_features = {}
|
features = {}
|
||||||
for node in edt.nodes:
|
for node in edt.nodes:
|
||||||
if node.binding_path is None:
|
if node.binding_path is None:
|
||||||
continue
|
continue
|
||||||
|
@ -271,6 +271,7 @@ def get_catalog(generate_hw_features=False):
|
||||||
|
|
||||||
description = DeviceTreeUtils.get_cached_description(node)
|
description = DeviceTreeUtils.get_cached_description(node)
|
||||||
filename = node.filename
|
filename = node.filename
|
||||||
|
lineno = node.lineno
|
||||||
locations = set()
|
locations = set()
|
||||||
if Path(filename).is_relative_to(ZEPHYR_BASE):
|
if Path(filename).is_relative_to(ZEPHYR_BASE):
|
||||||
filename = Path(filename).relative_to(ZEPHYR_BASE)
|
filename = Path(filename).relative_to(ZEPHYR_BASE)
|
||||||
|
@ -279,23 +280,30 @@ def get_catalog(generate_hw_features=False):
|
||||||
else:
|
else:
|
||||||
locations.add("soc")
|
locations.add("soc")
|
||||||
|
|
||||||
existing_feature = target_features.get(binding_type, {}).get(
|
existing_feature = features.get(binding_type, {}).get(
|
||||||
node.matching_compat
|
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:
|
if existing_feature:
|
||||||
locations.update(existing_feature["locations"])
|
locations.update(existing_feature["locations"])
|
||||||
key = "okay_count" if node.status == "okay" else "disabled_count"
|
existing_feature.setdefault(node_list_key, []).append(node_info)
|
||||||
existing_feature[key] = existing_feature.get(key, 0) + 1
|
continue
|
||||||
else:
|
|
||||||
key = "okay_count" if node.status == "okay" else "disabled_count"
|
feature_data = {
|
||||||
target_features.setdefault(binding_type, {})[node.matching_compat] = {
|
"description": description,
|
||||||
"description": description,
|
"locations": locations,
|
||||||
"locations": locations,
|
"okay_nodes": [],
|
||||||
key: 1
|
"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
|
# 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
|
# Grab all the twister files for this board and use them to figure out all the archs it
|
||||||
# supports.
|
# supports.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue