# This file is part of OpenCV project. # It is subject to the license terms in the LICENSE file found in the top-level directory # of this distribution and at http://opencv.org/license.html. # Copyright (C) 2026, BigVision LLC, all rights reserved. # Third party copyrights are property of their respective owners. """Doxygen-flavored .markdown -> MyST translation (the source-read engine).""" from __future__ import annotations import pathlib, re, os as _os, shutil as _shutil, textwrap as _textwrap from .state import * def _normalize_lang(lang: str) -> str: lang = (lang or "").strip(".").strip().lower() or "text" return _LANG_ALIASES.get(lang, lang) # Snippet-boundary marker lines (e.g. `// [name]`, `## [name]`), stripped # from rendered code to mirror docs.opencv.org. Matches only a bare # marker + `[name]` on its own line, so real code embedding a `[token]` # is left alone. _SNIPPET_MARKER_RE = re.compile( r"^[ \t]*(?://!|//|##|#)[ \t]*\[[\w\- ]+\][ \t]*$" r"|^[ \t]*[ \t]*$" ) # Doxygen block comments (`/** … */`, `/*! … */`) are decorative chrome in # OpenCV samples; strip them to mirror docs.opencv.org. Plain `/* … */`, # `//`, and `///` comments are kept as visible commentary. # Line-block pass first removes whole-line blocks (consuming the trailing # newline so no hollow blank remains); inline pass then sweeps the rare # mid-line block without eating surrounding code. _DOXY_LINE_BLOCK_RE = re.compile( r"^[ \t]*/\*[*!].*?\*/[ \t]*\n?", re.DOTALL | re.MULTILINE, ) _DOXY_INLINE_BLOCK_RE = re.compile( r"/\*[*!].*?\*/", re.DOTALL, ) def _strip_snippet_markers(text: str) -> str: """Drop snippet-boundary marker lines from a code body (whole line removed, no hollow blank left). Runs of 3+ resulting blank lines are collapsed to 2, matching docs.opencv.org's rendering.""" out = [ln for ln in text.split("\n") if not _SNIPPET_MARKER_RE.match(ln)] joined = "\n".join(out) return re.sub(r"\n{3,}", "\n\n", joined) def _strip_doxygen_block_comments(text: str) -> str: """Drop every `/** … */` / `/*! … */` Doxygen block comment anywhere in a snippet (with or without `@tag` directives). Plain `/* … */`, `//`, and `///` comments stay intact.""" text = _DOXY_LINE_BLOCK_RE.sub("", text) text = _DOXY_INLINE_BLOCK_RE.sub("", text) return text def _read_snippet(rel_path: str, label: str | None) -> tuple[str, str]: """Return (code_text, language) for an @include / @snippet directive.""" rel_norm = rel_path.lstrip("/") p = next((b / rel_norm for b in _SNIPPET_BASES if (b / rel_norm).is_file()), None) # Doxygen EXAMPLE_RECURSIVE basename lookup. if p is None: hit = _SNIPPET_INDEX.get(pathlib.Path(rel_norm).name) if hit and hit.is_file(): p = hit if p is None: return f"// not found: {rel_path}\n", "text" text = p.read_text(encoding="utf-8", errors="replace") ext = p.suffix.lower() lang = {".cpp": "cpp", ".hpp": "cpp", ".h": "cpp", ".c": "c", ".py": "python", ".java": "java", ".xml": "xml", ".html": "html", ".sh": "bash", ".bash": "bash"}.get(ext, "text") if label is None: # `@include`: whole file. Strip Doxygen block comments and snippet # markers so the rendered block matches docs.opencv.org (starts at # the first `#include`/`import`, no banners or doc-headers). return _strip_snippet_markers( _strip_doxygen_block_comments(text)), lang # Match `[label]` after any comment marker. pat = re.compile(r"^[^\[\n]*(?://!|//|##|#|" raw = p.read_text(encoding="utf-8", errors="replace") # Allow quoted attrs so a `=>` inside onload="..." doesn't end the tag. body = re.search( r"\"']|\"[^\"]*\"|'[^']*')*>(.*?)", raw, re.DOTALL | re.IGNORECASE) inner = body.group(1).strip() if body else raw return f"\n```{{raw}} html\n{inner}\n```\n" text = re.sub(r"^@htmlinclude\s+(?P\S+)\s*$", _htmlinclude_repl, text, flags=re.MULTILINE) # 5. @snippet path [Label] def _snippet_repl(m: re.Match) -> str: code, lang = _read_snippet(m.group("path"), m.group("label")) return _emit_codeblock(m.group("indent") or "", lang, code) text = re.sub( r"^(?P[ \t]*)@snippet\s+(?P\S+)\s+(?P