Add a command for stopping all LSP clients

This commit is contained in:
w0rp 2018-03-06 10:23:49 +00:00
parent b7363bef7d
commit 0a0535546f
7 changed files with 153 additions and 4 deletions

View File

@ -19,6 +19,10 @@ function! ale#definition#Execute(expr) abort
execute a:expr execute a:expr
endfunction endfunction
function! ale#definition#ClearLSPData() abort
let s:go_to_definition_map = {}
endfunction
function! ale#definition#Open(options, filename, line, column) abort function! ale#definition#Open(options, filename, line, column) abort
if a:options.open_in_tab if a:options.open_in_tab
call ale#definition#Execute('tabedit ' . fnameescape(a:filename)) call ale#definition#Execute('tabedit ' . fnameescape(a:filename))

View File

@ -76,6 +76,11 @@ function! ale#engine#InitBufferInfo(buffer) abort
return 0 return 0
endfunction endfunction
" Clear LSP linter data for the linting engine.
function! ale#engine#ClearLSPData() abort
let s:lsp_linter_map = {}
endfunction
" This function is documented and part of the public API. " This function is documented and part of the public API.
" "
" Return 1 if ALE is busy checking a given buffer " Return 1 if ALE is busy checking a given buffer
@ -144,7 +149,7 @@ function! s:GatherOutput(job_id, line) abort
endif endif
endfunction endfunction
function! s:HandleLoclist(linter_name, buffer, loclist) abort function! ale#engine#HandleLoclist(linter_name, buffer, loclist) abort
let l:info = get(g:ale_buffer_info, a:buffer, {}) let l:info = get(g:ale_buffer_info, a:buffer, {})
if empty(l:info) if empty(l:info)
@ -223,7 +228,7 @@ function! s:HandleExit(job_id, exit_code) abort
let l:loclist = ale#util#GetFunction(l:linter.callback)(l:buffer, l:output) let l:loclist = ale#util#GetFunction(l:linter.callback)(l:buffer, l:output)
call s:HandleLoclist(l:linter.name, l:buffer, l:loclist) call ale#engine#HandleLoclist(l:linter.name, l:buffer, l:loclist)
endfunction endfunction
function! s:HandleLSPDiagnostics(conn_id, response) abort function! s:HandleLSPDiagnostics(conn_id, response) abort
@ -237,7 +242,7 @@ function! s:HandleLSPDiagnostics(conn_id, response) abort
let l:loclist = ale#lsp#response#ReadDiagnostics(a:response) let l:loclist = ale#lsp#response#ReadDiagnostics(a:response)
call s:HandleLoclist(l:linter_name, l:buffer, l:loclist) call ale#engine#HandleLoclist(l:linter_name, l:buffer, l:loclist)
endfunction endfunction
function! s:HandleTSServerDiagnostics(response, error_type) abort function! s:HandleTSServerDiagnostics(response, error_type) abort
@ -262,7 +267,7 @@ function! s:HandleTSServerDiagnostics(response, error_type) abort
let l:loclist = get(l:info, 'semantic_loclist', []) let l:loclist = get(l:info, 'semantic_loclist', [])
\ + get(l:info, 'syntax_loclist', []) \ + get(l:info, 'syntax_loclist', [])
call s:HandleLoclist('tsserver', l:buffer, l:loclist) call ale#engine#HandleLoclist('tsserver', l:buffer, l:loclist)
endfunction endfunction
function! s:HandleLSPErrorMessage(error_message) abort function! s:HandleLSPErrorMessage(error_message) abort

View File

@ -325,6 +325,20 @@ function! ale#lsp#ConnectToAddress(address, project_root, callback) abort
return 1 return 1
endfunction endfunction
" Stop all LSP connections, closing all jobs and channels, and removing any
" queued messages.
function! ale#lsp#StopAll() abort
for l:conn in s:connections
if has_key(l:conn, 'channel')
call ch_close(l:conn.channel)
else
call ale#job#Stop(l:conn.id)
endif
endfor
let s:connections = []
endfunction
function! s:SendMessageData(conn, data) abort function! s:SendMessageData(conn, data) abort
if has_key(a:conn, 'executable') if has_key(a:conn, 'executable')
call ale#job#SendRaw(a:conn.id, a:data) call ale#job#SendRaw(a:conn.id, a:data)

View File

