# lsp: a Vim9 plugin that wires Vim to language servers you install yourself

> The lsp plugin for Vim 9 adds Language Server Protocol features such as completion, diagnostics, rename and hover to a stock Vim, but it ships no language servers and expects each one to be registered by hand with LspAddServer().

**yegappan/lsp** — Language Server Protocol (LSP) plugin for Vim9

- Repository: https://github.com/yegappan/lsp
- Stars: 786 · Forks: 106
- Language: Vim Script
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/yegappan-lsp

## A client for language servers, not a bundle of language servers

The plugin is described as a Language Server Protocol plugin for Vim, and the README is explicit about one boundary: you need to download and install one or more language servers corresponding to the programming languages you use, and the plugin does not install the language servers. The list of candidates lives at langserver.org, and picking from that list is the reader's first task.

That boundary defines the audience. This is for someone who already knows what a language server is and wants Vim to speak the protocol, rather than for someone looking for a batteries included IDE. The plugin is written using only the Vim9 script and requires Vim version 9.0 or above, so the floor is not negotiable. The repository layout backs this up: an autoload directory, ftplugin and plugin directories, syntax files, a doc directory and a test directory, all written in Vim9 script, with no compiled pieces or bundled binaries.

The repository carries an MIT licence and its last push was on 2026-10-15, with no GitHub releases published and no homepage listed. Activity is therefore visible on the main branch rather than in a tagged version stream, which matters if you pin plugins in a reproducible dotfiles repository.

## Cloning into the pack directory and adding one line to vimrc

The README gives a manual install that avoids any plugin manager. Clone the repository into the download directory of the Vim package system, then generate the help tags so that the plugin documentation is searchable:

```bash
git clone https://github.com/yegappan/lsp $HOME/.vim/pack/downloads/opt/lsp
vim -u NONE -c "helptags $HOME/.vim/pack/downloads/opt/lsp/doc" -c q
```

The second line is the part people skip. Running Vim with -u NONE and a helptags command over the doc directory writes the tag file that makes :help lsp-options and the rest of the help reachable. After the clone, activation is a single line in your $HOME/.vimrc:

```viml
packadd lsp
```

You should also see that the clone path matters: the pack path is what lets packadd lsp find the directory at all. If you clone somewhere else, packadd lsp will not find it and no LSP feature will appear.

## Plugin managers as an alternative to the manual clone

The manual steps are a fallback rather than the recommendation. The README states that the plugin can also be installed and managed using any one of the Vim plugin managers, naming dein.vim, pathogen, vam, vim-plug, volt and Vundle. Each of those handles the clone, the help tags and the activation line on its own, so the two command block above becomes unnecessary once one is in place.

There is a wrinkle for vim-plug users. The configuration section says that if you installed the LSP plugin with vim-plug, the steps are described later in that same section, which signals that the registration flow is described in a vim-plug specific way rather than the generic one.

Note what the plugin managers do not do here. They manage the Vim plugin, not the language server. A manager can fetch yegappan/lsp, but clangd, gopls, rust-analyzer and typescript-language-server still have to be installed on the machine by their own means, at paths you then spell out in the configuration.

## LspAddServer takes a list, and each entry needs a path and a filetype

Nothing happens until a language server is registered for a file type. The README says the servers are registered using the LspAddServer() function, which accepts a list of LSP servers, and each entry carries a set of fields. The Go example shows the shape, with a name, the filetype it handles, the absolute path to the executable, the command line arguments, and syncInit:

```viml
call LspAddServer([#{
	\    name: 'golang',
	\    filetype: ['go', 'gomod'],
	\    path: '/usr/local/bin/gopls',
	\    args: ['serve'],
	\    syncInit: v:true
	\  }])
```

The field list is documented as a table. filetype is one or more file types supported by the server, given as a String or a List, and a List is required when you want several. path is the complete path to the LSP server executable without any arguments. args is a list of command-line arguments passed to the server, each argument a separate List item. initializationOptions carries user provided options of any type, with the intelephense PHP language server given as the example of something that accepts a License Key among others. customNotificationHandlers and customRequestHandlers are dictionaries that add support for custom server notifications and requests. features is a dictionary of booleans that toggles what a given server provides, described as useful when running multiple servers in one buffer.

Registration is per file type, so a server that handles several languages needs its filetype list spelled out, and a path that does not exist on the machine will not produce a working server.

## LspOptionsSet holds the defaults for every buffer you open

Beyond server registration, the plugin exposes LspOptionsSet(), with the options documented under :help lsp-options. The README shows the configuration with default values, and the shape is instructive: a Vim9 dictionary of named settings, each either a boolean, a string, a number or a list.

