Skip to content

Commit 2412820

Browse files
juiwenchenubmarco
andauthored
πŸ› Handle id_required for src-trace (#35)
* added id field for src-trace * adapt id_requred * updated snapshot * add hashed id when not given * changed extra to additional * checked SN extension * Update src/sphinx_codelinks/sphinx_extension/source_tracing.py Co-authored-by: Marco Heinemann <[email protected]> * adapted error msg --------- Co-authored-by: Marco Heinemann <[email protected]>
1 parent 3a22828 commit 2412820

File tree

11 files changed

+134
-10
lines changed

11 files changed

+134
-10
lines changed

β€Ždocs/conf.pyβ€Ž

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,8 @@
7979
html_context = {"repository": "useblocks/sphinx-codelinks"}
8080
html_css_files = ["furo.css"]
8181

82+
# Sphinx-Needs configuration
83+
needs_from_toml = "ubproject.toml"
84+
85+
# Src-trace configuration
8286
src_trace_config_from_toml = "./src_trace.toml"

β€Ždocs/source/components/directive.rstβ€Ž

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,14 @@ The ``src-trace`` directive can be used with the **file** option:
5252
.. code-block:: rst
5353
5454
.. src-trace:: dcdc demo_1
55+
:id: SRC_001
5556
:project: dcdc
5657
:file: ./charge/demo_1.cpp
5758
5859
The needs defined in source code are extracted and rendered to:
5960

6061
.. src-trace:: dcdc demo_1
62+
:id: SRC_001
6163
:project: dcdc
6264
:file: ./charge/demo_1.cpp
6365

@@ -66,12 +68,14 @@ The ``src-trace`` directive can be used with the **directory** option:
6668
.. code-block:: rst
6769
6870
.. src-trace:: dcdc charge
71+
:id: SRC_001
6972
:project: dcdc
7073
:directory: ./discharge
7174
7275
The needs defined in source code are extracted and rendered to:
7376

7477
.. src-trace:: dcdc charge
78+
:id: SRC_002
7579
:project: dcdc
7680
:directory: ./discharge
7781

β€Ždocs/ubproject.tomlβ€Ž

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,3 @@ ignore = ["block.title_line"]
55

66
[needs]
77
id_required = true
8-
9-
[[needs.types]]
10-
directive = "my-req"
11-
title = "My Requirement"
12-
prefix = "M_"

β€Žsrc/sphinx_codelinks/sphinx_extension/directives/src_trace.pyβ€Ž

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from collections.abc import Callable
2+
import hashlib
23
import os
34
from pathlib import Path
45
from typing import Any, ClassVar, cast
@@ -7,6 +8,7 @@
78
from docutils.parsers.rst import directives
89
from packaging.version import Version
910
import sphinx
11+
from sphinx.config import Config as _SphinxConfig
1012
from sphinx.util.docutils import SphinxDirective
1113
from sphinx_needs.api import add_need # type: ignore[import-untyped]
1214
from sphinx_needs.utils import add_doc # type: ignore[import-untyped]
@@ -33,6 +35,42 @@
3335
logger = logging.getLogger(__name__)
3436

3537

38+
def _check_id(
39+
config: _SphinxConfig,
40+
id: str | None,
41+
src_strings: list[str],
42+
options: dict[str, str],
43+
additional_options: dict[str, str],
44+
) -> None:
45+
"""Check and set the id for the need.
46+
47+
src_strings[0] is always the title.
48+
src_strings[1] is always the project.
49+
"""
50+
if config.needs_id_required:
51+
if id:
52+
additional_options["id"] = id
53+
else:
54+
if "directory" in options:
55+
src_strings.append(options["directory"])
56+
if "file" in options:
57+
src_strings.append(options["file"])
58+
59+
additional_options["id"] = _make_hashed_id("SRCTRACE_", src_strings, config)
60+
61+
62+
def _make_hashed_id(
63+
type_prefix: str, src_strings: list[str], config: _SphinxConfig
64+
) -> str:
65+
"""Create an ID based on the type and title of the need."""
66+
full_title = src_strings[0] # title is always the first element
67+
hashable_content = "_".join(src_strings)
68+
hashed = hashlib.sha256(hashable_content.encode("UTF-8")).hexdigest().upper()
69+
if config.needs_id_from_title:
70+
hashed = full_title.upper().replace(" ", "_") + "_" + hashed
71+
return f"{type_prefix}{hashed[: config.needs_id_length]}"
72+
73+
3674
def get_rel_path(doc_path: Path, code_path: Path, base_dir: Path) -> tuple[Path, Path]:
3775
"""Get the relative path from the document to the source code file and vice versa."""
3876
doc_depth = len(doc_path.parents) - 1
@@ -93,6 +131,7 @@ def run(self) -> list[nodes.Node]:
93131
validate_option(self.options)
94132

95133
project = self.options["project"]
134+
id = self.options.get("id")
96135
title = self.arguments[0]
97136
# get source tracing config
98137
src_trace_sphinx_config = CodeLinksConfig.from_sphinx(self.env.config)
@@ -108,7 +147,12 @@ def run(self) -> list[nodes.Node]:
108147
# the directory where the source files are copied to
109148
target_dir = out_dir / src_dir.name
110149

111-
extra_options = {"project": project}
150+
additional_options = {"project": project}
151+
152+
_check_id(
153+
self.env.config, id, [title, project], self.options, additional_options
154+
)
155+
112156
source_files = self.get_src_files(self.options, src_dir, src_discover_config)
113157

114158
# add source files into the dependency
@@ -132,7 +176,7 @@ def run(self) -> list[nodes.Node]:
132176
lineno=self.lineno, # The line number where the directive is used
133177
need_type="srctrace", # The type of the need
134178
title=title, # The title of the need
135-
**extra_options,
179+
**additional_options,
136180
)
137181
needs.extend(src_trace_need)
138182

