From 0b0db777524f127f965768286623407f7ada5992 Mon Sep 17 00:00:00 2001 From: Illia Bobyr Date: Tue, 15 Aug 2023 00:05:41 -0700 Subject: [PATCH] LspStopServer: Stop all and stop specific It is convenient to be able to stop all LSP servers, regardless of the currently active buffer. Also, it seems confusing that when a server name is specified, it is only stopped if it is also one handling the current buffer type. I would imagine it is quite rare to have more than one server handing a specific buffer type. And if one explicitly specified a name, it seems reasonable to stop this particular server, regardless of the currently active buffer. --- autoload/lsp.vim | 24 ++++++++++++++++ autoload/lsp/ui/vim.vim | 62 ++++++++++++++++++++++++++++++++++++++--- doc/vim-lsp.txt | 29 +++++++++++++------ plugin/lsp.vim | 2 +- 4 files changed, 103 insertions(+), 14 deletions(-) diff --git a/autoload/lsp.vim b/autoload/lsp.vim index 65d79f301..0a981a1b8 100644 --- a/autoload/lsp.vim +++ b/autoload/lsp.vim @@ -95,6 +95,10 @@ function! lsp#get_server_names() abort return keys(s:servers) endfunction +function! lsp#is_valid_server_name(name) abort + return has_key(s:servers, a:name) +endfunction + function! lsp#get_server_info(server_name) abort return get(get(s:servers, a:server_name, {}), 'server_info', {}) endfunction @@ -128,6 +132,19 @@ function! s:server_status(server_name) abort return 'not running' endfunction +function! lsp#is_server_running(name) abort + if !has_key(s:servers, a:name) + return 0 + endif + + let l:server = s:servers[a:name] + + return has_key(l:server, 'init_result') + \ && !has_key(l:server, 'exited') + \ && !has_key(l:server, 'init_callbacks') + \ && !has_key(l:server, 'failed') +endfunction + " Returns the current status of all servers (if called with no arguments) or " the given server (if given an argument). Can be one of "unknown server", " "exited", "starting", "failed", "running", "not running" @@ -1329,6 +1346,13 @@ function! lsp#server_complete(lead, line, pos) abort return filter(sort(keys(s:servers)), 'stridx(v:val, a:lead)==0 && has_key(s:servers[v:val], "init_result")') endfunction +function! lsp#server_complete_running(lead, line, pos) abort + let l:all_servers = sort(keys(s:servers)) + return filter(l:all_servers, {idx, name -> + \ stridx(name, a:lead) == 0 && lsp#is_server_running(name) + \ }) +endfunction + function! lsp#_new_command() abort let s:last_command_id += 1 call lsp#stream(1, { 'command': 1 }) diff --git a/autoload/lsp/ui/vim.vim b/autoload/lsp/ui/vim.vim index 7ba5f6366..7c61e90e4 100644 --- a/autoload/lsp/ui/vim.vim +++ b/autoload/lsp/ui/vim.vim @@ -127,17 +127,71 @@ function! lsp#ui#vim#rename() abort call s:rename(l:server, input('new name: ', expand('')), lsp#get_position()) endfunction -function! lsp#ui#vim#stop_server(...) abort - let l:name = get(a:000, 0, '') - for l:server in lsp#get_allowed_servers() - if !empty(l:name) && l:server != l:name +function! s:stop_all_servers() abort + for l:server in lsp#get_server_names() + if !lsp#is_server_running(l:server) continue endif + echo 'Stopping' l:server 'server ...' call lsp#stop_server(l:server) endfor endfunction +function! s:stop_named_server(name) abort + if !lsp#is_valid_server_name(a:name) + call lsp#utils#warning('No LSP server named ' . a:name) + return + endif + + if lsp#is_server_running(a:name) + echo 'Stopping' a:name 'server ...' + call lsp#stop_server(a:name) + else + call lsp#utils#warning( + \ 'Server ' . a:name . ' is not running: ' + \ . lsp#get_server_status(a:name) + \ ) + endif +endfunction + +function! s:stop_buffer_servers() abort + let l:servers = lsp#get_allowed_servers() + let l:servers = + \ filter(l:servers, {idx, name -> lsp#is_server_running(name)}) + + if empty(l:servers) + call lsp#utils#warning('No active LSP servers for the current buffer') + return + endif + + for l:server in l:servers + echo 'Stopping' l:server 'server ...' + call lsp#stop_server(l:server) + endfor +endfunction + +function! lsp#ui#vim#stop_server(stop_all, name = '') abort + let l:stop_all = a:stop_all == '!' + + if l:stop_all + if !empty(a:name) + call lsp#utils#error( + \ '"!" stops all servers: name is ignored: ' . a:name) + endif + + call s:stop_all_servers() + return + endif + + if !empty(a:name) + call s:stop_named_server(a:name) + return + endif + + call s:stop_buffer_servers() +endfunction + function! lsp#ui#vim#workspace_symbol(query) abort let l:servers = filter(lsp#get_allowed_servers(), 'lsp#capabilities#has_workspace_symbol_provider(v:val)') let l:command_id = lsp#_new_command() diff --git a/doc/vim-lsp.txt b/doc/vim-lsp.txt index 57b549d6a..e8bf2659b 100644 --- a/doc/vim-lsp.txt +++ b/doc/vim-lsp.txt @@ -1909,17 +1909,28 @@ Prints the status of all registered servers. Use `:verbose LspStatus` to additionally show each server's workspace_config. See also |vim-lsp-healthcheck|. -LspStopServer [name] *:LspStopServer* +LspStopServer[!] [name] *:LspStopServer* -If 'name' is not specified, then all active servers that handle files matching -the current buffer type are stopped. This is often what you want. For -example, if you have multiple files of different types open, `LspStopServer` -will only stop the server for the current buffer. +:LspStopServer -When 'name' is provided, it acts as an additional restriction, only stopping -server that handles the current buffer type, if it also matches the specifie -name. 'name' value is compred to the 'name' property in the -|lsp#register_server()| call. +Stops all active servers that handle files matching the current buffer type +are stopped. This is often what you want. For example, if you have multiple +files of different types open, `LspStopServer` will only stop the server for +the current buffer. Shows an error if there are no active LSP servers for the +current buffer. + +:LspStopServer! + +Stops all active servers, regardless of the current buffer. Shows a message +for every stopped server. + +:LspStopServer name + +Stops a server named 'name', comparing the provided ID with the value of the +the 'name' property in the |lsp#register_server()| call. Shows an error if +'name' does not match a defined and currently running server. + +Completion should list only currently running servers for the 'name' argument. ============================================================================== Autocommands *vim-lsp-autocommands* diff --git a/plugin/lsp.vim b/plugin/lsp.vim index 1beea2425..0485b2b62 100644 --- a/plugin/lsp.vim +++ b/plugin/lsp.vim @@ -152,7 +152,7 @@ command! LspPeekImplementation call lsp#ui#vim#implementation(1) command! -nargs=0 LspStatus call lsp#print_server_status() command! LspNextReference call lsp#internal#document_highlight#jump(+1) command! LspPreviousReference call lsp#internal#document_highlight#jump(-1) -command! -nargs=? -complete=customlist,lsp#server_complete LspStopServer call lsp#ui#vim#stop_server() +command! -nargs=? -bang -complete=customlist,lsp#server_complete_running LspStopServer call lsp#ui#vim#stop_server("", ) command! -nargs=? -complete=customlist,lsp#utils#empty_complete LspSignatureHelp call lsp#ui#vim#signature_help#get_signature_help_under_cursor() command! LspDocumentFold call lsp#ui#vim#folding#fold(0) command! LspDocumentFoldSync call lsp#ui#vim#folding#fold(1)