Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,8 @@
html_context = {"repository": "useblocks/sphinx-codelinks"}
html_css_files = ["furo.css"]

# Sphinx-Needs configuration
needs_from_toml = "ubproject.toml"

# Src-trace configuration
src_trace_config_from_toml = "./src_trace.toml"
4 changes: 4 additions & 0 deletions docs/source/components/directive.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,14 @@ The ``src-trace`` directive can be used with the **file** option:
.. code-block:: rst

.. src-trace:: dcdc demo_1
:id: SRC_001
:project: dcdc
:file: ./charge/demo_1.cpp

The needs defined in source code are extracted and rendered to:

.. src-trace:: dcdc demo_1
:id: SRC_001
:project: dcdc
:file: ./charge/demo_1.cpp

Expand All @@ -66,12 +68,14 @@ The ``src-trace`` directive can be used with the **directory** option:
.. code-block:: rst

.. src-trace:: dcdc charge
:id: SRC_001
:project: dcdc
:directory: ./discharge

The needs defined in source code are extracted and rendered to:

.. src-trace:: dcdc charge
:id: SRC_002
:project: dcdc
:directory: ./discharge

Expand Down
5 changes: 0 additions & 5 deletions docs/ubproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,3 @@ ignore = ["block.title_line"]

[needs]
id_required = true

[[needs.types]]
directive = "my-req"
title = "My Requirement"
prefix = "M_"
42 changes: 42 additions & 0 deletions src/sphinx_codelinks/sphinx_extension/directives/src_trace.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from collections.abc import Callable
import hashlib
import os
from pathlib import Path
from typing import Any, ClassVar, cast
Expand All @@ -7,6 +8,7 @@
from docutils.parsers.rst import directives
from packaging.version import Version
import sphinx
from sphinx.config import Config as _SphinxConfig
from sphinx.util.docutils import SphinxDirective
from sphinx_needs.api import add_need # type: ignore[import-untyped]
from sphinx_needs.utils import add_doc # type: ignore[import-untyped]
Expand All @@ -33,6 +35,42 @@
logger = logging.getLogger(__name__)


def _check_id(
config: _SphinxConfig,
id: str | None,
src_strings: list[str],
options: dict[str, str],
extra_options: dict[str, str],
) -> None:
"""Check and set the id for the need.

src_strings[0] is always the title.
src_strings[1] is always the project.
"""
if config.needs_id_required:
Comment thread
juiwenchen marked this conversation as resolved.
if id:
extra_options["id"] = id
else:
if "directory" in options:
src_strings.append(options["directory"])
if "file" in options:
src_strings.append(options["file"])

extra_options["id"] = _make_hashed_id("SRCTRACE_", src_strings, config)


def _make_hashed_id(
type_prefix: str, src_strings: list[str], config: _SphinxConfig
) -> str:
"""Create an ID based on the type and title of the need."""
full_title = src_strings[0] # title is always the first element
hashable_content = "_".join(src_strings)
hashed = hashlib.sha256(hashable_content.encode("UTF-8")).hexdigest().upper()
if config.needs_id_from_title:
hashed = full_title.upper().replace(" ", "_") + "_" + hashed
return f"{type_prefix}{hashed[: config.needs_id_length]}"


def get_rel_path(doc_path: Path, code_path: Path, base_dir: Path) -> tuple[Path, Path]:
"""Get the relative path from the document to the source code file and vice versa."""
doc_depth = len(doc_path.parents) - 1
Expand Down Expand Up @@ -93,6 +131,7 @@ def run(self) -> list[nodes.Node]:
validate_option(self.options)

project = self.options["project"]
id = self.options.get("id")
title = self.arguments[0]
# get source tracing config
src_trace_sphinx_config = CodeLinksConfig.from_sphinx(self.env.config)
Expand All @@ -109,6 +148,9 @@ def run(self) -> list[nodes.Node]:
target_dir = out_dir / src_dir.name

extra_options = {"project": project}
Comment thread
juiwenchen marked this conversation as resolved.
Outdated

_check_id(self.env.config, id, [title, project], self.options, extra_options)

source_files = self.get_src_files(self.options, src_dir, src_discover_config)

# add source files into the dependency
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<document source="<source>">
<target anonymous="" ids="SRCTRACE_F70E0" refid="SRCTRACE_F70E0">
<Need classes="need need-srctrace" ids="SRCTRACE_F70E0" refid="SRCTRACE_F70E0">
<target anonymous="" ids="IMPL_1" refid="IMPL_1">
<Need classes="need need-impl" ids="IMPL_1" refid="IMPL_1">
30 changes: 30 additions & 0 deletions tests/doc_test/id_required/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html

# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information

project = "source-tracing-demo"
copyright = "2025, useblocks"
author = "useblocks"

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration

extensions = ["sphinx_needs", "sphinx_codelinks"]

templates_path = ["_templates"]
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]

src_trace_config_from_toml = "src_trace.toml"

# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output

html_theme = "alabaster"
html_static_path = ["_static"]

# Sphinx-Needs configuration
needs_id_required = True
7 changes: 7 additions & 0 deletions tests/doc_test/id_required/dummy_src.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include <iostream>

// @ title here, IMPL_1, impl
void singleLineExample()
{
std::cout << "Single-line comment example" << std::endl;
}
2 changes: 2 additions & 0 deletions tests/doc_test/id_required/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.. src-trace:: dummy src
:project: src
2 changes: 2 additions & 0 deletions tests/doc_test/id_required/src_trace.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[codelinks.projects.src]
remote_url_pattern = "https://github.com/useblocks/sphinx-codelinks/blob/{commit}/{path}#L{line}"
4 changes: 4 additions & 0 deletions tests/test_src_trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,10 @@ def test_src_tracing_config_positive(make_app: Callable[..., SphinxTestApp], tmp
Path("doc_test") / "minimum_config",
Path("doc_test") / "minimum_config",
),
(
Path("doc_test") / "id_required",
Path("doc_test") / "id_required",
),
],
)
def test_build_html(
Expand Down
Loading