@@ -200,7 +244,7 @@ def run(self) -> list[nodes.Node]:
200244

201245
def get_src_files(
202246
self,
203-
extra_options: dict[str, str],
247+
additional_options: dict[str, str],
204248
src_dir: Path,
205249
src_discover_config: SourceDiscoverConfig,
206250
) -> list[Path]:
@@ -210,14 +254,14 @@ def get_src_files(
210254
file: str = self.options["file"]
211255
filepath = src_dir / file
212256
source_files.append(filepath.resolve())
213-
extra_options["file"] = file
257+
additional_options["file"] = file
214258
else:
215259
directory = self.options.get("directory")
216260
if directory is None:
217261
# when neither "file" and "directory" are given, the project root dir is by default
218262
directory = "./"
219263
else:
220-
extra_options["directory"] = directory
264+
additional_options["directory"] = directory
221265
dir_path = src_dir / directory
222266
# create a new config for the specified directory
223267
src_discover = SourceDiscoverConfig(

β€Žsrc/sphinx_codelinks/sphinx_extension/source_tracing.pyβ€Ž

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,34 @@
3535
logger = logging.getLogger(__name__)
3636

3737

38+
def _check_sphinx_needs_dependency(app: Sphinx) -> bool:
39+
"""Check if sphinx-needs is actually loaded as an extension."""
40+
# Check if sphinx-needs is in the loaded extensions
41+
if "sphinx_needs" not in app.extensions:
42+
error_msg = (
43+
"sphinx-codelinks requires sphinx-needs to be loaded as an extension.\n"
44+
"Please ensure 'sphinx_needs' is properly installed and added to your extensions list in conf.py:\n"
45+
" extensions = ['sphinx_needs', 'sphinx_codelinks', ...]\n"
46+
f"Currently loaded extensions: {list(app.extensions.keys())}\n"
47+
f"Configured extensions: {app.config.extensions}"
48+
)
49+
logger.error(error_msg)
50+
return False
51+
return True
52+
53+
3854
def setup(app: Sphinx) -> dict[str, Any]: # type: ignore[explicit-any]
55+
# Check if sphinx-needs is available and properly configured
56+
if not _check_sphinx_needs_dependency(app):
57+
logger.error(
58+
"Failed to initialize sphinx-codelinks due to missing sphinx-needs dependency"
59+
)
60+
return {
61+
"version": "builtin",
62+
"parallel_read_safe": True,
63+
"parallel_write_safe": True,
64+
}
65+
3966
app.add_node(SourceTracing)
4067
app.add_directive("src-trace", SourceTracingDirective)
4168
CodeLinksConfig.add_config_values(app)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<document source="<source>">
2+
<target anonymous="" ids="SRCTRACE_F70E0" refid="SRCTRACE_F70E0">
3+
<Need classes="need need-srctrace" ids="SRCTRACE_F70E0" refid="SRCTRACE_F70E0">
4+
<target anonymous="" ids="IMPL_1" refid="IMPL_1">
5+
<Need classes="need need-impl" ids="IMPL_1" refid="IMPL_1">
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Configuration file for the Sphinx documentation builder.
2+
#
3+
# For the full list of built-in configuration values, see the documentation:
4+
# https://www.sphinx-doc.org/en/master/usage/configuration.html
5+
6+
# -- Project information -----------------------------------------------------
7+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
8+
9+
project = "source-tracing-demo"
10+
copyright = "2025, useblocks"
11+
author = "useblocks"
12+
13+
# -- General configuration ---------------------------------------------------
14+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
15+
16+
extensions = ["sphinx_needs", "sphinx_codelinks"]
17+
18+
templates_path = ["_templates"]
19+
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
20+
21+
src_trace_config_from_toml = "src_trace.toml"
22+
23+
# -- Options for HTML output -------------------------------------------------
24+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
25+
26+
html_theme = "alabaster"
27+
html_static_path = ["_static"]
28+
29+
# Sphinx-Needs configuration
30+
needs_id_required = True
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#include <iostream>
2+
3+
// @ title here, IMPL_1, impl
4+
void singleLineExample()
5+
{
6+
std::cout << "Single-line comment example" << std::endl;
7+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.. src-trace:: dummy src
2+
:project: src
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[codelinks.projects.src]
2+
remote_url_pattern = "https://github.com/useblocks/sphinx-codelinks/blob/{commit}/{path}#L{line}"

0 commit comments

Comments
Β (0)