@ -0,0 +1,25 @@
" Stop all LSPs and remove all of the data for them.
function! ale#lsp#reset#StopAllLSPs() abort
call ale#lsp#StopAll()
if exists('*ale#definition#ClearLSPData')
" Clear the mapping for connections, etc.
call ale#definition#ClearLSPData()
endif
if exists('*ale#engine#ClearLSPData')
" Clear the mapping for connections, etc.
call ale#engine#ClearLSPData()
" Remove the problems for all of the LSP linters in every buffer.
for l:buffer_string in keys(g:ale_buffer_info)
let l:buffer = str2nr(l:buffer_string)
for l:linter in ale#linter#Get(getbufvar(l:buffer, '&filetype'))
if !empty(l:linter.lsp)
call ale#engine#HandleLoclist(l:linter.name, l:buffer, [])
endif
endfor
endfor
endif
endfunction

View File

@ -1871,6 +1871,15 @@ ALEResetBuffer *ALEResetBuffer*
|ALEDisableBuffer|. |ALEDisableBuffer|.
ALEStopAllLSPs *ALEStopAllLSPs*
`ALEStopAllLSPs` will close and stop all channels and jobs for all LSP-like
clients, including tsserver, remove all of the data stored for them, and
delete all of the problems found for them, updating every linted buffer.
This command can be used when LSP clients mess up and need to be restarted.
=============================================================================== ===============================================================================
9. API *ale-api* 9. API *ale-api*

View File

@ -249,6 +249,8 @@ command! -bar ALEToggleBuffer :call ale#toggle#ToggleBuffer(bufnr(''))
command! -bar ALEEnableBuffer :call ale#toggle#EnableBuffer(bufnr('')) command! -bar ALEEnableBuffer :call ale#toggle#EnableBuffer(bufnr(''))
command! -bar ALEDisableBuffer :call ale#toggle#DisableBuffer(bufnr('')) command! -bar ALEDisableBuffer :call ale#toggle#DisableBuffer(bufnr(''))
command! -bar ALEResetBuffer :call ale#toggle#ResetBuffer(bufnr('')) command! -bar ALEResetBuffer :call ale#toggle#ResetBuffer(bufnr(''))
" A command to stop all LSP-like clients, including tsserver.
command! -bar ALEStopAllLSPs :call ale#lsp#reset#StopAllLSPs()
" A command for linting manually. " A command for linting manually.
command! -bar ALELint :call ale#Queue(0, 'lint_file') command! -bar ALELint :call ale#Queue(0, 'lint_file')

View File

@ -0,0 +1,90 @@
Before:
Save g:ale_enabled
Save g:ale_set_signs
Save g:ale_set_quickfix
Save g:ale_set_loclist
Save g:ale_set_highlights
Save g:ale_echo_cursor
let g:ale_enabled = 0
let g:ale_set_signs = 0
let g:ale_set_quickfix = 0
let g:ale_set_loclist = 0
let g:ale_set_highlights = 0
let g:ale_echo_cursor = 0
function EmptyString() abort
return ''
endfunction
call ale#engine#InitBufferInfo(bufnr(''))
call ale#linter#Define('testft', {
\ 'name': 'lsplinter',
\ 'lsp': 'tsserver',
\ 'executable_callback': 'EmptyString',
\ 'command_callback': 'EmptyString',
\ 'project_root_callback': 'EmptyString',
\ 'language_callback': 'EmptyString',
\})
call ale#linter#Define('testft', {
\ 'name': 'otherlinter',
\ 'callback': 'TestCallback',
\ 'executable': has('win32') ? 'cmd': 'true',
\ 'command': 'true',
\ 'read_buffer': 0,
\})
After:
Restore
unlet! b:ale_save_event_fired
delfunction EmptyString
call ale#linter#Reset()
Given testft(Some file with an imaginary filetype):
Execute(ALEStopAllLSPs should clear the loclist):
let g:ale_buffer_info[bufnr('')].loclist = [
\ {
\ 'text': 'a',
\ 'lnum': 10,
\ 'col': 0,
\ 'bufnr': bufnr(''),
\ 'vcol': 0,
\ 'type': 'E',
\ 'nr': -1,
\ 'linter_name': 'lsplinter',
\ },
\ {
\ 'text': 'a',
\ 'lnum': 10,
\ 'col': 0,
\ 'bufnr': bufnr(''),
\ 'vcol': 0,
\ 'type': 'E',
\ 'nr': -1,
\ 'linter_name': 'otherlinter',
\ },
\]
let g:ale_buffer_info[bufnr('')].active_linter_list = ['lsplinter', 'otherlinter']
ALEStopAllLSPs
" The loclist should be updated.
AssertEqual g:ale_buffer_info[bufnr('')].loclist, [
\ {
\ 'text': 'a',
\ 'lnum': 10,
\ 'col': 0,
\ 'bufnr': bufnr(''),
\ 'vcol': 0,
\ 'type': 'E',
\ 'nr': -1,
\ 'linter_name': 'otherlinter',
\ },
\]
" The LSP linter should be removed from the active linter list.
AssertEqual g:ale_buffer_info[bufnr('')].active_linter_list, ['otherlinter']