FantastyQAQ/dsh-doxygen

dsh-doxygen

为 C/C++(含 Qt)源码生成与维护 Doxygen 注释的工作流:文件头、函数、模块分组、行尾与简短注释,并扫描出签名指纹已过期、需要更新的注释。运行时需要 Python 3.10+ 并 `pip install tree-sitter tree-sitter-cpp`。

未分類cppdocumentationdoxygen

doxygen-comment

English | 中文说明

An agent skill for generating and maintaining Doxygen comments in C/C++ (including Qt) sources. It is not a snippet collection but a pipeline an AI coding assistant can drive end to end: read the function signature → generate or complete the comment → mark the comment stale when the code changes.

Features

  • Locate a function by line number or by name. parse_function.py parses C/C++ signatures with

tree-sitter and prints JSON (function name, return type, parameters and their direction, start line, signature fingerprint, optional body snippet). Read-only, no side effects.

  • Six templates. File header / function / module head / module tail / trailing /**< */ / short

@brief, matching the editor snippet prefixes doxygen_source, doxygen_fun, doxygen_module_head, doxygen_module_end, doxygen_rear, doxygen_nom.

  • Fill in, never rewrite. When a Doxygen block already exists above a function, only the missing

fields are added and the fingerprint is refreshed; existing wording and line order are kept. A file that already carries an @file block is skipped.

  • Signature fingerprint. Every function block ends with @doxygen_sig_fp ; --scan

compares the current signature against it and marks "signature changed, comment outdated" functions as stale, which is what makes repository-wide upkeep possible. Pure formatting changes (whitespace, */& placement) do not change the fingerprint.

  • Nothing is written by default. A diff is printed first; --write applies it while preserving the

target file's CRLF/LF style and its UTF-8 / UTF-8-BOM / GBK encoding.

  • Fails fast on a machine without Python. The plugin probes Python 3.10+ and tree-sitter at

registration and puts the verdict at the top of the skill body; on a missing or broken interpreter the skill instructs the agent to stop and hand over the install steps instead of letting a shell error turn into a fake "function not found". node scripts/check_env.mjs runs the same probe on demand — it is plain Node, so it works where Python does not.

  • CJK-text friendly. The scripts force UTF-8 output, avoiding the mojibake a GBK Windows console

would otherwise cause.

Repository layout

doxygen-comment/
├── SKILL.md                  # skill body: workflow, script contract, template list
├── README.md                 # this file
├── LICENSE                   # MIT
├── requirements.txt          # Python dependencies
├── package.json              # DSH plugin manifest — declares dsh.bundle
├── cordis.patch.yml          # plugin insert row (id: doxygen-comment, name: dsh-doxygen)
├── index.js                  # registers the bundled skill when installed as a plugin
├── assets/
│   └── cpp.json              # the six templates as editor snippets (optional)
├── references/
│   └── examples.md           # before/after examples, Qt cases, common mistakes
└── scripts/
    ├── parse_function.py     # read: locate a function + parse its signature (no side effects)
    ├── gen_doxygen.py        # write: render / insert / complete / fingerprint / diff / scan
    ├── install_snippets.py   # optional: merge the snippets into a VS Code style IDE
    ├── check_env.mjs         # environment preflight (Node, works without Python)
    └── lib/
        └── env.mjs           # the probe behind check_env.mjs; also used by index.js

Installation

1. Get the source

git clone https://github.com/FantastyQAQ/dsh-doxygen.git

The repository is named dsh-doxygen while the skill is named doxygen-comment: when you drop it into a skills directory, name the directory `doxygen-comment`.

2. Install it

Two ways in — as a DSH plugin bundle, or by copying the folder into a skills directory.

As a DSH plugin. The repository root declares dsh.bundle, so it installs like any other plugin:

dsh plugin --profile desktop add github:FantastyQAQ/dsh-doxygen

desktop is the profile the desktop app uses — swap in your own profile name (desktop+office, etc.). The --profile flag is required by current hosts (0.2.1 and newer); dsh plugin add ... alone fails with required option '--profile ' not specified.

index.js registers SKILL.md as the doxygen-comment skill and resolves ${SKILL_DIR} for you, so no path guessing is needed.

By copying the folder. The directory is self-contained; the scripts contain no project-specific paths:

Host · Skills directory DeepSeek Harness · ~/.dsh/skills/doxygen-comment/ Claude Code · ~/.claude/skills/doxygen-comment/, or a project's .claude/skills/ CodeBuddy CN / WorkBuddy · ~/.codebuddy/skills/doxygen-comment/, ~/.workbuddy/skills/doxygen-comment/

# e.g. install for Claude Code at user level
git clone https://github.com/FantastyQAQ/dsh-doxygen.git "$env:USERPROFILE\.claude\skills\doxygen-comment"

3. Dependencies

Requires Python 3.10+; install the C/C++ parser with pip install tree-sitter tree-sitter-cpp:

pip install tree-sitter tree-sitter-cpp
# or the version-constrained install from this repo:
pip install -r requirements.txt

Tested with tree-sitter 0.26.0 + tree-sitter-cpp 0.23.4; the scripts support the Language/Parser construction API both before and after 0.22. On Windows, always type python (python3 is an alias trap in some environments).

When Python is missing, the plugin says so instead of failing mid-command. The bundle probes the machine once when it registers the skill and puts the verdict at the top of the skill body; a failing verdict tells the agent to stop and hand the install steps to you. The probe is plain Node (Node ships with DSH), so it can report "no Python" on the very machines where no Python exists:

node scripts/check_env.mjs           # human readable, exit 0/2/3
node scripts/check_env.mjs --json    # machine readable

