Repository navigation
design: mcpp.toml 补全重做方案 —— 语义模块 + index 动态数据(#4 重做) #8
Description
Activity
- addeddocumentationImprovements or additions to documentationImprovements or additions to documentationenhancementNew feature or requestNew feature or request
on Aug 8, 2026 @Ximiaw
mcpp xpkg parse --json接口可以做支持, 但实现侧感觉可以不高频调用而是做数据缓存@Ximiaw 接口可以做支持, 但实现侧感觉可以不高频调用而是做数据缓存
mcpp xpkg parse --json
@Sunrisepeak 感谢支持!调用节奏正是缓存式的,之前「高频调用」的表述不准确,已修正:- 补全过程只读本地缓存,零 spawn;
xpkg parse仅在索引 git HEAD 变化后后台批量执行一次(缓存键 = HEAD/FETCH_HEAD);- 典型触发是
mcpp index update,或mcpp add本地未命中的新包(读了 cmd_add 源码,
仅本地索引查不到且归共享 registry 时才刷新)——日常可能几天都不到一次。
只读性本机实测(2026.7.27.1)无写副作用,希望作为接口契约固定下来即可。
结合 mcpp-community/mcpp#379 的最新拆分决定和当前源码重新复核,结论是:方案适合拆成“结构补全先落地、动态索引继续等待”,不适合按现稿一次性实现。
可以先实施的部分
以下部分不依赖上游新协议,范围也可验证:
- 段头结构建议;
- 依赖/feature 写法 snippets;
- 光标上下文与显式 replacement range;
- provider 映射、引号闭合、部分输入和真实 mcpp parser 契约测试;
- 数据源失败时静默降级为纯结构建议;
- 未受信任工作区不启动外部进程。
不过不建议为了这部分实现一个接近完整 TOML 的自制 parser。当前目标只需要回答“光标所在段、键位/值位、局部字符串或内联表位置和替换范围”,用带字符串/注释/括号状态的容错 context scanner 更容易审计,也更容易用残缺输入 fixture 覆盖。完整 parser 会扩大实现和维护面,却仍不能成为 mcpp manifest 的权威语义来源。
动态包名/版本补全仍有阻塞
1. Form A 仍不输出 versions
当前
cmd_xpkg_parse已经在进入 Form A 分支前计算了 linux/macosx/windows versions,但--json的 Form A 输出仍只有:{"namespace":"...","name":"...","form":"A"}最新 mcpp-index
upstream/main静态统计有 81 个pkgs/**/*.lua描述符,其中 63 个内联mcpp = {},其余 18 个进入非 TableBody/Form A 路径。它们不能提供版本候选,因此“官方解析器零漂移”目前并不成立于完整索引。2. 缓存不能消除首次 N 进程成本
补全过程读缓存是正确的,但第一次构建缓存、索引 revision 变化或缓存失效时,现稿仍需对约 81 个描述符分别启动 mcpp。缓存降低调用频率,不解决一次刷新时的进程数量、部分失败聚合和扩展激活后台负载。
在批量 catalog API 出现前,不建议把动态数据层默认开启。更合适的上游接口仍是一次返回 canonical identity、三平台 versions、index revision 和逐项 diagnostics 的批量 catalog。
3. Git HEAD/FETCH_HEAD 不是默认索引的权威身份
mcpp/xlings 对安装索引使用:
.xlings-index-version:内容 revision,opaque,只比较相等性;.mcpp-index-updated:最近刷新时间。
默认索引通常是 artifact materialization,不保证存在
.git。因此不能把 HEAD/FETCH_HEAD 作为主缓存键或索引年龄;它们只适合作为用户显式 path/git index 的可选 fallback。没有 marker 的 path index 可以使用描述符内容摘要,但应避免每次补全现场全量计算。4. home/env 路径仍未形成只读契约
mcpp-community/mcpp#379 已确认
self env当前调用load_or_init(),会创建或迁移配置并可能 bootstrap,不能直接标记为只读。扩展也不应复制完整 home/shim 推导逻辑。本机当前 PATH 上的
mcpp实际是指向 xlings 的 shim;本次执行mcpp --version就因 shim 选择了本地索引不存在的版本而在进入 mcpp 前失败。这进一步说明动态数据层应允许完全缺席,不能把“可定位 mcpp home”当作激活阶段前提。建议实施顺序
- 新开 PR,只做 context scanner、段头/snippets、显式替换范围和 provider/parser 契约测试。
- 结构补全达到不生成无效文本的标准后,可以默认开启。
- 动态补全保持关闭或不实现,等待 Form A versions、只读 env resolver 和批量 catalog 契约。
- 上游提供版本化 manifest vocabulary 后,再接入静态字段键和枚举值。
- 不建议 force-push 重写现有 feat: add opt-in code completion for mcpp.toml #4;新 PR 建立后,将 feat: add opt-in code completion for mcpp.toml #4 标记为 superseded 并关闭,保留历史 review 上下文。
结合 mcpp-community/mcpp#379 的最新拆分决定和当前源码重新复核,结论是:方案适合拆成“结构补全先落地、动态索引继续等待”,不适合按现稿一次性实现。
可以先实施的部分
以下部分不依赖上游新协议,范围也可验证:
- 段头结构建议;
- 依赖/feature 写法 snippets;
- 光标上下文与显式替换范围;
- provider 映射、引号闭合、部分输入和真实 mcpp parser 契约测试;
- 数据源失败时静默降级为纯结构建议;
- 未受信任工作区不启动外部进程。
不过不建议为了这部分实现一个接近完整 TOML 的自制 parser。当前目标只需要回答“光标所在段、键位/值位、局部字符串或内联表位置和替换范围”,用带字符串/注释/括号状态的容错 context scanner 更容易审计,也更容易用残缺输入 fixture 覆盖。完整 Parser 会扩大实现和维护面,却仍不能成为 mcpp manifest 的权威语义来源。
动态包名/版本补全仍有阻塞
1. 表格A仍不输出
当前 已经在进入 Form A 分支前计算了 linux/macosx/windows versions,但 的 Form A 输出仍只有:
cmd_xpkg_parse``--json{"namespace":"...","name":"...","form":"A"}
最新 mcpp-index 静态统计有 81 个 描述符,其中 63 个内联 ,其余 18 个进入非 TableBody/Form A 路径。它们不能提供版本候选,因此“官方解析器零漂移”目前并不成立于完整索引。upstream/main``pkgs/**/*.lua``mcpp = {}2. 缓存不能消除首次 N 进程成本
补全过程读缓存是正确的,但第一次构建缓存、索引 revision 变化或缓存失效时,现稿仍需对约 81 个描述符分别启动 mcpp。缓存降低调用频率,不解决一次刷新时的进程数量、部分失败聚合和扩展激活后台负载。
在批量 catalog API 出现前,不建议把动态数据层默认开启。更合适的上游接口仍是一次返回 canonical identity、三平台 versions、index revision 和逐项 diagnostics 的批量 catalog。
3. Git HEAD/FETCH_HEAD 不是默认索引的权威身份
MCPP/xlings 对安装索引使用:
.xlings-index-version:内容 revision,opaque,只比较相等性;.mcpp-index-updated:最近刷新时间。
默认索引通常是 artifact materialization,不保证存在 。因此不能把 HEAD/FETCH_HEAD 作为主缓存键或索引年龄;它们只适合作为用户显式 path/git index 的可选 fallback。没有 marker 的 path index 可以使用描述符内容摘要,但应避免每次补全现场全量计算。
.git4. home/env 路径仍未形成只读契约
mcpp-community/mcpp#379 已确认 当前调用 ,会创建或迁移配置并可能 bootstrap,不能直接标记为只读。扩展也不应复制完整 home/shim 推导逻辑。
self env``load_or_init()本机当前 PATH 上的 实际是指向 xlings 的 shim;本次执行 就因 shim 选择了本地索引不存在的版本而在进入 mcpp 前失败。这进一步说明动态数据层应允许完全缺席,不能把“可定位 mcpp home”当作激活阶段前提。
mcpp``mcpp --version建议实施顺序
- 新开 PR,只做 context scanner、段头/snippets、显式替换范围和 provider/parser 契约测试。
- 结构补全达到不生成无效文本的标准后,可以默认开启。
- 动态补全保持关闭或不实现,等待 Form A versions、只读 env resolver 和批量 catalog 契约。
- 上游提供版本化 manifest vocabulary 后,再接入静态字段键和枚举值。
- 不建议 force-push 重写现有功能:为mcpp.toml #4添加自愿加入的代码完成功能;新 PR 建立后,将功能:为mcpp.toml #4添加自愿加入的代码完成功能标记为 superseded 并关闭,保留历史 review 上下文。
结构层已按拆分结论实现并提 PR:#9
落地内容:容错 context scanner(显式替换范围)、段头 snippet(25 段)、
开放段写法模板、provider 1:1 映射、契约测试(段头/模板键/条件段规则,
真实 mcpp 验证,44 例)。mcpp.tomlCompletion默认开启。留待上游契约的部分(本 PR 不含):
- 静态字段键/枚举 → 等版本化 manifest vocabulary(RFC: 统一机器可读输出协议 —— envelope + destructive + --format 归一 + 老命令永久兼容 mcpp#379);
- 依赖包名/版本 → 等批量 catalog 接口、Form A versions 输出、只读 env
resolver。
#4 已标记 superseded 并关闭。
结构层已合并:#9(merge commit
e8586b5),含 review 打磨项:- 补
[build-dependencies]段头(26 段),新增真实 mcpp 契约用例; [[...]]数组表不提供建议(mcpp manifest 无数组表,避免语义被悄悄替换成普通段);- README 与 PR 描述同步更新(新增 103 例 / 全量 237 例通过,含真实 mcpp 契约测试)。
动态层后续仍待上游契约(接口已预留,本 issue 继续跟踪):
- Form A
xpkg parse输出三平台 versions 并集; - 批量 catalog 接口:一次返回 canonical identity + 三平台 versions + index revision + 逐项 diagnostics,避免首次 N 进程成本;
- 接入机器输出协议(
docs/zh/11-machine-output.md):--format json信封 +--protocol-version静态 effects 契约,替代--json裸输出与自研 home/shim 推导;self env --format json只读已满足「只读 env resolver」前提; - 缓存键改用
.xlings-index-version/.mcpp-index-updated官方 marker(默认索引无.git); - 静态字段键/枚举:等上游版本化 manifest vocabulary(RFC: 统一机器可读输出协议 —— envelope + destructive + --format 归一 + 老命令永久兼容 mcpp#379)。
「结构层先落地、动态层等契约」的拆分结论不变。
- 补
- added a commit that references this issue
on Aug 26, 2026
mcpp.toml 自动补全 — 重做方案(#4)
1. 范围
[package]、[targets.<name>]等 snippet)standard、kind等——等上游版本化 schema,接口已预留)2. 架构
四层,单向依赖,跨层只传纯数据:
2.1 parser 层
[dep、simd = { flags = [ {)、带 token 行列位置、contextAt(line, ch)返回光标上下文(段路径 / 键路径 / 键位或值位 / 替换范围)。toml-eslint-parser:对未闭合段头/字符串/内联表、残缺键全部直接抛异常——它的错误恢复面向「完整但不合法」的 lint 场景,不面向补全时的半成品输入。排除。@taplo/lib:lint能容错并返回带 range 的错误,但 JS 绑定只暴露 lint/format/encode/decode,不暴露带位置的 AST,回答不了「光标在哪个段哪个键」。排除。2.2 语义层
[target.<sel>.build]只接受 build inputs——修复 review 问题 1)。src/manifest/toml.cppm)提取,注释带出处文件 + 行号 + commit hash,升级时git diff对照同步。2.3 index 数据层
mcpp xpkg parse <file> --json(官方解析器,零漂移),结果缓存到扩展存储;每次补全只读缓存。xpkg parse --json,前后对比 index 仓库 git 状态与.xlings-index-cache.jsonmtime 均无变化——该命令直接解析单文件,不经过索引加载/缓存重建路径。考虑其重要性(见 §7),仍请上游把只读性确认为契约。.git/FETCH_HEADmtime 或HEADcommit hash),不用目录 mtime——目录 mtime 只在直接子项增删时变化,git pull更新深层已有描述符时祖先目录 mtime 不动,会静默陈旧。项目级 path 索引通常没有.git,fallback 为描述符集合的内容 hash(或 max mtime)。xpkg parse失败或输出缺字段时,该数据源静默缺席,段头/模板等结构建议照常——任何数据层故障都不影响结构层。2.4 跨平台
src/home.cppm的顺序:$MCPP_HOME> 二进制自包含布局 >~/.mcpp(Windows 为%USERPROFILE%\.mcpp)。自包含布局的判定:二进制位于<dir>/bin/mcpp,且祖先路径不含target/(mcpp 源码开发构建产物)或data/xpkgs/(xlings 包安装)——该检查只看二进制的上级目录,用户项目产生的target/在项目内、不影响判定。扩展侧补充一条检查:PATH 上的mcpp可能是 xlings shim(符号链接追到调度器而非真实二进制),因此自包含分支额外要求<dir>/registry实际存在,否则落到默认 home。<home>/registry/data/mcpplibs/(src/xlings.cppm硬编码)。src/process.ts(Windowsmcpp.exe)。path.join。3. 数据源路径(均有源码依据)
明确排除:
xim-pkgindex——xlings 工具链索引;xim-index-repos/*——xlings 教学仓,扫错会建议出 mcpp 解析不了的包。v1 只读默认 mcpplibs + 项目级
[indices]的 path 索引;全局config.toml的[indices]语义实现时对照src/pm/index_management.cppm。4. 索引陈旧处理
MCPP_OFFLINE语义)。.git/FETCH_HEADmtime)。mcpp index update」,不弹窗、不打断。MCPP_OFFLINE=1或未受信任工作区:不提示。5. 设置
mcpp.tomlCompletiontrue(建议改为默认开启)mcpp.tomlCompletionIndexStaleDays300= 关闭提示6. 测试
default-p、"c++2)不破坏文本有显式断言(review 问题 5)。~/ln/code/test_mcpp/mcpp-index)做样本。7. 待确认
@wellwei
mcpp.tomlCompletion建议默认开启(范围收窄后「默认关闭」已无必要),indexStaleDays新设置是否接受?@Sunrisepeak
xpkg parse --json。建议给--json输出加一个 format/schema 版本字段:扩展对未知版本降级(只用结构建议)而非解析出错——把「输出结构变动请提前告知」这种单向通知变成机器可判定的契约,对上游只是一个字段的成本。xpkg parse --json无写副作用(不写 index cache / 不动磁盘状态)并可作为契约依赖。本机实测(2026.7.27.1)当前无写副作用,希望上游将其固定为保障。说明调用节奏:扩展不做高频调用——补全只读缓存,xpkg parse仅在索引 git HEAD 变化后后台批量执行一次(典型触发:mcpp index update,或mcpp add添加本地索引中不存在的包时——cmd_add源码确认仅本地未命中且归共享 registry 时才刷新)。8. 演进预留
fetchManifestSchema(),查询层加staticFieldProvider,其余不动。