Awesome
<h1 align="center">typescript-tools.nvim</h1> <p align="center"><sup>ā” TypeScript integration NeoVim deserves ā”</sup></p>š§ Warning š§
Please note that the plugin is currently in the early beta version, which means you may encounter bugs.
āļø Why?
- Drop in, pure lua replacement for
typescript-language-server
- If you work on a large TS/JS project, you probably understand why this plugin came into existence.
The
typescript-language-server
can be extremely slow in such projects, and it often fails to provide accurate completions or just crash.
āØ Features
- ā” Blazingly fast, thanks to the utilization of the native Tsserver communication protocol, similar to Visual Studio Code
- šŖ Supports a wide range of TypeScript versions 4.0 and above
- š Supports the nvim LSP plugin ecosystem
- š Supports multiple instances of Tsserver
- š» Supports both local and global installations of TypeScript
- šØ Supports
tsserver
installed from Mason - š Provides out-of-the-box support for styled-components, which is not enabled by default (see Installation and Configuration)
- āØ Improved code refactor capabilities e.g. extracting to variable or function
š How it works?
<details> <summary> If you're interested in learning more about the technical details of the plugin, you can click here. </summary> <p> <br> 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. </p>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 ā ā
ā ā ā ā ā āāā¼āā¼āāāāāāāāāāāāā¤ ā
ā ā ā ā āāāāāāāāāāāāāāāā ā ā ā ā
ā ā ā ā ā ā ā ā
ā āāāāāāāāāāā āāāāāāāāāāāāāāāāāāāā ā ā ā
ā ā ā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāā
</details>
š¦ Installation
āļø IMPORTANT: As mentioned earlier, this plugin serves as a replacement for
typescript-language-server
, so you should remove thenvim-lspconfig
setup for it.
ā”ļø Requirements
- NeoVim >= 0.8.0
- nvim-lspconfig
- plenary.nvim
- TypeScript >= 4.0
- Node supported suitable for TypeScript version you use
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,
}
āļø Configuration
The parameters passed into the setup
function are also passed to the standard nvim-lspconfig
server setup
, allowing you to use the same settings here.
But you can pass plugin-specific options through the settings
parameter, which defaults to:
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
},
}
</p>
</details>
The default values for preferences
and format_options
are in this file
š
styled-components
support
<details>
<summary>Show more</summary>
<p>
<br>
To get IntelliSense for <code>styled-components</code>, you need to install the tsserver plugin
globally, which enables support for it:
</p>
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",
},
},
}
</details>
Custom user commands
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)
Supported LSP methods
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 |
š¦ Roadmap
šØ Development
Useful links:
š Run tests
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
š Credits
- null-ls.nvim - for the idea to monkeypatch nvim API to start a custom LSP I/O loop
- typescript-language-server - for ideas on how to translate certain Tsserver responses
- Visual Studio Code(TypeScript extension) - for insights on using the Tsserver protocol and performance optimizations