【免费下载链接】gridex
A native macOS / windows / Linux database IDE built with Swift and AppKit. Connect to PostgreSQL, MySQL, SQLite, and Redis from a single app with a fast, keyboard-driven interface.
Gridex 是一款基于 Swift + AppKit 原生构建的数据库 IDE(同时支持 Windows 与 Linux),可连接 PostgreSQL、MySQL、SQLite、Redis 等数据库。这篇文章拆解它的 SQL 自动补全引擎:一次按键后,如何在 80ms 内完成上下文解析、模糊匹配评分与弹窗渲染,让补全"感觉是瞬时的"。
三步流水线:一次补全是怎样发生的
整个引擎只有三个类协作,数据流非常清晰:
- 上下文解析:SQLContextParser.swift 把光标前的 SQL 文本切分为 token,判断"此刻该补全什么"——是关键词、表名、列名、函数,还是一次 JOIN。
- 模糊匹配 + 评分排序:AutocompleteProvider.swift 对候选集打分、去重、排序,输出最多 20 条建议。
- 轻量弹窗渲染:CompletionWindow.swift 把前 10 条渲染进一个无边框悬浮窗口。
三者之间唯一的"闸门"是编辑器协调器中的 80ms 防抖定时器,位于 QueryEditorView.swift。
上下文感知:先判断"该补什么"
很多补全引擎"什么位置都补一切",结果噪音很大。Gridex 的做法是先做轻量级 SQL 解析(不依赖完整语法树):
- 字符串内不触发:光标落在
'...'里直接跳过,避免补全打断你输入数据; - 按分号隔离当前语句:只分析光标所在的那条 SQL,历史语句零干扰;
- 别名与多表作用域:解析
FROM users u JOIN orders o,记住每张表的别名,这样输入u.时只补users的列; - 点号即时触发:输入
.不走防抖,立刻弹列名列表(见 SQLContextParser.swift 的触发判定)。
最有意思的是FK 感知的 JOIN 建议:当光标停在JOIN之后,引擎会读取外键元数据,直接生成整句JOIN orders o ON u.id = o.user_id——连别名都按表名首字母自动选好,见 AutocompleteProvider.swift。
模糊匹配评分算法:四层金字塔
输入只有两个字符,怎么既"快"又"准"?核心是一个纯函数 fuzzyScore,把候选词按匹配质量分成四层:
| 匹配层级 | 示例(输入or) | 基础分 |
|---|---|---|
| 精确匹配 | order→order | 1000 |
| 前缀匹配 | or→order_id | 500 − 长度惩罚 |
| 词边界前缀 | uid→ 命中user_id中的user | 200 − 长度惩罚 |
| 子序列模糊 | ord→ 逐个吃到 o-r-d | 连击加分,_/.后命中再 +3 |
几个细节决定了实际体验:
- 长度惩罚:前缀匹配时越短的候选越靠前,所以输入
s时SELECT会排在大名鼎鼎的SUBSTRING前面; - 连击奖励:子序列匹配中,连续命中的字符会累积加分(
ord命中order三个连续字符,远胜散落三处的 o-r-d); - 下划线/点号加权:
user_id中_i命中比中间随机位置命中更高分,贴合 snake_case 命名习惯; - 匹配高亮:命中的字符位置被记录下来(
fuzzyMatchRanges),弹窗里用粗体 + 强调色标出,让用户一眼看出"为什么它出现了"。
智能排序:你常用的是什么,它就排前面
打完基础分后还有三道"加减分",见 评分与排序逻辑:
- 近期使用加权:最近用过 50 次以内的对象,每次命中加
30 − 使用序号分——刚补全过的SELECT会稳稳排在最前; - 高频子句加成:
SELECT / WHERE / ORDER BY这类主关键词固定 +100; - 主键列加成:补列名时主键列额外 +5,因为它们通常是 JOIN 和 WHERE 的主角。
最后按「分数降序 → 类型优先级(关键词 > 表 > 列 > 函数 > JOIN)→ 字母序」三级排序,去重后截断到 20 条。
80ms防抖:即时感与性能的平衡
每次按键都全量重算吗?不。协调器用一个可取消的DispatchWorkItem做 80ms 防抖(QueryEditorView.swift):
- 每按一个键就取消旧任务、重排新任务,只有"停手 80ms"才真正触发解析;
- 80ms 是精心挑的:低于人的感知阈值,连打 10 个字只会补一次全;
- 例外通道:输入
.或空格后直接回车等场景绕过防抖,该快的时候立刻快; - 智能隐藏:如果只剩 1 条候选且与你已输入的词完全一致,弹窗干脆不弹——不刷屏才是好补全。
顺带一提,Linux 版用QTimer单发定时器实现同款逻辑,但阈值调到了 60ms(见 QueryEditorView.cpp),同一个算法骨架、按平台手感微调参数,跨端一致性是"算法层共用、体验层各自调参"的结果。
纯NSView轻量弹窗:没有表格,没有滚动条
CompletionWindow 的注释很直白:No scroll view, no table view。它就是一个 420px 宽、每行 28px 高的悬浮面板:
NSPanel+nonactivating:窗口设为"不能成为 key window",弹出时不抢焦点,输入框光标纹丝不动——这是原生补全最容易被忽略的细节;NSVisualEffectViewpopover 材质:毛玻璃背景零成本,圆角 6px 直接跟系统 popover 一个模子;- NSStackView 平铺最多 10 行:没有
NSTableView的虚拟化开销,10 行以内直接布局,快且省内存; - 纯键盘驱动:↑↓ 移动、
↩插入、⇥替换、Esc关闭,底部常驻一行操作提示; - 边缘自适应:靠近屏幕底部时自动翻转到光标上方,横向则钳制在屏幕内 8px 边距里。
模块文件索引
想动手看代码的话,按这条路径走最快:
- macOS 补全核心:macos/Presentation/Views/QueryEditor/Autocomplete/
- 评分与排序:AutocompleteProvider.swift
- 上下文解析:SQLContextParser.swift
- 轻量弹窗:CompletionWindow.swift
- 防抖与键盘处理:QueryEditorView.swift
- Linux 同构实现:linux/src/Presentation/Views/QueryEditor/Autocomplete/(评分引擎 + Qt 弹窗)
小结
Gridex 的 SQL 自动补全没有引入任何第三方 LSP 或重量级组件,靠的就是三件事:一层清晰的四层模糊匹配评分保证"准",80ms 防抖 + 点号即时触发保证"快",纯 NSView 面板保证"轻"。对于想给自己的编辑器加补全功能的同学,这套"解析 → 打分 → 排序 → 轻量 UI"的流水线是一个可以直接抄作业的参考。
【免费下载链接】gridex
A native macOS / windows / Linux database IDE built with Swift and AppKit. Connect to PostgreSQL, MySQL, SQLite, and Redis from a single app with a fast, keyboard-driven interface.
相关推荐
如何用Python零门槛获取股票数据:MOOTDX终极指南
如何用Python零门槛获取股票数据:MOOTDX终极指南 你是否曾经因为获取股票数据太困难而放弃量化分析的想法?或者被复杂的数据接口和昂贵的费用吓退?今天我要
金融科技数据分析把 Switch 变手柄 B 站观影站:wiliwili 完整上手指南
把 Switch 变手柄 B 站观影站:wiliwili 完整上手指南 凌晨一点,小区停电,你把 Switch 靠在被子上,用两只 Joy Con 把 B 站刷
音视频桌面应用深度解析gh_mirrors/raft/raft:Go语言实现的Raft分布式共识协议完全指南
深度解析gh_mirrors/raft/raft:Go语言实现的Raft分布式共识协议完全指南 gh_mirrors/raft/raft是一个基于Go语言实现的
后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考