Repository navigation
design: mcpp.toml 补全重做方案 —— 语义模块 + index 动态数据(#4 重做) #8
Copy link
Copy link
Open
Labels
documentationImprovements or additions to documentationImprovements or additions to documentationenhancementNew feature or requestNew feature or request
Description
mcpp.toml 自动补全 — 重做方案(#4)
状态:方案待 review,确认后动工。背景:#4 首轮实现(手写字段表)被 review 打回,本方案为重做稿。
1. 范围
| 做 | 不做 |
|---|---|
段头结构建议([package]、[targets.<name>] 等 snippet) |
静态字段键/枚举值(standard、kind 等——等上游版本化 schema,接口已预留) |
| 依赖包名 + 版本候选(动态数据) | 诊断 / hover / 跳转 |
| 依赖/feature 写法模板(snippet) | 市场中心 UI(二期,复用同一缓存层) |
2. 架构
四层,单向依赖,跨层只传纯数据:
extension.ts 唯一 vscode 依赖:注册 provider、设置门、1:1 映射
↓
completion 查询层 compute(context) → 建议(每条带显式替换范围)
↓ ↓
parser+语义层 index 数据层
容错 TOML 解析 包名/版本候选
2.1 parser 层
- 自写容错 TOML 解析:未闭合输入容错(
[dep、simd = { flags = [ {)、带 token 行列位置、contextAt(line, ch)返回光标上下文(段路径 / 键路径 / 键位或值位 / 替换范围)。 - 库选型已实测(2026-08,沙盒验证):
toml-eslint-parser:对未闭合段头/字符串/内联表、残缺键全部直接抛异常——它的错误恢复面向「完整但不合法」的 lint 场景,不面向补全时的半成品输入。排除。@taplo/lib:lint能容错并返回带 range 的错误,但 JS 绑定只暴露 lint/format/encode/decode,不暴露带位置的 AST,回答不了「光标在哪个段哪个键」。排除。- 结论:补全需要的是「光标上下文 + 容错位置」而非完整 TOML 一致性,自写范围收敛(段/键值/数组/内联表/字符串/注释),工程量可控且全程测试覆盖。
- 结构性修复 review 问题 2(key/value 无替换范围)与问题 3(内嵌 flags 分支不可达)。
2.2 语义层
- 段归属规范化、条件段规则(如
[target.<sel>.build]只接受 build inputs——修复 review 问题 1)。 - 规则从 mcpp 源码(
src/manifest/toml.cppm)提取,注释带出处文件 + 行号 + commit hash,升级时git diff对照同步。
2.3 index 数据层
- 扩展激活时后台对每个描述符执行
mcpp xpkg parse <file> --json(官方解析器,零漂移),结果缓存到扩展存储;每次补全只读缓存。 - 只读性已实测(mcpp 2026.7.27.1):对 index 缓存内和外部目录的描述符分别执行
xpkg parse --json,前后对比 index 仓库 git 状态与.xlings-index-cache.jsonmtime 均无变化——该命令直接解析单文件,不经过索引加载/缓存重建路径。考虑其重要性(见 §7),仍请上游把只读性确认为契约。 - 缓存键 = index 仓库的 git 状态(
.git/FETCH_HEADmtime 或HEADcommit hash),不用目录 mtime——目录 mtime 只在直接子项增删时变化,git pull更新深层已有描述符时祖先目录 mtime 不动,会静默陈旧。项目级 path 索引通常没有.git,fallback 为描述符集合的内容 hash(或 max mtime)。 - 已在真实索引(mcpplibs/mcpp-index,81 包 / 16 命名空间 / 122 版本)验证输出结构:identity + versions(按 OS)+ targets + unknown_keys。
- 降级行为:mcpp 二进制缺失、
xpkg parse失败或输出缺字段时,该数据源静默缺席,段头/模板等结构建议照常——任何数据层故障都不影响结构层。 - 未受信任工作区不 spawn 外部进程,静默降级为纯结构建议。
2.4 跨平台
- mcpp home 定位按
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。 - index 路径
<home>/registry/data/mcpplibs/(src/xlings.cppm硬编码)。 - spawn mcpp 复用扩展现有
src/process.ts(Windowsmcpp.exe)。 - 版本候选取 linux/macosx/windows 三平台并集(manifest 可能交叉构建),semver 倒序。
- parser 兼容 CRLF;fixture 路径全部
path.join。
3. 数据源路径(均有源码依据)
~/.mcpp/registry/data/mcpplibs/pkgs/**/*.lua ← 库索引(唯一正确来源)
明确排除:
xim-pkgindex——xlings 工具链索引;xim-index-repos/*——xlings 教学仓,扫错会建议出 mcpp 解析不了的包。
v1 只读默认 mcpplibs + 项目级 [indices] 的 path 索引;全局 config.toml 的 [indices] 语义实现时对照 src/pm/index_management.cppm。
4. 索引陈旧处理
- 扩展只读不刷新(网络操作 + 工作区信任边界 +
MCPP_OFFLINE语义)。 - 候选 detail 显示索引年龄(
.git/FETCH_HEADmtime)。 - 超阈值追加提示「可运行
mcpp index update」,不弹窗、不打断。 MCPP_OFFLINE=1或未受信任工作区:不提示。- 设计立场:旧索引是 mcpp 的合法状态(caret 约束本就按本地已知版本求解),候选 = mcpp 实际会解析的结果,「与 mcpp 所见一致」优先于「新」。
5. 设置
| 设置 | 类型 | 默认 | 说明 |
|---|---|---|---|
mcpp.tomlCompletion |
boolean | true(建议改为默认开启) |
补全总开关。范围已收窄为「结构 + 与 mcpp 所见一致的动态数据」,不存在生成无效配置的风险,「默认关闭」不再必要(待 wellwei 确认) |
mcpp.tomlCompletionIndexStaleDays |
number | 30 |
索引超过 N 天未更新时提示;0 = 关闭提示 |
6. 测试
- 纯函数单测(parser / 语义 / completion / index fixture):node --test,零 vscode 依赖。
- 替换范围、部分输入(
default-p、"c++2)不破坏文本有显式断言(review 问题 5)。 - 契约测试:段头 / 条件段规则生成最小 manifest 喂真实 mcpp,断言无 unsupported 诊断;无 mcpp 的环境 skip。硬承诺:语义层每条规则必须有对应契约测试——语义层仍是人工同步(漂移变慢但不是零),契约测试保证漂移发生时是测试红,而不是用户补全出错。
- index 层 fixture 可用真实索引描述符(
~/ln/code/test_mcpp/mcpp-index)做样本。
7. 待确认
- 段头 snippet + 写法模板是否保留?(我的立场:它们描述语法结构而非字段语义,属于允许手写的语义层)
mcpp.tomlCompletion建议默认开启(范围收窄后「默认关闭」已无必要),indexStaleDays新设置是否接受?- 重做方式:feat: add opt-in code completion for mcpp.toml #4 上 force-push 还是开新 PR?契约测试策略:本地强 CI 弱,还是 CI 钉版安装 mcpp?
- 依赖补全数据走
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. 演进预留
- 上游版本化 manifest schema 落地后:数据层加
fetchManifestSchema(),查询层加staticFieldProvider,其余不动。 - 市场中心二期:复用 index 缓存层。
- 远期可迁移为独立 LSP:parser + completion 原样搬进程,只重写协议胶水。
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
documentationImprovements or additions to documentationImprovements or additions to documentationenhancementNew feature or requestNew feature or request
Activity
Sunrisepeak commentedon Aug 8, 2026
@Ximiaw
mcpp xpkg parse --json接口可以做支持, 但实现侧感觉可以不高频调用而是做数据缓存Ximiaw commentedon Aug 8, 2026
xpkg parse仅在索引 git HEAD 变化后后台批量执行一次(缓存键 = HEAD/FETCH_HEAD);mcpp index update,或mcpp add本地未命中的新包(读了 cmd_add 源码,仅本地索引查不到且归共享 registry 时才刷新)——日常可能几天都不到一次。
只读性本机实测(2026.7.27.1)无写副作用,希望作为接口契约固定下来即可。
Ximiaw commentedon Aug 8, 2026
结构层已按拆分结论实现并提 PR:#9
落地内容:容错 context scanner(显式替换范围)、段头 snippet(25 段)、
开放段写法模板、provider 1:1 映射、契约测试(段头/模板键/条件段规则,
真实 mcpp 验证,44 例)。
mcpp.tomlCompletion默认开启。留待上游契约的部分(本 PR 不含):
resolver。
#4 已标记 superseded 并关闭。
Sunrisepeak commentedon Aug 8, 2026
@Ximiaw
fix: xpkg parse 的 Form A 输出补回已计算的 versions (#489) (#490)