From 876fe5981241e145799ecd98c25ecd124f4fc927 Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Mon, 10 Aug 2020 13:59:51 -0600 Subject: [PATCH 1/6] Remove redundant call to mapKeys() This is called in the onOpen function two lines later. Besides, we don't want to map the keys until after we check if the current filetype is active. --- plugin/lsc.vim | 1 - 1 file changed, 1 deletion(-) diff --git a/plugin/lsc.vim b/plugin/lsc.vim index 33948742..c45711c5 100644 --- a/plugin/lsc.vim +++ b/plugin/lsc.vim @@ -159,7 +159,6 @@ endfunction function! s:OnOpen() abort if !has_key(g:lsc_servers_by_filetype, &filetype) | return | endif - call lsc#config#mapKeys() if !lsc#server#filetypeActive(&filetype) | return | endif call lsc#file#onOpen() endfunction From a5a8cfc080a1e10bdf2a2c2bf0e4bc1f919ccdeb Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Mon, 10 Aug 2020 14:30:16 -0600 Subject: [PATCH 2/6] Only map keys when server is running --- autoload/lsc/file.vim | 1 - autoload/lsc/server.vim | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/autoload/lsc/file.vim b/autoload/lsc/file.vim index 2f295cb1..c6eed2e5 100644 --- a/autoload/lsc/file.vim +++ b/autoload/lsc/file.vim @@ -22,7 +22,6 @@ endfunction " Run language servers for this filetype if they aren't already running and " flush file changes. function! lsc#file#onOpen() abort - call lsc#config#mapKeys() if &modifiable && expand('%') !~# '\vfugitive:///' call lsc#server#start(&filetype) call s:FlushChanges(lsc#file#fullPath(), &filetype) diff --git a/autoload/lsc/server.vim b/autoload/lsc/server.vim index 93a1fd9d..faeb0fab 100644 --- a/autoload/lsc/server.vim +++ b/autoload/lsc/server.vim @@ -119,6 +119,7 @@ endfunction function! s:Start(server) abort if has_key(a:server, '_channel') " Server is already running + call lsc#config#mapKeys() return endif let l:command = a:server.config.command @@ -145,6 +146,7 @@ function! s:Start(server) abort for filetype in a:server.filetypes call lsc#file#trackAll(filetype) endfor + call lsc#config#mapKeys() endfunction if exists('g:lsc_trace_level') && \ index(['off', 'messages', 'verbose'], g:lsc_trace_level) >= 0 From 6f05784276168f1de0afbce39847ed96aad66044 Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Mon, 10 Aug 2020 14:30:30 -0600 Subject: [PATCH 3/6] Unmap keys when server shuts down --- autoload/lsc/config.vim | 61 ++++++++++++++++++++++++++++++++--------- autoload/lsc/server.vim | 1 + 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/autoload/lsc/config.vim b/autoload/lsc/config.vim index 316ecd21..bb0563e8 100644 --- a/autoload/lsc/config.vim +++ b/autoload/lsc/config.vim @@ -39,19 +39,8 @@ function! s:ApplyDefaults(config) abort return l:merged endfunction -function! lsc#config#mapKeys() abort - if !exists('g:lsc_auto_map') - \ || (type(g:lsc_auto_map) == type(v:true) && !g:lsc_auto_map) - \ || (type(g:lsc_auto_map) == type(0) && !g:lsc_auto_map) - return - endif - let l:maps = s:ApplyDefaults(g:lsc_auto_map) - if type(l:maps) != type({}) - call lsc#message#error('g:lsc_auto_map must be a bool or dict') - return - endif - - for command in [ +function! s:CommandList() abort + return [ \ 'GoToDefinition', \ 'GoToDefinitionSplit', \ 'FindReferences', @@ -64,6 +53,22 @@ function! lsc#config#mapKeys() abort \ 'WorkspaceSymbol', \ 'SignatureHelp', \] + (get(g:, 'lsc_enable_apply_edit', 1) ? ['Rename'] : []) +endfunction + +function! lsc#config#mapKeys() abort + if !exists('g:lsc_auto_map') + \ || (type(g:lsc_auto_map) == type(v:true) && !g:lsc_auto_map) + \ || (type(g:lsc_auto_map) == type(0) && !g:lsc_auto_map) + return + endif + let l:maps = s:ApplyDefaults(g:lsc_auto_map) + if type(l:maps) != type({}) + call lsc#message#error('g:lsc_auto_map must be a bool or dict') + return + endif + + let b:lsc_save = {} + for command in s:CommandList() let lhs = get(l:maps, command, []) if type(lhs) != type('') && type(lhs) != type([]) continue @@ -75,18 +80,48 @@ function! lsc#config#mapKeys() abort if has_key(l:maps, 'Completion') && \ type(l:maps['Completion']) == type('') && \ len(l:maps['Completion']) > 0 + let b:lsc_save[l:maps['Completion']] = getbufvar('', l:maps['Completion']) execute 'setlocal '.l:maps['Completion'].'=lsc#complete#complete' endif if has_key(l:maps, 'ShowHover') let l:show_hover = l:maps['ShowHover'] if type(l:show_hover) == type(v:true) || type(l:show_hover) == type(0) if l:show_hover + let b:lsc_save.keywordprg = &l:keywordprg setlocal keywordprg=:LSClientShowHover endif endif endif endfunction +function! lsc#config#unmapKeys() abort + if exists('b:lsc_save') + for opt in keys(b:lsc_save) + execute 'setlocal '.opt.'='.b:lsc_save[opt] + endfor + unlet b:lsc_save + endif + + if !exists('g:lsc_auto_map') + \ || (type(g:lsc_auto_map) == type(v:true) && !g:lsc_auto_map) + \ || (type(g:lsc_auto_map) == type(0) && !g:lsc_auto_map) + return + endif + let l:maps = s:ApplyDefaults(g:lsc_auto_map) + + for command in s:CommandList() + let lhs = get(l:maps, command, []) + if type(lhs) != type('') && type(lhs) != type([]) + continue + endif + for m in type(lhs) == type([]) ? lhs : [lhs] + if get(maparg(m, 'n', v:false, v:true), 'buffer') + execute 'nunmap '.m + endif + endfor + endfor +endfunction + " Wraps [Callback] with a function that will first translate a result through a " user provided translation. function! lsc#config#responseHook(server, method, Callback) abort diff --git a/autoload/lsc/server.vim b/autoload/lsc/server.vim index faeb0fab..8aed5658 100644 --- a/autoload/lsc/server.vim +++ b/autoload/lsc/server.vim @@ -87,6 +87,7 @@ function! s:Kill(server, status, OnExit) abort call a:server._channel.notify('exit', v:null) endif if a:OnExit != v:null | call a:OnExit() | endif + call lsc#config#unmapKeys() endfunction return a:server.request('shutdown', v:null, funcref('Exit')) endfunction From c8248dc9b64e87d95920ad794edf4c2f7f2c3450 Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Mon, 5 Oct 2020 12:36:18 -0600 Subject: [PATCH 4/6] Save mapped keys to buffer-local variable This allows keys to be unmapped much easier by simply iterating through the list of keys that have been mapped. --- autoload/lsc/config.vim | 53 ++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 33 deletions(-) diff --git a/autoload/lsc/config.vim b/autoload/lsc/config.vim index bb0563e8..a38b2fac 100644 --- a/autoload/lsc/config.vim +++ b/autoload/lsc/config.vim @@ -39,22 +39,6 @@ function! s:ApplyDefaults(config) abort return l:merged endfunction -function! s:CommandList() abort - return [ - \ 'GoToDefinition', - \ 'GoToDefinitionSplit', - \ 'FindReferences', - \ 'NextReference', - \ 'PreviousReference', - \ 'FindImplementations', - \ 'FindCodeActions', - \ 'ShowHover', - \ 'DocumentSymbol', - \ 'WorkspaceSymbol', - \ 'SignatureHelp', - \] + (get(g:, 'lsc_enable_apply_edit', 1) ? ['Rename'] : []) -endfunction - function! lsc#config#mapKeys() abort if !exists('g:lsc_auto_map') \ || (type(g:lsc_auto_map) == type(v:true) && !g:lsc_auto_map) @@ -68,12 +52,26 @@ function! lsc#config#mapKeys() abort endif let b:lsc_save = {} - for command in s:CommandList() + let b:lsc_maps = [] + for command in [ + \ 'GoToDefinition', + \ 'GoToDefinitionSplit', + \ 'FindReferences', + \ 'NextReference', + \ 'PreviousReference', + \ 'FindImplementations', + \ 'FindCodeActions', + \ 'ShowHover', + \ 'DocumentSymbol', + \ 'WorkspaceSymbol', + \ 'SignatureHelp', + \] + (get(g:, 'lsc_enable_apply_edit', 1) ? ['Rename'] : []) let lhs = get(l:maps, command, []) if type(lhs) != type('') && type(lhs) != type([]) continue endif for m in type(lhs) == type([]) ? lhs : [lhs] + call add(b:lsc_maps, m) execute 'nnoremap '.m.' :LSClient'.command.'' endfor endfor @@ -102,24 +100,13 @@ function! lsc#config#unmapKeys() abort unlet b:lsc_save endif - if !exists('g:lsc_auto_map') - \ || (type(g:lsc_auto_map) == type(v:true) && !g:lsc_auto_map) - \ || (type(g:lsc_auto_map) == type(0) && !g:lsc_auto_map) - return + if exists('b:lsc_maps') + for m in b:lsc_maps + silent! execute 'nunmap '.m + endfor + unlet b:lsc_maps endif - let l:maps = s:ApplyDefaults(g:lsc_auto_map) - for command in s:CommandList() - let lhs = get(l:maps, command, []) - if type(lhs) != type('') && type(lhs) != type([]) - continue - endif - for m in type(lhs) == type([]) ? lhs : [lhs] - if get(maparg(m, 'n', v:false, v:true), 'buffer') - execute 'nunmap '.m - endif - endfor - endfor endfunction " Wraps [Callback] with a function that will first translate a result through a From 6d437f48be482dd06b702373888a80dbfd37f8d8 Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Mon, 5 Oct 2020 12:36:58 -0600 Subject: [PATCH 5/6] Only unmap keys if server is used by current buffer --- autoload/lsc/server.vim | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/autoload/lsc/server.vim b/autoload/lsc/server.vim index 8aed5658..d7f30353 100644 --- a/autoload/lsc/server.vim +++ b/autoload/lsc/server.vim @@ -87,7 +87,11 @@ function! s:Kill(server, status, OnExit) abort call a:server._channel.notify('exit', v:null) endif if a:OnExit != v:null | call a:OnExit() | endif - call lsc#config#unmapKeys() + + " Unmap keys if the language server is used in the current buffer + if index(a:server.filetypes, &filetype) >= 0 + call lsc#config#unmapKeys() + endif endfunction return a:server.request('shutdown', v:null, funcref('Exit')) endfunction From 19e4e6cf57d32943f273c5eca9944f1036ec74ef Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Mon, 5 Oct 2020 12:37:28 -0600 Subject: [PATCH 6/6] Check server status and unmap keys if not running When a language server exits for any reason, we want to unmap the vim-lsc mappings in all of its corresponding buffers (so that we don't have "dead" mappings lying around). To do this, we can either 1. Iterate through all open buffers and unmap buffer-local mappings whenever the server quits 2. Unmap buffer-local mappings on-demand when the buffer is opened, if the server is no longer running Option 2 is the better choice (and is what this commit implements) as it's faster and leaner (iterating through all open buffers and removing mappings can be *very* slow if there are a lot of buffers open). --- autoload/lsc/config.vim | 6 ++++++ plugin/lsc.vim | 1 + 2 files changed, 7 insertions(+) diff --git a/autoload/lsc/config.vim b/autoload/lsc/config.vim index a38b2fac..b6f1038d 100644 --- a/autoload/lsc/config.vim +++ b/autoload/lsc/config.vim @@ -106,7 +106,13 @@ function! lsc#config#unmapKeys() abort endfor unlet b:lsc_maps endif +endfunction +" Unmap buffer-local keys if the associated language server is not running +function! lsc#config#checkKeys() abort + if lsc#server#status(&filetype) !=# 'running' + call lsc#config#unmapKeys() + endif endfunction " Wraps [Callback] with a function that will first translate a result through a diff --git a/plugin/lsc.vim b/plugin/lsc.vim index c45711c5..1e4b8497 100644 --- a/plugin/lsc.vim +++ b/plugin/lsc.vim @@ -145,6 +145,7 @@ function! LSCEnsureCurrentWindowState() abort call lsc#diagnostics#updateLocationList(lsc#file#fullPath()) call lsc#highlights#update() call lsc#cursor#onWinEnter() + call lsc#config#checkKeys() endfunction " Run `function` if LSC is enabled for the current filetype.