- 开发工具
【免费下载链接】tern_for_vim
Tern plugin for Vim
tern_for_vim 是一个为 Vim 提供 JavaScript 语义级智能补全、跳转定义、类型查询与一键重命名的插件。它的核心不是某一段代码,而是 VimL、Python、Node.js 三层技术各司其职的协作设计。本文带你快速看懂这套三层架构是如何跑起来的。
一张流程看懂三层架构
先记住这条数据链路,全文围绕它展开:
你的按键/光标 →VimL(命令与入口)→Python(组装请求、管理进程)→ 本地 HTTP/JSON →Tern 服务器(Node.js 分析 JS)→ 结果原路返回 Vim 界面
三层分别对应仓库里的三块核心文件:
- 第一层 VimL:autoload/tern.vim
- 第二层 Python 桥接:script/tern.py
- 第三层 Tern 服务器:由 package.json 声明的
tern依赖安装而来
第一层:VimL 负责命令、补全入口与生命周期
VimL 层几乎不做"重活",它只做三件事:
- 自动启用:当你打开 JavaScript 文件时,after/ftplugin/javascript_tern.vim 会调用
tern#Enable(),把:TernDef、:TernDoc、:TernType、:TernRefs、:TernRename等命令注册到当前缓冲区。 - 接管智能补全:VimL 将缓冲区的
omnifunc指向tern#Complete(见 autoload/tern.vim),于是你按 Ctrl-X Ctrl-O 时,补全结果来自 Tern 而非简单文本匹配。 - 管理生命周期:退出 Vim 时通过
VimLeavePre自动调用tern#Shutdown()杀掉所有服务器进程,不留"僵尸"。
另外,ftdetect/tern.vim 还顺手让.tern-project配置文件获得 JSON 高亮,细节上很贴心。
💡 这一层的关键设计:VimL 只负责"接电话",所有电话内容都转给 Python 处理——因为 VimL 本身没有方便的 HTTP 和网络能力。
第二层:Python 桥接,真正的"胶水"
script/tern.py 是整个插件的心脏,它通过 Vim 内置的vimPython 模块双向读写 Vim 状态,承担四块职责:
1. 找到或启动 Tern 服务器
- 从当前文件目录向上查找
.tern-project文件,确定项目根目录(script/tern.py); - 每个项目目录对应一个独立的
Project对象和一台服务器,端口号会被缓存复用; - 若服务器未运行,则执行
g:tern#command(默认为node node_modules/tern/bin/tern --no-port-file,见 autoload/tern.vim),从子进程输出中解析Listening on port N拿到端口(script/tern.py)。
2. 组装 JSON 请求
tern_runCommand()把"查询类型 + 光标位置 + 文件内容"打包成 JSON,POST 到http://localhost:端口(script/tern.py)。
3. 智能的缓冲同步(最精妙的一处)
- 用 Vim 的
undotree()['seq_cur']序列号判断文件是否改过,没改就不重发; - 文件超过 250 行时只发送"光标附近的函数片段"而非全文(script/tern.py),大幅降低传输量;
- 切离缓冲区(BufLeave)时若内容脏了,会主动把最新全文同步给服务器,保证后续分析基于最新代码。
4. 把结果渲染回 Vim
补全结果写入b:ternLastCompletion供弹出菜单使用,类型、文档输出到信息行或预览窗口,引用(References)和重命名结果直接填入 Vim 的 location list,按:lopen即可逐条跳转。
第三层:Tern 服务器:Node.js 里的 JavaScript 分析引擎
Tern 是一个独立的 JavaScript 程序,通过 npm 安装到插件目录(安装命令见下文)。它在本地随机端口上监听 HTTP 请求,支持completions、type、definition、refs、rename等查询类型,真正负责:
- 解析整个项目代码,建立语义索引;
- 根据
.tern-project加载你指定的库(如jquery、browser)和插件; - 返回 JSON 结果,供上层渲染。
配置示例(完整说明见 doc/tern.txt):
{ "libs": ["browser", "jquery"], "loadEagerly": ["src/main.js"] }一次智能补全的完整链路
以"输入obj.触发补全"为例,数据是这样流动的:
- Vim 发现
omnifunc=tern#Complete,先调用 VimL 的tern#Complete; - VimL 转调 Python 的
tern_ensureCompletionCached(),检查光标行是否变了(变了才重新请求); - Python 组装 JSON 请求,必要时先同步缓冲,POST 给本地 Tern 服务器;
- 服务器基于项目语义索引返回候选词及其类型、文档;
- Python 把候选词整理成带类型图标(fn/num/str/bool)的列表,交还 Vim 弹出补全菜单。
整个过程在 1 秒超时(g:tern_request_timeout)内完成,几乎无感。
新手向:常用配置项速查
| 配置项 | 默认值 | 作用 |
|---|---|---|
g:tern_map_keys | 0 | 设为1启用<LocalLeader>t系列快捷键 |
g:tern_map_prefix | <LocalLeader> | 快捷键前缀 |
g:tern_show_argument_hints | no | 设为on_move/on_hold显示函数参数提示 |
g:tern_show_signature_in_pum | 0 | 设为1在补全菜单显示完整函数签名 |
g:tern_request_timeout | 1 | 请求超时(秒) |
g:tern#command | node .../tern | 自定义服务器启动命令(node 路径特殊时必备) |
更多命令说明可查阅官方帮助文档 doc/tern.txt。
上手三步:安装 tern_for_vim
- 确保系统已安装 Node.js 和 npm(Tern 是 JavaScript 程序);
- 将仓库放入你的插件目录,例如
git clone https://gitcode.com/gh_mirrors/te/tern_for_vim; - 在插件根目录(
package.json所在处)执行npm install,再在项目根目录创建.tern-project即可。
⚠️ 小提示:插件要求 Vim 编译时带 Python 支持(Vim 7.3+);另外本项目目前处于非活跃维护状态,遇到版本兼容问题时建议优先检查 node 与 tern 的版本匹配。
写在最后:这套三层设计教会我们什么
tern_for_vim 的价值不只在于功能,更在于它给插件开发者的教科书式示范:
- 各语言干各语言擅长的事:VimL 管 UI 与生命周期,Python 管系统与网络,JavaScript 管语义分析;
- 把昂贵的分析进程外置:Vim 保持轻量,重活交给独立的本地服务器,还能按项目多开、随 Vim 退出而清理;
- 用脏检查与分片传输控制通信开销,让"智能"体验不牺牲编辑器流畅度。
理解了这个骨架,你再看任何"编辑器 + 语言服务器"的组合(LSP 生态即是其现代版),都会觉得似曾相识。
- 开发工具
【免费下载链接】tern_for_vim
Tern plugin for Vim
相关推荐
Mononoke 服务架构全解:前端协议服务器与内部微服务的分工协作
Mononoke 服务架构全解:前端协议服务器与内部微服务的分工协作 Mononoke 是 Sapling(一个可扩展、易用的版本控制系统)的服务器端实现,采用
开发工具CLI后端CodePilot 服务商架构全景:Provider Catalog → Resolver → Claude Code SDK 三层桥接的设计与实战
CodePilot 服务商架构全景:Provider Catalog → Resolver → Claude Code SDK 三层桥接的设计与实战 本篇技术指
人工智能AI 应用AI Agent交互助手MCP Clients本地部署Thorium 浏览器:按 CPU 选版本,3 步装好的老电脑提速指南
Thorium 浏览器:按 CPU 选版本,3 步装好的老电脑提速指南 Thorium 浏览器是一个按 CPU 分别编译、默认收紧隐私的 Chromium 分支
桌面应用跨平台
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考