Skip to content

feat: mongo shell 补全增强 — 类型感知 / REPL / 排序 / snippet#12

Merged
rrbe merged 10 commits into
masterfrom
feat/shell-completion-enhance
Jun 17, 2026
Merged

feat: mongo shell 补全增强 — 类型感知 / REPL / 排序 / snippet#12
rrbe merged 10 commits into
masterfrom
feat/shell-completion-enhance

Conversation

@rrbe

@rrbe rrbe commented Jun 16, 2026

Copy link
Copy Markdown
Owner

背景

迭代 mongo shell 编辑器的代码补全,对齐 NoSQLBooster / Compass 的体验(两者均逆向调研过:NoSQLBooster 用 Ace + 内嵌 TS 语言服务,Compass 用 CodeMirror 6 + @mongodb-js/mongodb-ts-autocomplete)。本项目沿用 CodeMirror 6,采用「TS 语言服务 worker + 正则注册表」的混合架构。

主要变更

  • 集合名连接后预取:连接 / 切库时预取当前库集合名,db. 补全无需先展开目录树。
  • 类型感知链式补全:渲染层 lazy Web Worker 跑 TS 语言服务,喂入手写基础 mongo.d.ts(匹配 shellCore shim 子集)+ 运行时生成的集合接口声明,db.coll.find().sort(). 等链式按真类型推导。typescript 打成独立懒加载 chunk,不进主包。worker 不可用时透明回退到正则源。
  • 补全结构化注册表completionRegistry.ts 作为「数据模型」单一真相源(算子按 query/update/aggregate 分组、全局、JS 关键字/字面量、值表、REPL 命令),扩展=改表。
  • 值下拉 + inline 幽灵文本sort({ _id: 处下拉 1/-1,并有灰色幽灵提示(Tab 接受)。
  • 方法 snippetlimit→limit(10)find→find({ })sort→sort({ field: -1 })…,Tab 在占位符间跳转。
  • mongosh REPL 命令show dbs/databases/collections/tables/users/roles/profileuse x(切库信号);整段恰为单条命令时翻译成 driver 调用,混合脚本仍按 JS 执行。
  • 排序修复:CodeMirror 6.20.2 对纯前缀匹配统一打 -100 分回退字母序,给集合/字段名按 99-len 设 boost,短名/近似匹配优先。
  • 下拉样式:标签加粗、类型 detail 淡化区分;选中行用应用强调色;图标只保留 ƒ(方法) 和 𝑥(字段),其余留白。
  • 编辑器交互修复:换行保持当前缩进;零参方法补全光标落在 () 后。

测试

  • pnpm typecheck
  • pnpm test:unit ✅(343)
  • pnpm test:integration ✅(116,真实 MongoDB,含 REPL 命令)
  • pnpm build ✅(worker 独立 chunk)

⚠️ 活补全行为(snippet 占位跳转、show dbs 出表、use x 切库、幽灵文本)需 pnpm dev 手验;worker 任何失败都回退到正则源,最差=原有体验。

rrbe added 10 commits June 16, 2026 22:50
- 连接后/切库时预取当前库集合名,db. 补全无需先展开目录树
- mongoCompletion 拆分纯核 computeShellCompletion + 薄封装,新增值位置下拉
  (sort→1/-1、投影→1/0、布尔键→true/false),复用值槽检测助手
- 新增 inline 幽灵文本(inlineHint + ghostText):被动提示单个最可能值,
  与下拉互斥,Tab 接受、接受后自动清除
- ShellEditor 接入 ghostText() 与 Tab 优先级;.cm-ghost-text 样式
- 配套 computeShellCompletion / computeInlineHint 的 unit 测试
CodeMirror 6.20.2 对纯前缀匹配统一打 -100 分(不减标签长度),
导致 `db.live` 时 `lives` 与 `liveauthorizedviewers` 同分,回退到
字母序 → 长复合名反而靠前。给集合名/字段名按 `99 - len` 设 boost
(CM 将 boost 直接加到匹配分),短名得分更高、稳定排在前;boost 限
在 [-99,99] 仅在前缀同分区间内重排,不会把散列匹配顶到前缀匹配之上。
NoSQLBooster/Compass 式做法的轻量自研版:渲染层 lazy Web Worker 跑
TS 语言服务,喂入手写的 mongo 基础 d.ts(Database/Collection/Cursor,
链式方法返回自身,匹配 shellCore shim 子集)+ 运行时按集合名生成的
interface Database 增强声明,靠 TS 真类型推导链式补全
(db.coll.find().sort(). 知道仍是 cursor、getSiblingDB(x). 是 Database、
const c = db.x.find(); c. 知道 c 是 Cursor)。

- shellCompletion: 成员访问(.后)走 TS,其余($算子/值槽/字段/全局)与
  worker 不可用/超时/空结果时回退到现有正则源 mongoCompletionSource
- 用 noLib + 紧凑内置 globals,避免把 ~30 个 lib.es*.d.ts 打进 worker;
  typescript 编译器被打成独立懒加载 chunk(~1.6MB gzip,不进主包)
- 客户端 id-keyed pending/超时/崩溃透明回退(仿 serializerPool);
  编辑器挂载时预热 worker;条目按 kind→type 映射、复用 lengthBoost 排序
- 配 buildCollectionDecls / isMemberCompletion 单测;typecheck + build 通过
TS 把集合声明为 Collection 属性,补全条目 kind=property → CM 默认渲染
□ 图标(property),与方法的 ƒ 混在一起显得"空白"。在 db. 成员场景下把
property 条目映射为 type:'class'(○)+ detail:'collection',方法保留 ƒ
并加 'db' 标注,恢复此前正则源的集合外观。
- 抽 completionRegistry.ts 作为补全"数据模型"单一真相源:算子(按
  query/update/aggregate 上下文分组)、全局构造器、JS 关键字/字面量、
  值表(sort/projection/boolean)、REPL 命令表,均带 category。
  mongoCompletion/stageCompletion 改为消费它,扩展=改表不改正则
- 裸词位置新增 JS 关键字补全(const/function/return/debugger…),
  原 true/false/null 归为字面量
- TS 方法条目渲染为调用 snippet:limit→limit(10)、find→find({ })、
  sort→sort({ field: -1 })…,常用方法配模板、零参方法 name()、其余 name()
shellCore 预处理:整段恰为单条 REPL 命令时不走 vm,翻译成 driver 调用——
show dbs/databases→listDatabases、show collections/tables→listCollections、
show users/roles→usersInfo/rolesInfo、show profile→system.profile;
use x→返回 ack + useDatabase 信号,渲染层据此 setActiveDatabase(并预取集合)。
混合脚本仍按 JS 执行(报错,与 mongosh 一致)。

- ShellResult 加 useDatabase 字段;parseReplCommand 纯解析(可单测)
- 行首语句位置补全 show dbs/use 等(category=command,来自注册表)
- 配 parseReplCommand 单测 + runReplCommand 集成测试(5 例,真实 mongo)
- 建议词加粗(fg-0)、匹配段强调色加粗;类型 detail 改为很淡(fg-3)、更小、
  斜体,明显从标签后退
- 选中行从 CodeMirror 默认刺眼蓝改为应用 accent + accent-fg,detail 半透明
- 用 .cm-tooltip.cm-tooltip-autocomplete 提高优先级压过 CM 运行时注入样式
- Enter 改为保持当前行缩进(JS 缩进器会把续行的 .sort()/.project() 链
  归零,丢掉手动缩进);开括号后加一级、{|} 时把闭括号下沉到新行。
  下拉打开时让位给 Enter 接受补全。
- 零参方法(admin/toArray/itcount…)改用纯 `name()` apply 而非无字段
  snippet:CM 对无字段 snippet 不设光标,会落在插入起点(db.|admin()),
  纯字符串 apply 则把光标放在末尾(db.admin()|)。
- Tab 链入 nextSnippetField、Shift+Tab 链入 prevSnippetField,
  多字段 snippet(sort/updateOne)可在占位间跳转而非插入制表符。
类型 detail 已用文字标明类别,CodeMirror 默认那套(○ 集合、□ 算子、
🔑 关键字/全局/命令、abc 值)反而是噪音。CSS 把这些 ::after content 置空;
.cm-completionIcon 列宽固定 .8em,留白后标签仍对齐。
- tsAutocompleteClient: pending 改存 {resolve, timer},新增幂等 settle()
  作为唯一收口;cancel() 真正丢弃在飞请求,快速输入不再累积 pending/timer
- ShellEditor: enterKeepIndent 用 range.from/to 替代 range.head,
  对空光标与选区一致;更新 plain Enter 的陈旧注释
- completionRegistry: 删除 AGG_EXPR_OPERATORS 里重复的 $mergeObjects
- mongoCompletion: 补全 inString 文档,注明不处理模板串/注释的已知限制
@rrbe rrbe merged commit 68e8e70 into master Jun 17, 2026
2 checks passed
@rrbe rrbe deleted the feat/shell-completion-enhance branch June 17, 2026 01:47
@rrbe rrbe mentioned this pull request Jun 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant