A highly experimental LSP client for VIM using the builtin LSP channel mode.
Written in vim9script.
I just wanted to try out the new vim9script language, at the same time, wanted to challenge myself on building something
different/unique besides just building web applications.
At this moment, this plugin is just a toy project for me to play around with LSP and what features I could possibly implement/contribute to different plugins that already do something similar.
The aim for this LSP client is to be:
- Portable: use as much of built-in VIM features as possible, write any custom wrappers in case a feature is needed.
- Efficient: find ways to display important info and make it easy for the users to access this info.
- Aesthetics: make displaying info as aesthetically pleasing as possible but still out of the way of distractions if needed.
- Performance: not really a high aim for now, but eventually will get there in small increments.
- Server Initialization (
initializeandinitialized) - Server Shutdown (
shutdownandexit) - Dynamic Registration Capability
workspace/didChangeConfiguration
- Document updates
textDocument/didOpentextDocument/didChangetextDocument/didClosetextDocument/willSavetextDocument/didSave
- Language features
textDocument/publishDiagnosticstextDocument/declarationtextDocument/definitiontextDocument/typeDefinitiontextDocument/implementationtextDocument/referencestextDocument/documentHighlighttextDocument/hovertextDocument/codeLens(WIP)codeLens/resolve(WIP)
- Workspace features
workspace/configurationworkspace/didChangeConfigurationworkspace/workspaceFolders(WIP)
- Window features
window/showMessageRequest(WIP)window/showMessagewindow/logMessagewindow/workDoneProgress/create(WIP)window/workDoneProgress/cancel(WIP)
The following version and features are required, these can also be checked with :LSPClientCheckHealth:
- VIM v8.2.4758 and up or VIM 9 and up is required.
+channel+job+timers+popupwin
Plug 'creativenull/vim-lspclient'git clone https://github.com/creativenull/vim-lspclient.git ~/.vim/pack/creativenull/start/vim-lspclient
" Example keymaps
nmap <Leader>lgd <Plug>(lspclient_definition)
nmap <Leader>lge <Plug>(lspclient_declaration)
nmap <Leader>lgt <Plug>(lspclient_type_definition)
nmap <Leader>lgi <Plug>(lspclient_implementation)
nmap <Leader>lr <Plug>(lspclient_references)
nmap <Leader>lro <Plug>(lspclient_reference_next)
nmap <Leader>lri <Plug>(lspclient_reference_prev)
nmap <Leader>li <Plug>(lspclient_document_highlight)
nmap <Leader>ld <Plug>(lspclient_diagnostics)
nmap <Leader>ldo <Plug>(lspclient_diagnostic_next)
nmap <Leader>ldi <Plug>(lspclient_diagnostic_prev)
nmap <Leader>lw <Plug>(lspclient_diagnostic_hover)
nmap <Leader>lh <Plug>(lspclient_hover)Check logs with :LSPClientLog or vim +LSPClientLog (in terminal)
let g:lspclient_debug = 1Must have typescript-language-server installed globally with npm i -g typescript-language-server.
let s:tsserver = {}
let s:tsserver.name = 'tsserver'
let s:tsserver.cmd = ['typescript-language-server', '--stdio']
let s:tsserver.filetypes = ['typescript', 'typescriptreact', 'javascript', 'javascriptreact']
let s:tsserver.initOptions = { 'hostInfo': 'VIM 9' }
let s:tsserver.markers = ['tsconfig.json', 'jsconfig.json', 'package.json']
call lspclient#Create(s:tsserver)Must have vue-language-server installed globally with npm i -g @volar/vue-language-server
let s:volar = {}
let s:volar.name = 'volar'
let s:volar.cmd = ['vue-language-server', '--stdio']
let s:volar.filetypes = ['vue']
let s:volar.markers = ['package.json', 'vite.config.js', 'vite.config.ts']
" https://github.com/johnsoncodehk/volar/blob/d27d989355adc2aa3f9c6260226bd3167e3fac97/packages/shared/src/types.ts
let s:volar.initOptions = {
\ 'typescript': {
\ 'serverPath': lspclient#fs#GetProjectRoot('node_modules/typescript/lib/tsserverlibrary.js'),
\ },
\ 'documentFeatures': {
\ 'allowedLanguageIds': ['html', 'css', 'vue', 'typescript'],
\ 'selectionRange': v:true,
\ 'foldingRange': v:true,
\ 'linkedEditingRange': v:true,
\ 'documentSymbol': v:true,
\ 'documentColor': v:true,
\ 'documentFormatting': v:true,
\ },
\ 'languageFeatures': {
\ 'references': v:true,
\ 'implementation': v:true,
\ 'definition': v:true,
\ 'typeDefinition': v:true,
\ 'callHierarchy': v:true,
\ 'hover': v:true,
\ 'rename': v:true,
\ 'renameFileRefactoring': v:true,
\ 'signatrueHelp': v:true,
\ 'completion': {
\ 'defaultTagNameCase': 'both',
\ 'defaultAttrNameCase': 'kebabCase',
\ 'getDocumentNameCasesRequest': v:true,
\ 'getDocumentSelectionRequest': v:true,
\ },
\ 'documentHighlight': v:true,
\ 'documentLink': v:true,
\ 'workspaceSymbol': v:true,
\ 'codeLens': v:true,
\ 'semanticTokens': v:true,
\ 'codeAction': v:true,
\ 'inlayHints': v:false,
\ 'diagnostics': v:true,
\ 'schemaRequestService': v:true,
\ },
\ }
call lspclient#Create(s:volar)Must have deno installed globally.
let s:denols = {}
let s:denols.name = 'denols'
let s:denols.cmd = ['deno', 'lsp']
let s:denols.filetypes = ['typescript', 'typescriptreact', 'javascript', 'javascriptreact']
let s:denols.settings = { 'enable': v:true, 'unstable': v:true }
let s:denols.markers = ['deno.json', 'deno.jsonc']
call lspclient#Create(s:denols)Must have rust-analyzer installed globally.
let s:rust_analyzer = {}
let s:rust_analyzer.name = 'rust_analyzer'
let s:rust_analyzer.cmd = ['rust-analyzer']
let s:rust_analyzer.filetypes = ['rust']
let s:rust_analyzer.markers = ['Cargo.toml']
call lspclient#Create(s:rust_analyzer)Must have gopls installed globally.
let s:gopls = {}
let s:gopls.name = 'gopls'
let s:gopls.cmd = ['gopls']
let s:gopls.filetypes = ['go', 'gomod']
let s:gopls.markers = ['go.mod']
call lspclient#Create(s:gopls)