From 4fd696ffa51aa4dba02514c720cfceb078657126 Mon Sep 17 00:00:00 2001 From: SPeak Date: Sun, 10 May 2026 04:10:33 +0800 Subject: [PATCH 1/8] ci: switch to mcpp build (.xlings.json pins mcpp 0.0.3) (#2) Replaces the existing CI with a single mcpp-driven Linux job: - `.xlings.json` declares `mcpp = { linux = "0.0.3" }`. - `.github/workflows/ci.yml` boots xlings, runs `xlings install -y`, then `mcpp build` + `mcpp test` against the existing mcpp.toml. --- .github/workflows/ci.yml | 108 ++++++--------------------------------- .xlings.json | 5 ++ 2 files changed, 20 insertions(+), 93 deletions(-) create mode 100644 .xlings.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ec99aa1..f5a9833 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,110 +2,32 @@ name: CI on: push: - branches: [main, master] + branches: [main] pull_request: - branches: [main, master] - -concurrency: - group: ci-${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true jobs: - build-linux: + build: name: build + test (linux x86_64, mcpp) - runs-on: ubuntu-24.04 - timeout-minutes: 30 - env: - MCPP_HOME: /home/runner/.mcpp + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - # mcpp's sandbox (musl-gcc + ninja + binutils) is multi-hundred-MB; - # key on mcpp.toml so toolchain changes refresh the cache. - - name: Cache mcpp sandbox - uses: actions/cache@v4 - with: - path: ~/.mcpp - key: mcpp-sandbox-${{ runner.os }}-${{ hashFiles('mcpp.toml') }} - restore-keys: | - mcpp-sandbox-${{ runner.os }}- - - - name: Cache xlings - uses: actions/cache@v4 - with: - path: ~/.xlings - key: xlings-${{ runner.os }} - restore-keys: | - xlings-${{ runner.os }}- - - - name: Bootstrap mcpp via xlings + - name: Install xlings env: - XLINGS_NON_INTERACTIVE: '1' + XLINGS_VERSION: 0.4.25 run: | - if [ ! -x "$HOME/.xlings/subos/default/bin/xlings" ]; then - curl -fsSL https://d2learn.org/xlings-install.sh | bash - fi - export PATH="$HOME/.xlings/subos/default/bin:$PATH" - xlings --version - xlings install mcpp -y - mcpp --version - echo "$HOME/.xlings/subos/default/bin" >> "$GITHUB_PATH" + tarball="xlings-${XLINGS_VERSION}-linux-x86_64.tar.gz" + curl -fsSL -o "/tmp/${tarball}" \ + "https://github.com/d2learn/xlings/releases/download/v${XLINGS_VERSION}/${tarball}" + tar -xzf "/tmp/${tarball}" -C /tmp + "/tmp/xlings-${XLINGS_VERSION}-linux-x86_64/subos/default/bin/xlings" self install + echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH" - - name: Cache target/ (build artifacts + BMIs) - uses: actions/cache@v4 - with: - path: target - key: mcpp-target-${{ runner.os }}-${{ hashFiles('src/**', 'tests/**', 'mcpp.toml') }} - restore-keys: | - mcpp-target-${{ runner.os }}- + - name: Install workspace tools (.xlings.json → mcpp 0.0.3) + run: xlings install -y - - name: Build + - name: Build with mcpp run: mcpp build - - name: Test + - name: Run tests run: mcpp test - - # mcpp is Linux-x86_64 first; macOS/Windows support is still WIP, so the - # cross-platform xmake build keeps coverage for those targets. - build-macos: - name: build (macOS, xmake) - runs-on: macos-latest - steps: - - uses: actions/checkout@v4 - - - name: Setup xmake - uses: xmake-io/github-action-setup-xmake@v1 - with: - xmake-version: latest - package-cache: true - - - name: Install LLVM 20 - run: brew install llvm@20 - - - name: Build - run: | - xmake f --toolchain=llvm --sdk=/opt/homebrew/opt/llvm@20 - xmake -y -vv - - build-windows: - name: build + test (Windows, xmake) - runs-on: windows-latest - steps: - - uses: actions/checkout@v4 - - - name: Setup xmake - uses: xmake-io/github-action-setup-xmake@v1 - with: - xmake-version: latest - package-cache: true - - - name: Build - run: xmake -y -vv - - - name: Test - run: xmake run cmdline_test - - - name: Run examples (smoke) - run: | - xmake run with_dispatch -- add python 3.12 - xmake run with_dispatch -- remove foo diff --git a/.xlings.json b/.xlings.json new file mode 100644 index 0000000..f2be3fd --- /dev/null +++ b/.xlings.json @@ -0,0 +1,5 @@ +{ + "workspace": { + "mcpp": { "linux": "0.0.3" } + } +} From cca6df016fd194170f92dbf059f0fa2f10ec44b8 Mon Sep 17 00:00:00 2001 From: SPeak Date: Sun, 10 May 2026 06:26:54 +0800 Subject: [PATCH 2/8] =?UTF-8?q?ci:=20cache=20mcpp's=20self-bootstrapped=20?= =?UTF-8?q?sandbox=20(~800=20MB=20=E2=86=92=20instant)=20(#3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mcpp 0.0.3's binary lives at xim-x-mcpp/0.0.3/bin/mcpp; on first run it self-detects home as that grandparent and bootstraps musl-gcc + binutils + glibc + ninja + patchelf into /registry/data/xpkgs. Toolchain set is version-pinned by mcpp 0.0.3, so a fixed cache key is safe. Cache-hit runs skip the ~800 MB download. --- .github/workflows/ci.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f5a9833..e33f485 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,6 +26,15 @@ jobs: - name: Install workspace tools (.xlings.json → mcpp 0.0.3) run: xlings install -y + # Cache mcpp's self-bootstrapped sandbox (musl-gcc + binutils + + # glibc + ninja + patchelf, ~800 MB). Toolchain set is pinned by + # mcpp 0.0.3, so a fixed key suffices. + - name: Cache mcpp sandbox + uses: actions/cache@v4 + with: + path: ~/.xlings/data/xpkgs/xim-x-mcpp/0.0.3/registry + key: mcpp-sandbox-${{ runner.os }}-mcpp0.0.3 + - name: Build with mcpp run: mcpp build From 3313a394ad2b80be5aab6937d53aa7cbf26fa566 Mon Sep 17 00:00:00 2001 From: SPeak Date: Sun, 10 May 2026 06:32:48 +0800 Subject: [PATCH 3/8] =?UTF-8?q?ci:=20bump=20mcpp=200.0.3=20=E2=86=92=200.0?= =?UTF-8?q?.4=20(glob=20exclusion,=20sandbox=20PATH)=20(#4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 8 ++++---- .xlings.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e33f485..6616cbd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,17 +23,17 @@ jobs: "/tmp/xlings-${XLINGS_VERSION}-linux-x86_64/subos/default/bin/xlings" self install echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH" - - name: Install workspace tools (.xlings.json → mcpp 0.0.3) + - name: Install workspace tools (.xlings.json → mcpp 0.0.4) run: xlings install -y # Cache mcpp's self-bootstrapped sandbox (musl-gcc + binutils + # glibc + ninja + patchelf, ~800 MB). Toolchain set is pinned by - # mcpp 0.0.3, so a fixed key suffices. + # mcpp 0.0.4, so a fixed key suffices. - name: Cache mcpp sandbox uses: actions/cache@v4 with: - path: ~/.xlings/data/xpkgs/xim-x-mcpp/0.0.3/registry - key: mcpp-sandbox-${{ runner.os }}-mcpp0.0.3 + path: ~/.xlings/data/xpkgs/xim-x-mcpp/0.0.4/registry + key: mcpp-sandbox-${{ runner.os }}-mcpp0.0.4 - name: Build with mcpp run: mcpp build diff --git a/.xlings.json b/.xlings.json index f2be3fd..b3b1fb4 100644 --- a/.xlings.json +++ b/.xlings.json @@ -1,5 +1,5 @@ { "workspace": { - "mcpp": { "linux": "0.0.3" } + "mcpp": { "linux": "0.0.4" } } } From 649d659f97fdf8e0850acb91c0216e2e88e1e6d2 Mon Sep 17 00:00:00 2001 From: SPeak Date: Mon, 11 May 2026 19:23:55 +0800 Subject: [PATCH 4/8] chore: migrate deps to namespace syntax (mcpp 0.0.6) (#5) * chore: migrate deps to namespace syntax (mcpp 0.0.6) Updates mcpp.toml to use explicit namespace fields: - [package].namespace added - [package].name uses short name only - [dependencies.compat] / [dev-dependencies.compat] for non-modular libs - [dependencies.mcpplibs.capi] for C API wrappers * ci: retrigger with fixed mcpp 0.0.6 * ci: retrigger * ci: retrigger with mcpp 0.0.7 --- .github/workflows/ci.yml | 8 ++++---- .xlings.json | 2 +- mcpp.toml | 6 ++---- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6616cbd..d27b500 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,17 +23,17 @@ jobs: "/tmp/xlings-${XLINGS_VERSION}-linux-x86_64/subos/default/bin/xlings" self install echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH" - - name: Install workspace tools (.xlings.json → mcpp 0.0.4) + - name: Install workspace tools (.xlings.json → mcpp 0.0.7) run: xlings install -y # Cache mcpp's self-bootstrapped sandbox (musl-gcc + binutils + # glibc + ninja + patchelf, ~800 MB). Toolchain set is pinned by - # mcpp 0.0.4, so a fixed key suffices. + # mcpp 0.0.7, so a fixed key suffices. - name: Cache mcpp sandbox uses: actions/cache@v4 with: - path: ~/.xlings/data/xpkgs/xim-x-mcpp/0.0.4/registry - key: mcpp-sandbox-${{ runner.os }}-mcpp0.0.4 + path: ~/.xlings/data/xpkgs/xim-x-mcpp/0.0.7/registry + key: mcpp-sandbox-${{ runner.os }}-mcpp0.0.7 - name: Build with mcpp run: mcpp build diff --git a/.xlings.json b/.xlings.json index b3b1fb4..3f993c1 100644 --- a/.xlings.json +++ b/.xlings.json @@ -1,5 +1,5 @@ { "workspace": { - "mcpp": { "linux": "0.0.4" } + "mcpp": { "linux": "0.0.7" } } } diff --git a/mcpp.toml b/mcpp.toml index 9bcdb69..a69d0de 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -1,14 +1,12 @@ [package] -name = "mcpplibs.cmdline" +namespace = "mcpplibs" +name = "cmdline" version = "0.0.2" description = "A simple command-line parsing library/framework for modern C++" license = "Apache-2.0" authors = ["mcpplibs"] repo = "https://github.com/mcpplibs/cmdline" -# Library target — exposes module `mcpplibs.cmdline` to dependents. -# Sources default to src/**/*.{cppm,cpp,cc,c}; tests/ and examples/ are -# discovered separately (`mcpp test` / standalone builds). [targets.cmdline] kind = "lib" From 8eab0b324a3a8a377b214c10dabe68fc1c88b5d6 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Tue, 12 May 2026 05:30:45 +0800 Subject: [PATCH 5/8] fix: use [dev-dependencies.compat] for gtest gtest is a compat (non-modular) package in mcpp-index. Declare it under [dev-dependencies.compat] so mcpp resolves the correct namespace. Required for mcpp 0.0.10+ namespace-aware dependency pipeline. --- mcpp.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mcpp.toml b/mcpp.toml index a69d0de..5deeb5b 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -10,5 +10,5 @@ repo = "https://github.com/mcpplibs/cmdline" [targets.cmdline] kind = "lib" -[dev-dependencies] +[dev-dependencies.compat] gtest = "1.15.2" From 831c3a16e92aa8e9d5ab7a990ae60dd529f98870 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Tue, 12 May 2026 18:33:10 +0800 Subject: [PATCH 6/8] chore: bump mcpp to 0.0.11 + update README MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - .xlings.json: mcpp 0.0.7 → 0.0.11 - CI: xlings 0.4.25 → 0.4.30, mcpp 0.0.11 - README: expand mcpp build/usage instructions --- .github/workflows/ci.yml | 10 +++++----- .xlings.json | 2 +- README.md | 23 ++++++++++++++++++++--- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d27b500..f0ee911 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: - name: Install xlings env: - XLINGS_VERSION: 0.4.25 + XLINGS_VERSION: 0.4.30 run: | tarball="xlings-${XLINGS_VERSION}-linux-x86_64.tar.gz" curl -fsSL -o "/tmp/${tarball}" \ @@ -23,17 +23,17 @@ jobs: "/tmp/xlings-${XLINGS_VERSION}-linux-x86_64/subos/default/bin/xlings" self install echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH" - - name: Install workspace tools (.xlings.json → mcpp 0.0.7) + - name: Install workspace tools (.xlings.json → mcpp 0.0.11) run: xlings install -y # Cache mcpp's self-bootstrapped sandbox (musl-gcc + binutils + # glibc + ninja + patchelf, ~800 MB). Toolchain set is pinned by - # mcpp 0.0.7, so a fixed key suffices. + # mcpp 0.0.11, so a fixed key suffices. - name: Cache mcpp sandbox uses: actions/cache@v4 with: - path: ~/.xlings/data/xpkgs/xim-x-mcpp/0.0.7/registry - key: mcpp-sandbox-${{ runner.os }}-mcpp0.0.7 + path: ~/.xlings/data/xpkgs/xim-x-mcpp/0.0.11/registry + key: mcpp-sandbox-${{ runner.os }}-mcpp0.0.11 - name: Build with mcpp run: mcpp build diff --git a/.xlings.json b/.xlings.json index 3f993c1..e986e06 100644 --- a/.xlings.json +++ b/.xlings.json @@ -1,5 +1,5 @@ { "workspace": { - "mcpp": { "linux": "0.0.7" } + "mcpp": { "linux": "0.0.11" } } } diff --git a/README.md b/README.md index 1c765cf..cdef3ae 100644 --- a/README.md +++ b/README.md @@ -112,14 +112,31 @@ target("mytool") ### mcpp -在项目的 `mcpp.toml` 中声明依赖: +#### 添加依赖 + +```bash +mcpp add cmdline@0.0.2 +``` + +或在 `mcpp.toml` 中手动添加: ```toml [dependencies] -"mcpplibs.cmdline" = "^0.0.2" +cmdline = "0.0.2" +``` + +#### 构建 + +```bash +mcpp build ``` -然后在源码中 `import mcpplibs.cmdline;` 即可使用。 +#### 代码示例 + +```cpp +import mcpplibs.cmdline; +// ... 参见上方"快速开始" +``` ## 相关链接 From c0e7078c15f234a519fc1bc8ff90c6a67be1746b Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Tue, 12 May 2026 18:40:35 +0800 Subject: [PATCH 7/8] fix: revert to flat dependency form (xlings compat) --- mcpp.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mcpp.toml b/mcpp.toml index 5deeb5b..a69d0de 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -10,5 +10,5 @@ repo = "https://github.com/mcpplibs/cmdline" [targets.cmdline] kind = "lib" -[dev-dependencies.compat] +[dev-dependencies] gtest = "1.15.2" From d2288114322d5b648b3c7ed8d49d97948be28eac Mon Sep 17 00:00:00 2001 From: Johan Xie Date: Mon, 13 Jul 2026 20:25:57 +0800 Subject: [PATCH 8/8] feat: add shell completion generation (bash, fish, zsh) (#8) * feat: add shell completions skeleton * feat(completions): add fish support * docs: add shell completions example * build: re-support xmake * feat(completions): add bash support * feat(completions): add zsh support * docs: update api.md with shell completions * test(completions): add shell completion tests * fix(completions): fix linkage for gcc 15.1.0-musl Move SubCmdEntry and ScBranch from anonymous namespace to named `detail` namespace in bash and zsh completion partitions. GCC 15.1.0 enforces C++20 module linkage rules more strictly: types with internal linkage (anonymous namespace) cannot appear as template arguments to module-attached templates like std::vector. This exposes TU-local entities through template instantiation, causing "exposes TU-local entity" errors. ScBranch additionally required moving to namespace scope because local structs (no linkage) triggered an ICE when instantiating std::vector inside an external-linkage function in a module implementation. * chore: bump mcpp 0.0.11 to 0.0.89 --- .xlings.json | 2 +- docs/api.md | 73 +++++ examples/completions/.gitignore | 1 + examples/completions/mcpp.toml | 8 + examples/completions/src/main.cpp | 143 +++++++++ src/cmdline.cppm | 58 ++++ src/completions.cppm | 66 ++++ src/completions/bash.cppm | 405 ++++++++++++++++++++++++ src/completions/fish.cppm | 226 +++++++++++++ src/completions/zsh.cppm | 505 ++++++++++++++++++++++++++++++ tests/completions_test.cpp | 160 ++++++++++ tests/xmake.lua | 4 +- xmake.lua | 1 + 13 files changed, 1650 insertions(+), 2 deletions(-) create mode 100644 examples/completions/.gitignore create mode 100644 examples/completions/mcpp.toml create mode 100644 examples/completions/src/main.cpp create mode 100644 src/completions.cppm create mode 100644 src/completions/bash.cppm create mode 100644 src/completions/fish.cppm create mode 100644 src/completions/zsh.cppm create mode 100644 tests/completions_test.cpp diff --git a/.xlings.json b/.xlings.json index e986e06..86555db 100644 --- a/.xlings.json +++ b/.xlings.json @@ -1,5 +1,5 @@ { "workspace": { - "mcpp": { "linux": "0.0.11" } + "mcpp": "0.0.89" } } diff --git a/docs/api.md b/docs/api.md index 33b2433..3a2d1e1 100644 --- a/docs/api.md +++ b/docs/api.md @@ -11,6 +11,8 @@ | `OptionValue` | 单个选项取值(flag 计数 + values) | | `ParseError` | 解析错误(kind + message) | | `Argv` | `std::vector` 的别名,用于 `parse_from` | +| `Shell` | 目标 shell 枚举:`bash` / `fish` / `zsh` | +| `Command` | 命令树快照,用于生成补全脚本 | 解析返回 `ParseResult`,即 `std::expected`。`-h`/`--help`、`--version` 时,`ParseError::kind` 分别为 `help` / `version`,不携带 `message`,通过 `is_error()` 可区分真实错误。 @@ -40,6 +42,14 @@ --- +## Shell + +| 函数 | 说明 | +|------|------| +| `shell_from_string(sv)` | 字符串 → `std::optional`(如 `"fish"` → `Shell::fish`) | +| `to_string(shell)` | `Shell` → `std::string_view` | +| `shell_supported(shell)` | 该 shell 补全是否已实现(fish / bash / zsh) | + ## ParseError | 成员 | 说明 | @@ -168,3 +178,66 @@ app.option(cmdline::Option("yes").long_opt("yes").global().help("Auto confirm")) app.arg(cmdline::Arg("input").required().help("Input file")); app.subcommand(cmdline::App("add").description("Add").arg(cmdline::Arg("x").required()).action([](const cmdline::ParsedArgs&) {})); ``` + +--- + +## Shell 补全 + +### 生成流程 + +1. 从 `App` 构建 `completions::Command` 树(`snapshot(app)` 或自动由 `generate_completions` 调用) +2. `Command` 包含名称、描述、版本、`Arg`/`Option` 列表、子命令列表 +3. 选择目标 `Shell` 后调用 `generate_completions`,输出补全脚本文本 + +### completions::Command + +| 成员 | 说明 | +|------|------| +| `name` | 命令名 | +| `description` | 描述文本 | +| `version` | 版本号 | +| `args` / `options` / `subcommands` | `vector` / `vector