Several defaults reveal how the plugin behaves by default. autoComplete is v:true while autoHighlight is v:false and autoHighlightDiags is v:true, so completion is offered but symbol highlighting is off. showInlayHints is v:false, onTypeFormatting is v:false, snippetSupport is v:false and ultisnipsSupport is v:false, which means several popular completion niceties are opt in. useBufferCompletion is v:false, leaving the question of where completion candidates come from to the configuration. maxDiagnostics is set to 200, a ceiling rather than an unlimited stream. There are also rendering controls such as diagVirtualTextAlign with a default of 'above', popupBorder with v:true, and the highlight groups popupHighlight, popupBorderHighlight and popupHighlightSignatureHelp, which tells you that the appearance is themed through standard Vim highlight groups rather than a bespoke style.

Because the defaults are documented in full, changing behaviour is mostly a matter of copying the dictionary and overriding single keys instead of rediscovering which option controls what.

## The feature list is wide, and each item maps to a server capability

The supported set is long, and reading it closely shows that the plugin is a protocol client rather than a set of Vim-native approximations. Code completion is listed first. Navigation covers jump to definition, declaration, implementation and type definition, plus peek variants of the same targets, find all symbol references, and document and workspace symbol search. Diagnostics show warning and error messages. Hover displays type and documentation, and signature help describes the call being typed. Rename symbol, code action, formatting and folding are all present.

The newer protocol capabilities are also claimed: call hierarchy, type hierarchy, inlay hints, visually select symbol block/region, and semantic highlight, alongside code outline and highlight current symbol references.

The important caveat sits underneath that list. Every one of these features is only as available as the language server you registered, and the features field lets you switch individual capabilities off per server, which is what the documentation means by running multiple servers in one buffer. A server that does not implement rename will not produce a rename, and the plugin cannot fill the gap on its own.

## Where this plugin is the wrong choice

Three situations rule it out. First, Vim 8 and older: the requirement is Vim version 9.0 or above and the code is written using only the Vim9 script, so there is no legacy path. Second, anyone who wants a single tool that also installs, updates and versions language servers, since the plugin deliberately leaves that out and points to langserver.org instead. Third, anyone who wants tagged releases, because the repository publishes no GitHub releases.

There is a smaller operational risk as well. Servers are registered by absolute path, so a machine with the server at a different location, or a container without it, simply has no server for that filetype. The plugin also lists customNotificationHandlers and customRequestHandlers as an extension point, which means unusual server specific behaviour is possible but is not covered by any documented default.

On upkeep and licensing, the licence is MIT, which is permissive and places no particular burden on a team shipping a dotfiles setup, and the last push was on 2026-10-15 with work on the main branch. Per server settings live in doc/configs.md, referenced from the README, so the details that differ between clangd, gopls and rust-analyzer are maintained alongside the plugin rather than in the top level configuration.

## Conclusion

Adopt this plugin if you edit a language that has a language server, you run Vim 9 or newer, and you would rather register servers explicitly in your vimrc than have an editor fetch and manage them for you. Do not adopt it if you need Vim 8 support, want one tool that installs servers, or expect a packaged release: the repository has no GitHub releases and the last push was on 2026-10-15. Before wiring it into a daily setup, check that the language server you want exposes a stdio command line, register it with LspAddServer(), and read doc/configs.md for the per server settings that the top level configuration does not cover.

## FAQ

### How do I install the lsp plugin for Vim?

The README gives a manual route: clone https://github.com/yegappan/lsp into $HOME/.vim/pack/downloads/opt/lsp, generate the help tags with vim -u NONE -c "helptags $HOME/.vim/pack/downloads/opt/lsp/doc" -c q, and add packadd lsp to your $HOME/.vimrc. The plugin can also be installed and managed with dein.vim, pathogen, vam, vim-plug, volt or Vundle.

### Does the lsp plugin install language servers for me?

No. The README states that you need to download and install one or more language servers for the languages you use, refers to the https://langserver.org/ page for the list, and says plainly that the plugin does not install the language servers.

### How do I register a language server such as gopls with the lsp plugin?

Use LspAddServer() with a list of dictionaries, giving the name, the filetype or list of filetypes it handles, the complete path to the executable, the args list, and options such as syncInit when needed. Per server details for language specific settings are documented in doc/configs.md.

### What Vim version does the lsp plugin require?

Vim version 9.0 or above, and the plugin is written using only the Vim9 script. There is no stated support for earlier Vim versions.

### Which LSP features does the lsp plugin support?

The README lists code completion, jump to definition, declaration, implementation and type definition, peek targets, diagnostics, symbol references, document and workspace symbol search, code outline, rename, hover, signature help, code action, call and type hierarchy, inlay hints, formatting, folding, semantic highlight and visual selection of a symbol block. Individual capabilities can be toggled per server through the features dictionary.

## Sources

- [Issues](https://github.com/yegappan/lsp/issues)
- [License: MIT](https://github.com/yegappan/lsp/blob/main/LICENSE)
- [README](https://github.com/yegappan/lsp/blob/main/README.md)
- [yegappan/lsp on GitHub](https://github.com/yegappan/lsp)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/yegappan-lsp
