typescript-tools.nvim
⚡ NeoVim 值得拥有的 TypeScript 集成 ⚡
🚧 警告 🚧
请注意,该插件目前处于早期测试版本,这意味着您可能会遇到一些错误。
⁉️ 为什么?
- 纯 Lua 实现的
typescript-language-server
替代品,可直接使用 - 如果您在大型 TS/JS 项目中工作,您可能理解这个插件诞生的原因。在这类项目中,
typescript-language-server
可能会非常慢,而且经常无法提供准确的补全或直接崩溃。
✨ 特性
- ⚡ 速度极快,得益于使用类似 Visual Studio Code 的原生 Tsserver 通信协议
- 🪭 支持 TypeScript 4.0 及以上的多个版本
- 🌍 支持 nvim LSP 插件生态系统
- 🔀 支持多个 Tsserver 实例
- 💻 支持本地和全局安装的 TypeScript
- 🔨 支持从 Mason 安装的
tsserver
- 💅 提供开箱即用的 styled-components 支持,默认未启用(参见安装和配置)
- ✨ 改进的代码重构能力,例如提取变量或函数
🚀 工作原理?
如果您想了解插件的技术细节,请点击这里。
这个插件的功能与 Visual Studio Code 中捆绑的 TypeScript 支持扩展完全相同。
得益于新的(0.8.0)NeoVim API,现在可以将 Lua 函数作为 LSP 启动命令传递。因此,该插件生成了一个自定义版本的 I/O 循环,直接使用 Tsserver 的原生协议与其通信,无需任何额外代理。
Tsserver 协议是一个基于 JSON 的通信协议,可能是 LSP 的灵感来源。然而,它与 LSP 不兼容。为解决这个问题,该插件提供的 I/O 循环具有一个转换层,用于将所有消息在 Tsserver 格式之间进行转换。
总之,该插件的架构可以用下面的图表来表示:
NeoVim Tsserver 实例
┌────────────────────────────────────────────┐ ┌────────────────┐
│ │ │ │
│ LSP 处理程序 Tsserver LSP 循环 │ │ │
│ ┌─────────┐ ┌──────────────────┐ │ │ │
│ │ │ │ │ │ │ │
│ │ │ 请求 │ ┌──────────────┐ │ │ │ │
│ │ ├───────────┤►│ 转换层 │ │ │ │ │
│ │ │ 响应 │ │ │ │ │ │ │
│ │ ◄───────────┼─┤ │ │ │ │ │
│ │ │ │ └───┬─────▲────┘ │ │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ │ ┌───▼─────┴────┐ │ │ 请求 │ │
│ │ │ │ │ I/O 循环 ├─┼─┼────────────► │
│ │ │ │ │ │ │ │ 响应 │ │
│ │ │ │ │ ◄─┼─┼────────────┤ │
│ │ │ │ └──────────────┘ │ │ │ │
│ │ │ │ │ │ │ │
│ └─────────┘ └──────────────────┘ │ │ │
│ │ │ │
└────────────────────────────────────────────┘ └────────────────┘
📦 安装
❗️ 重要提示:如前所述,此插件作为
typescript-language-server
的替代品,因此您应该移除nvim-lspconfig
对它的设置。
⚡️ 要求
- NeoVim >= 0.8.0
- nvim-lspconfig
- plenary.nvim
- TypeScript >= 4.0
- 与您使用的 TypeScript 版本兼容的 Node 版本
lazy.nvim
{
"pmizio/typescript-tools.nvim",
dependencies = { "nvim-lua/plenary.nvim", "neovim/nvim-lspconfig" },
opts = {},
}
packer.nvim
use {
"pmizio/typescript-tools.nvim",
requires = { "nvim-lua/plenary.nvim", "neovim/nvim-lspconfig" },
config = function()
require("typescript-tools").setup {}
end,
}
⚙️ 配置
传递给 setup
函数的参数也会传递给标准的 nvim-lspconfig
服务器 setup
,允许您在此处使用相同的设置。
但您可以通过 settings
参数传递插件特定的选项,默认值如下:
require("typescript-tools").setup {
on_attach = function() ... end,
handlers = { ... },
...
settings = {
-- 生成额外的 tsserver 实例来计算诊断信息
separate_diagnostic_server = true,
-- "change"|"insert_leave" 决定客户端何时向服务器询问诊断信息
publish_diagnostic_on = "insert_leave",
-- 字符串数组("fix_all"|"add_missing_imports"|"remove_unused"|
-- "remove_unused_imports"|"organize_imports") -- 或字符串 "all"
-- 包含所有支持的代码操作
-- 指定作为代码操作公开的命令
expose_as_code_action = {},
-- 字符串|nil - 指定自定义的 `tsserver.js` 文件路径,如果为 nil 或路径下文件不存在
-- 则应用标准路径解析策略
tsserver_path = nil,
-- 指定 tsserver 加载的插件列表,例如,用于支持 `styled-components`
-- (参见 💅 `styled-components` 支持部分)
tsserver_plugins = {},
-- 此值传递给:https://nodejs.org/api/cli.html#--max-old-space-sizesize-in-megabytes
-- 内存限制(以兆字节为单位)或 "auto"(基本上没有限制)
tsserver_max_memory = "auto",
-- 下面描述
tsserver_format_options = {},
tsserver_file_preferences = {},
-- 所有 tsserver 消息的区域设置,支持的区域设置可以在这里找到:
-- https://github.com/microsoft/TypeScript/blob/3c221fc086be52b19801f6e8d82596d04607ede6/src/compiler/utilitiesPublic.ts#L620
tsserver_locale = "en",
-- VSCode 的 `typescript.suggest.completeFunctionCalls` 的镜像
complete_function_calls = false,
include_completions_with_insert_text = true,
-- CodeLens
-- 警告:这在 VSCode 中也是一个实验性功能,因为它可能会影响服务器的性能。
-- 可能的值:("off"|"all"|"implementations_only"|"references_only")
code_lens = "off",
-- 默认情况下,代码镜头显示在所有可引用的值上,对于某些人来说可能太多了
-- 这个选项通过移除成员引用的镜头来减少它们的数量
disable_member_code_lens = true,
-- JSXCloseTag
-- 警告:默认情况下它是禁用的(也许您的配置或发行版已经使用了 nvim-ts-autotag,
-- 如果启用此功能可能会发生冲突。)
jsx_close_tag = {
enable = false,
filetypes = { "javascriptreact", "typescriptreact" },
}
},
}
请注意,handlers
可用于覆盖某些 LSP 方法。
例如,您可以使用 filter_diagnostics
辅助函数来忽略特定错误:
local api = require("typescript-tools.api")
require("typescript-tools").setup {
handlers = {
["textDocument/publishDiagnostics"] = api.filter_diagnostics(
-- 忽略 'This may be converted to an async function' 诊断。
{ 80006 }
),
},
}
您还可以传递自定义配置选项,这些选项将传递给 tsserver
实例。您可以在 typescript
仓库中找到可用选项(例如,对于 typescript 5.0.4 版本):
要将这些选项传递给插件,请在插件的 setup
函数中传递它们:
require("typescript-tools").setup {
settings = {
...
tsserver_file_preferences = {
includeInlayParameterNameHints = "all",
includeCompletionsForModuleExports = true,
quotePreference = "auto",
...
},
tsserver_format_options = {
allowIncompleteCompletions = false,
allowRenameOfImportPath = false,
...
}
},
}
如果您想让 tsserver_format_options
或 tsserver_file_preferences
依赖文件类型,您可以将它们设置为返回表的函数,例如:
示例代码在此
require("typescript-tools").setup {
settings = {
...
tsserver_file_preferences = function(ft)
-- 使用打开文件的 `ft` 进行一些 "if 逻辑"
return {
includeInlayParameterNameHints = "all",
includeCompletionsForModuleExports = true,
quotePreference = "auto",
...
}
end,
tsserver_format_options = function(ft)
-- 使用打开文件的 `ft` 进行一些 "if 逻辑"
return {
allowIncompleteCompletions = false,
allowRenameOfImportPath = false,
...
}
end
},
}
preferences
和 format_options
的默认值在这个文件中
💅 styled-components
支持
显示更多
要获取 styled-components
的 IntelliSense,你需要全局安装 tsserver 插件,以启用对它的支持:
npm i -g @styled/typescript-styled-plugin typescript-styled-plugin
现在,你需要通过修改 settings
对象来加载插件,如下所示:
require("typescript-tools").setup {
settings = {
...
tsserver_plugins = {
-- 适用于 TypeScript v4.9+
"@styled/typescript-styled-plugin",
-- 或者适用于较旧的 TypeScript 版本
-- "typescript-styled-plugin",
},
},
}
自定义用户命令
该插件提供了几个自定义用户命令(仅应用于当前缓冲区):
TSToolsOrganizeImports
- 对导入进行排序并移除未使用的导入TSToolsSortImports
- 对导入进行排序TSToolsRemoveUnusedImports
- 移除未使用的导入TSToolsRemoveUnused
- 移除所有未使用的语句TSToolsAddMissingImports
- 为所有缺少导入且可导入的语句添加导入TSToolsFixAll
- 修复所有可修复的错误TSToolsGoToSourceDefinition
- 跳转到源定义(自 TS v4.7 可用)TSToolsRenameFile
- 允许重命名当前文件并将更改应用到相关文件TSToolsFileReferences
- 查找引用当前文件的文件(自 TS v4.2 可用)
支持的 LSP 方法
状态 | 请求 |
---|---|
✅ | textDocument/completion |
✅ | textDocument/hover |
✅ | textDocument/rename |
✅ | textDocument/publishDiagnostics |
✅ | textDocument/signatureHelp |
✅ | textDocument/references |
✅ | textDocument/definition |
✅ | textDocument/typeDefinition |
✅ | textDocument/implementation |
✅ | textDocument/documentSymbol |
✅ | textDocument/documentHighlight |
✅ | textDocument/codeAction |
✅ | textDocument/formatting |
✅ | textDocument/rangeFormatting |
✅ | textDocument/foldingRange |
✅ | textDocument/semanticTokens/full(自 TS v4.1 支持) |
✅ | textDocument/inlayHint(自 TS v4.4 支持) |
✅ | callHierarchy/incomingCalls |
✅ | callHierarchy/outgoingCalls |
✅ | textDocument/codeLens |
🚧 | textDocument/linkedEditingRange(计划中) |
✅ | workspace/symbol |
✅ | workspace/willRenameFiles |
❌ | workspace/applyEdit - 不适用 |
❌ | textDocument/declaration - 不适用 |
❌ | window/logMessage - 不适用 |
❌ | window/showMessage - 不适用 |
❌ | window/showMessageRequest - 不适用 |
🚦 路线图
🔨 开发
有用的链接:
🐛 运行测试
单元测试环境会自动引导,只需运行:
make test
或者如果你想运行单个测试文件:
make file=test_spec.lua test
💐 致谢
- null-ls.nvim - 提供了通过猴子补丁修改 nvim API 以启动自定义 LSP I/O 循环的想法
- typescript-language-server - 提供了如何转换某些 Tsserver 响应的思路
- Visual Studio Code(TypeScript 扩展) - 提供了使用 Tsserver 协议和性能优化的见解