⚡ TypeScript integration NeoVim deserves ⚡
Please note that the plugin is currently in the early beta version, which means you may encounter bugs.
typescript-language-servertypescript-language-server can be extremely slow in such projects,
and it often fails to provide accurate completions or just crash.tsserver installed from Mason
This plugin functions exactly like the bundled TypeScript support extension in Visual Studio Code.
Thanks to the new (0.8.0) NeoVim API, it is now possible to pass a Lua function as the LSP start
command. As a result, the plugin spawns a custom version of the I/O loop to communicate directly
with Tsserver using its native protocol, without the need for any additional proxy.
The Tsserver protocol, which is a JSON-based communication protocol, likely served as inspiration
for the LSP. However, it is incompatible with the LSP. To address this, the I/O loop provided by
this plugin features a translation layer that converts all messages to and from the Tsserver format.
In summary, the architecture of this plugin can be visualized as shown in the diagram below:
NeoVim Tsserver Instance
┌────────────────────────────────────────────┐ ┌────────────────┐
│ │ │ │
│ LSP Handlers Tsserver LSP Loop │ │ │
│ ┌─────────┐ ┌──────────────────┐ │ │ │
│ │ │ │ │ │ │ │
│ │ │ Request │ ┌──────────────┐ │ │ │ │
│ │ ├───────────┤►│ Translation │ │ │ │ │
│ │ │ Response │ │ Layer │ │ │ │ │
│ │ ◄───────────┼─┤ │ │ │ │ │
│ │ │ │ └───┬─────▲────┘ │ │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ │ ┌───▼─────┴────┐ │ │ Request │ │
│ │ │ │ │ I/O Loop ├─┼─┼────────────► │
│ │ │ │ │ │ │ │ Response │ │
│ │ │ │ │ ◄─┼─┼────────────┤ │
│ │ │ │ └──────────────┘ │ │ │ │
│ │ │ │ │ │ │ │
│ └─────────┘ └──────────────────┘ │ │ │
│ │ │ │
└────────────────────────────────────────────┘ └────────────────┘
❗️ IMPORTANT: As mentioned earlier, this plugin serves as a replacement for
typescript-language-server, so you should remove thenvim-lspconfigsetup for it.
{
"pmizio/typescript-tools.nvim",
dependencies = { "nvim-lua/plenary.nvim", "neovim/nvim-lspconfig" },
opts = {},
}
use {
"pmizio/typescript-tools.nvim",
requires = { "nvim-lua/plenary.nvim" },
config = function()
require("typescript-tools").setup {}
end,
}
require("typescript-tools").setup {
on_attach = function() ... end,
handlers = { ... },
...
settings = {
-- spawn additional tsserver instance to calculate diagnostics on it
separate_diagnostic_server = true,
-- "change"|"insert_leave" determine when the client asks the server about diagnostic
publish_diagnostic_on = "insert_leave",
-- array of strings("fix_all"|"add_missing_imports"|"remove_unused"|
-- "remove_unused_imports"|"organize_imports") -- or string "all"
-- to include all supported code actions
-- specify commands exposed as code_actions
expose_as_code_action = {},
-- string|nil - specify a custom path to `tsserver.js` file, if this is nil or file under path
-- not exists then standard path resolution strategy is applied
tsserver_path = nil,
-- specify a list of plugins to load by tsserver, e.g., for support `styled-components`
-- (see 💅 `styled-components` support section)
tsserver_plugins = {},
-- this value is passed to: https://nodejs.org/api/cli.html#--max-old-space-sizesize-in-megabytes
-- memory limit in megabytes or "auto"(basically no limit)
tsserver_max_memory = "auto",
-- described below
tsserver_format_options = {},
tsserver_file_preferences = {},
-- locale of all tsserver messages, supported locales you can find here:
-- https://github.com/microsoft/TypeScript/blob/3c221fc086be52b19801f6e8d82596d04607ede6/src/compiler/utilitiesPublic.ts#L620
tsserver_locale = "en",
-- mirror of VSCode's `typescript.suggest.completeFunctionCalls`
complete_function_calls = false,
include_completions_with_insert_text = true,
-- CodeLens
-- WARNING: Experimental feature also in VSCode, because it might hit performance of server.
-- possible values: ("off"|"all"|"implementations_only"|"references_only")
code_lens = "off",
-- by default code lenses are displayed on all referencable values and for some of you it can
-- be too much this option reduce count of them by removing member references from lenses
disable_member_code_lens = true,
-- JSXCloseTag
-- WARNING: it is disabled by default (maybe you configuration or distro already uses nvim-ts-autotag,
-- that maybe have a conflict if enable this feature. )
jsx_close_tag = {
enable = false,
filetypes = { "javascriptreact", "typescriptreact" },
}
},
}
Note that handlers can be used to override certain LSP methods.
For example, you can use the filter_diagnostics helper to ignore specific errors:
local api = require("typescript-tools.api")
require("typescript-tools").setup {
handlers = {
["textDocument/publishDiagnostics"] = api.filter_diagnostics(
-- Ignore 'This may be converted to an async function' diagnostics.
{ 80006 }
),
},
}
You can also pass custom configuration options that will be passed to tsserver
instance. You can find available options in typescript repository (e.g.
for version 5.0.4 of typescript):
To pass those options to plugin pass them to the plugin setup function:
require("typescript-tools").setup {
settings = {
...
tsserver_file_preferences = {
includeInlayParameterNameHints = "all",
includeCompletionsForModuleExports = true,
quotePreference = "auto",
...
},
tsserver_format_options = {
allowIncompleteCompletions = false,
allowRenameOfImportPath = false,
...
}
},
}
If you want to make tsserver_format_options or tsserver_file_preferences filetype dependant you
need to may set them as functions returning tables eg.
require("typescript-tools").setup {
settings = {
...
tsserver_file_preferences = function(ft)
-- Some "ifology" using `ft` of opened file
return {
includeInlayParameterNameHints = "all",
includeCompletionsForModuleExports = true,
quotePreference = "auto",
...
}
end,
tsserver_format_options = function(ft)
-- Some "ifology" using `ft` of opened file
return {
allowIncompleteCompletions = false,
allowRenameOfImportPath = false,
...
}
end
},
}
The default values for preferences and format_options are in this file
styled-components support
To get IntelliSense for styled-components, you need to install the tsserver plugin
globally, which enables support for it:
npm i -g @styled/typescript-styled-plugin typescript-styled-plugin
Now, you need to load the plugin by modifying the settings object as follows:
require("typescript-tools").setup {
settings = {
...
tsserver_plugins = {
-- for TypeScript v4.9+
"@styled/typescript-styled-plugin",
-- or for older TypeScript versions
-- "typescript-styled-plugin",
},
},
}
This plugin provides several custom user commands (they are only applied to current buffer):
TSToolsOrganizeImports - sorts and removes unused importsTSToolsSortImports - sorts importsTSToolsRemoveUnusedImports - removes unused importsTSToolsRemoveUnused - removes all unused statementsTSToolsAddMissingImports - adds imports for all statements that lack one and can be importedTSToolsFixAll - fixes all fixable errorsTSToolsGoToSourceDefinition - goes to
source definition
(available since TS v4.7)TSToolsRenameFile - allow to rename current file and apply changes to connected filesTSToolsFileReferences - find files that reference the current file (available since TS v4.2)| Status | Request |
|---|---|
| ✅ | 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 (supported from TS v4.1) |
| ✅ | textDocument/inlayHint (supported from TS v4.4) |
| ✅ | callHierarchy/incomingCalls |
| ✅ | callHierarchy/outgoingCalls |
| ✅ | textDocument/codeLens |
| 🚧 | textDocument/linkedEditingRange (planned) |
| ✅ | workspace/symbol |
| ✅ | workspace/willRenameFiles |
| ❌ | workspace/applyEdit - N/A |
| ❌ | textDocument/declaration - N/A |
| ❌ | window/logMessage - N/A |
| ❌ | window/showMessage - N/A |
| ❌ | window/showMessageRequest - N/A |
Useful links:
The unit testing environment is automatically bootstrapped, just run:
make test
Or if you want to run a single test file:
make file=test_spec.lua test
(top 24 of 44)
964 followers · starred Jul 2024
106 followers · starred Jun 2023
556 followers · starred Sep 2024
328 followers · starred Jun 2023
⚡ TypeScript integration NeoVim deserves ⚡
Please note that the plugin is currently in the early beta version, which means you may encounter bugs.
typescript-language-servertypescript-language-server can be extremely slow in such projects,
and it often fails to provide accurate completions or just crash.tsserver installed from Mason
This plugin functions exactly like the bundled TypeScript support extension in Visual Studio Code.
Thanks to the new (0.8.0) NeoVim API, it is now possible to pass a Lua function as the LSP start
command. As a result, the plugin spawns a custom version of the I/O loop to communicate directly
with Tsserver using its native protocol, without the need for any additional proxy.
The Tsserver protocol, which is a JSON-based communication protocol, likely served as inspiration
for the LSP. However, it is incompatible with the LSP. To address this, the I/O loop provided by
this plugin features a translation layer that converts all messages to and from the Tsserver format.
In summary, the architecture of this plugin can be visualized as shown in the diagram below:
NeoVim Tsserver Instance
┌────────────────────────────────────────────┐ ┌────────────────┐
│ │ │ │
│ LSP Handlers Tsserver LSP Loop │ │ │
│ ┌─────────┐ ┌──────────────────┐ │ │ │
│ │ │ │ │ │ │ │
│ │ │ Request │ ┌──────────────┐ │ │ │ │
│ │ ├───────────┤►│ Translation │ │ │ │ │
│ │ │ Response │ │ Layer │ │ │ │ │
│ │ ◄───────────┼─┤ │ │ │ │ │
│ │ │ │ └───┬─────▲────┘ │ │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ │ ┌───▼─────┴────┐ │ │ Request │ │
│ │ │ │ │ I/O Loop ├─┼─┼────────────► │
│ │ │ │ │ │ │ │ Response │ │
│ │ │ │ │ ◄─┼─┼────────────┤ │
│ │ │ │ └──────────────┘ │ │ │ │
│ │ │ │ │ │ │ │
│ └─────────┘ └──────────────────┘ │ │ │
│ │ │ │
└────────────────────────────────────────────┘ └────────────────┘
❗️ IMPORTANT: As mentioned earlier, this plugin serves as a replacement for
typescript-language-server, so you should remove thenvim-lspconfigsetup for it.
{
"pmizio/typescript-tools.nvim",
dependencies = { "nvim-lua/plenary.nvim", "neovim/nvim-lspconfig" },
opts = {},
}
use {
"pmizio/typescript-tools.nvim",
requires = { "nvim-lua/plenary.nvim" },
config = function()
require("typescript-tools").setup {}
end,
}
require("typescript-tools").setup {
on_attach = function() ... end,
handlers = { ... },
...
settings = {
-- spawn additional tsserver instance to calculate diagnostics on it
separate_diagnostic_server = true,
-- "change"|"insert_leave" determine when the client asks the server about diagnostic
publish_diagnostic_on = "insert_leave",
-- array of strings("fix_all"|"add_missing_imports"|"remove_unused"|
-- "remove_unused_imports"|"organize_imports") -- or string "all"
-- to include all supported code actions
-- specify commands exposed as code_actions
expose_as_code_action = {},
-- string|nil - specify a custom path to `tsserver.js` file, if this is nil or file under path
-- not exists then standard path resolution strategy is applied
tsserver_path = nil,
-- specify a list of plugins to load by tsserver, e.g., for support `styled-components`
-- (see 💅 `styled-components` support section)
tsserver_plugins = {},
-- this value is passed to: https://nodejs.org/api/cli.html#--max-old-space-sizesize-in-megabytes
-- memory limit in megabytes or "auto"(basically no limit)
tsserver_max_memory = "auto",
-- described below
tsserver_format_options = {},
tsserver_file_preferences = {},
-- locale of all tsserver messages, supported locales you can find here:
-- https://github.com/microsoft/TypeScript/blob/3c221fc086be52b19801f6e8d82596d04607ede6/src/compiler/utilitiesPublic.ts#L620
tsserver_locale = "en",
-- mirror of VSCode's `typescript.suggest.completeFunctionCalls`
complete_function_calls = false,
include_completions_with_insert_text = true,
-- CodeLens
-- WARNING: Experimental feature also in VSCode, because it might hit performance of server.
-- possible values: ("off"|"all"|"implementations_only"|"references_only")
code_lens = "off",
-- by default code lenses are displayed on all referencable values and for some of you it can
-- be too much this option reduce count of them by removing member references from lenses
disable_member_code_lens = true,
-- JSXCloseTag
-- WARNING: it is disabled by default (maybe you configuration or distro already uses nvim-ts-autotag,
-- that maybe have a conflict if enable this feature. )
jsx_close_tag = {
enable = false,
filetypes = { "javascriptreact", "typescriptreact" },
}
},
}
Note that handlers can be used to override certain LSP methods.
For example, you can use the filter_diagnostics helper to ignore specific errors:
local api = require("typescript-tools.api")
require("typescript-tools").setup {
handlers = {
["textDocument/publishDiagnostics"] = api.filter_diagnostics(
-- Ignore 'This may be converted to an async function' diagnostics.
{ 80006 }
),
},
}
You can also pass custom configuration options that will be passed to tsserver
instance. You can find available options in typescript repository (e.g.
for version 5.0.4 of typescript):
To pass those options to plugin pass them to the plugin setup function:
require("typescript-tools").setup {
settings = {
...
tsserver_file_preferences = {
includeInlayParameterNameHints = "all",
includeCompletionsForModuleExports = true,
quotePreference = "auto",
...
},
tsserver_format_options = {
allowIncompleteCompletions = false,
allowRenameOfImportPath = false,
...
}
},
}
If you want to make tsserver_format_options or tsserver_file_preferences filetype dependant you
need to may set them as functions returning tables eg.
require("typescript-tools").setup {
settings = {
...
tsserver_file_preferences = function(ft)
-- Some "ifology" using `ft` of opened file
return {
includeInlayParameterNameHints = "all",
includeCompletionsForModuleExports = true,
quotePreference = "auto",
...
}
end,
tsserver_format_options = function(ft)
-- Some "ifology" using `ft` of opened file
return {
allowIncompleteCompletions = false,
allowRenameOfImportPath = false,
...
}
end
},
}
The default values for preferences and format_options are in this file
styled-components support
To get IntelliSense for styled-components, you need to install the tsserver plugin
globally, which enables support for it:
npm i -g @styled/typescript-styled-plugin typescript-styled-plugin
Now, you need to load the plugin by modifying the settings object as follows:
require("typescript-tools").setup {
settings = {
...
tsserver_plugins = {
-- for TypeScript v4.9+
"@styled/typescript-styled-plugin",
-- or for older TypeScript versions
-- "typescript-styled-plugin",
},
},
}
This plugin provides several custom user commands (they are only applied to current buffer):
TSToolsOrganizeImports - sorts and removes unused importsTSToolsSortImports - sorts importsTSToolsRemoveUnusedImports - removes unused importsTSToolsRemoveUnused - removes all unused statementsTSToolsAddMissingImports - adds imports for all statements that lack one and can be importedTSToolsFixAll - fixes all fixable errorsTSToolsGoToSourceDefinition - goes to
source definition
(available since TS v4.7)TSToolsRenameFile - allow to rename current file and apply changes to connected filesTSToolsFileReferences - find files that reference the current file (available since TS v4.2)| Status | Request |
|---|---|
| ✅ | 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 (supported from TS v4.1) |
| ✅ | textDocument/inlayHint (supported from TS v4.4) |
| ✅ | callHierarchy/incomingCalls |
| ✅ | callHierarchy/outgoingCalls |
| ✅ | textDocument/codeLens |
| 🚧 | textDocument/linkedEditingRange (planned) |
| ✅ | workspace/symbol |
| ✅ | workspace/willRenameFiles |
| ❌ | workspace/applyEdit - N/A |
| ❌ | textDocument/declaration - N/A |
| ❌ | window/logMessage - N/A |
| ❌ | window/showMessage - N/A |
| ❌ | window/showMessageRequest - N/A |
Useful links:
The unit testing environment is automatically bootstrapped, just run:
make test
Or if you want to run a single test file:
make file=test_spec.lua test
(top 24 of 44)
964 followers · starred Jul 2024
106 followers · starred Jun 2023
556 followers · starred Sep 2024
328 followers · starred Jun 2023