Exit codes: 0 usable, 2 no Python at all, 3 Python found but unusable (too old, modules missing, interpreter broken). If Python is installed but not on PATH (venv, conda, portable build), set DOXYGEN_PYTHON to the interpreter's absolute path and restart the session.

4. Verify

node scripts/check_env.mjs                      # environment: Python + tree-sitter
python scripts/parse_function.py --file demo.cpp --list

If the first prints ✅ and the second prints an array of functions, the installation works.

Quick start

The commands below are run from the skill root; replace : with your source path.

1) Locate a function and parse its signature

python scripts/parse_function.py --file src/rtc.cpp --line 42 --body-lines 30
python scripts/parse_function.py --file src/rtc.cpp --name RTC_Init
python scripts/parse_function.py --file src/rtc.cpp --list      # list all (no body_snippet)

The output is UTF-8 JSON:

{
  "name": "RTC_Init",
  "return_type": "int32_t",
  "params": [
    {"type": "const RTC_Config_t*", "name": "config", "direction": "in"},
    {"type": "uint32_t*", "name": "status", "direction": "out"}
  ],
  "start_line": 42,
  "end_line": 68,
  "is_definition": true,
  "signature": "int32_t RTC_Init(const RTC_Config_t* config, uint32_t* status)",
  "fingerprint": "ac50cb812857de87",
  "file": "…/rtc.cpp"
}

direction is decided by the script using the parameter-direction rules (the "参数方向判断规则" section of SKILL.md); take it as given.

2) Generate a function comment

Hand the signature plus the body snippet from the previous step to the model and let it produce the description JSON:

{
  "brief": "初始化 RTC 外设",
  "params": [
    {"name": "config", "desc": "RTC 配置参数"},
    {"name": "status", "desc": "初始化状态码,非 0 表示失败"}
  ],
  "return_desc": "0 成功,非 0 为错误码",
  "retval": "none",
  "details": "调用前需保证 32.768kHz 晶振已起振。"
}

Then render, preview and apply:

python scripts/gen_doxygen.py --file src/rtc.cpp --line 42 --kind fun --doc doc.json --diff
python scripts/gen_doxygen.py --file src/rtc.cpp --line 42 --kind fun --doc doc.json --write

Without --diff/--write it prints JSON (with status, notes, changed, diff fields).

3) Other template kinds

# file header (inserted at the first line of the file)
python scripts/gen_doxygen.py --file src/rtc.cpp --kind source \
  --brief "RTC 驱动" --note "依赖 32.768kHz 晶振" --log-desc "创建" --diff

# module group head / tail (used as a pair)
python scripts/gen_doxygen.py --file src/rtc.cpp --kind module --line 30 \
  --group rtc_api --title "RTC API" --brief "RTC 对外接口" --desc "全部函数可重入" --diff
python scripts/gen_doxygen.py --file src/rtc.cpp --kind module-end --line 120 --diff

# trailing comment / short comment (no signature parsing needed)
python scripts/gen_doxygen.py --file src/rtc.h --kind rear --line 18 --text "已发送帧数" --diff
python scripts/gen_doxygen.py --file src/rtc.h --kind nom  --line 25 --brief "RTC 状态枚举" --diff

4) Repository-wide scan (read-only)

python scripts/gen_doxygen.py --scan src

It returns {"summary": {...}, "items": [...]} where every function carries a status:

scan status · meaning · what to do missing · no Doxygen block above it · add one with the function-comment flow stale · block exists but the fingerprint no longer matches (the code changed) · review the description, then refresh partial · block exists but fields are missing (e.g. no @param) · fill in only what is missing ok · complete and fingerprint matches · leave it alone

The scan skips .git, build, libs, node_modules and similar directories. Do not rewrite hundreds of files in one go: group by status and let the user pick the scope first.

Commands and exit codes

Script · Purpose parse_function.py --file --line/--name/--list [--body-lines N] · parse a signature gen_doxygen.py --file … --kind · generate one comment gen_doxygen.py --scan · scan comment status across a tree

Both scripts share the same exit codes:

Code · Meaning 0 · Success (including status=ok/skipped, i.e. "nothing to change") 1 · Target function not found / not enough arguments 2 · Argument or file error (missing path, invalid JSON) 3 · The tree-sitter dependency is missing

On failure the reason is written to stderr, and stdout never carries a half-written JSON document.

Authors and copyright

The author and copyright in file headers have no universal default: when nothing is specified the script writes the placeholders ` and Copyright (c) by , All Rights Reserved.` for the user to replace. There are two ways to specify them:

python scripts/gen_doxygen.py --file a.cpp --kind source --brief "…" \
  --author "Your Name (you@example.com)" --copyright "Copyright (c) 2026 by Your Company, All Rights Reserved."
# set once, then every later command reuses it
export DOXYGEN_AUTHOR="Your Name (you@example.com)"
export DOXYGEN_COPYRIGHT="Copyright (c) {year} by Your Company, All Rights Reserved."   # {year} becomes the current year

Optional: install the templates into your IDE

assets/cpp.json is exactly the six templates as editor snippets. Type doxygen_fun and press Tab to expand it:

python scripts/install_snippets.py                       # dry run: detect IDEs, show what would be merged (writes nothing)
python scripts/install_snippets.py --apply --create       # actually write
python scripts/install_snippets.py --uninstall --apply    # remove the snippets this skill installed
  • The target file is \snippets\cpp.json; it is merged, never overwritten, and the

previous file is backed up as cpp.json.bak-.

  • Snippets are scoped per language: cpp.json only applies to .cpp/.cc/.cxx; to use them in .c/.h

you must merge them into c.json in the same directory.

  • Only that one snippet file is touched; settings.json is left alone.
  • CodeBuddy CN, VS Code, CodeBuddy, Cursor and Windsurf can be detected automatically; --target