#517 Add more code LSP support which makes the tssserver linter behave more like the LSP linters

This commit is contained in:
w0rp
2017-07-26 10:37:37 +01:00
parent 86297a7c65
commit cd860e3e8d
16 changed files with 485 additions and 169 deletions

View File

@@ -31,13 +31,15 @@ endfunction
function! ale#engine#InitBufferInfo(buffer) abort
if !has_key(g:ale_buffer_info, a:buffer)
" job_list will hold the list of jobs
" job_list will hold the list of job IDs
" active_linter_list will hold the list of active linter names
" loclist holds the loclist items after all jobs have completed.
" temporary_file_list holds temporary files to be cleaned up
" temporary_directory_list holds temporary directories to be cleaned up
" history holds a list of previously run commands for this buffer
let g:ale_buffer_info[a:buffer] = {
\ 'job_list': [],
\ 'active_linter_list': [],
\ 'loclist': [],
\ 'temporary_file_list': [],
\ 'temporary_directory_list': [],
@@ -114,6 +116,16 @@ function! s:GatherOutput(job_id, line) abort
endfunction
function! s:HandleLoclist(linter_name, buffer, loclist) abort
let l:buffer_info = get(g:ale_buffer_info, a:buffer, {})
if empty(l:buffer_info)
return
endif
" Remove this linter from the list of active linters.
" This may have already been done when the job exits.
call filter(l:buffer_info.active_linter_list, 'v:val !=# a:linter_name')
" Make some adjustments to the loclists to fix common problems, and also
" to set default values for loclist items.
let l:linter_loclist = ale#engine#FixLocList(a:buffer, a:linter_name, a:loclist)
@@ -154,6 +166,7 @@ function! s:HandleExit(job_id, exit_code) abort
call ale#job#Stop(a:job_id)
call remove(s:job_info_map, a:job_id)
call filter(g:ale_buffer_info[l:buffer].job_list, 'v:val !=# a:job_id')
call filter(g:ale_buffer_info[l:buffer].active_linter_list, 'v:val !=# l:linter.name')
" Stop here if we land in the handle for a job completing if we're in
" a sandbox.
@@ -180,29 +193,32 @@ function! s:HandleExit(job_id, exit_code) abort
call s:HandleLoclist(l:linter.name, l:buffer, l:loclist)
endfunction
function! s:HandleLSPResponse(response) abort
let l:is_diag_response = get(a:response, 'type', '') ==# 'event'
\ && get(a:response, 'event', '') ==# 'semanticDiag'
function! s:HandleLSPDiagnostics(response) abort
let l:filename = ale#path#FromURI(a:response.params.uri)
let l:buffer = bufnr(l:filename)
let l:loclist = ale#lsp#response#ReadDiagnostics(a:response)
if !l:is_diag_response
return
endif
call s:HandleLoclist('langserver', l:buffer, l:loclist)
endfunction
function! s:HandleTSServerDiagnostics(response) abort
let l:buffer = bufnr(a:response.body.file)
let l:info = get(g:ale_buffer_info, l:buffer, {})
if empty(l:info)
return
endif
let l:info.waiting_for_tsserver = 0
let l:loclist = ale#lsp#response#ReadTSServerDiagnostics(a:response)
call s:HandleLoclist('tsserver', l:buffer, l:loclist)
endfunction
function! s:HandleLSPResponse(response) abort
let l:method = get(a:response, 'method', '')
if l:method ==# 'textDocument/publishDiagnostics'
call s:HandleLSPDiagnostics(a:response)
elseif get(a:response, 'type', '') ==# 'event'
\&& get(a:response, 'event', '') ==# 'semanticDiag'
call s:HandleTSServerDiagnostics(a:response)
endif
endfunction
function! ale#engine#SetResults(buffer, loclist) abort
let l:linting_is_done = !ale#engine#IsCheckingBuffer(a:buffer)
@@ -430,6 +446,7 @@ function! s:RunJob(options) abort
if l:job_id
" Add the job to the list of jobs, so we can track them.
call add(g:ale_buffer_info[l:buffer].job_list, l:job_id)
call add(g:ale_buffer_info[l:buffer].active_linter_list, l:linter.name)
let l:status = 'started'
" Store the ID for the job in the map to read back again.
@@ -555,41 +572,27 @@ function! s:StopCurrentJobs(buffer, include_lint_file_jobs) abort
let l:info.job_list = l:new_job_list
endfunction
function! s:CheckWithTSServer(buffer, linter, executable) abort
let l:info = g:ale_buffer_info[a:buffer]
let l:command = ale#job#PrepareCommand(
\ ale#linter#GetCommand(a:buffer, a:linter),
\)
let l:id = ale#lsp#StartProgram(
\ a:executable,
\ l:command,
function! s:CheckWithLSP(buffer, linter) abort
let l:lsp_details = ale#linter#StartLSP(
\ a:buffer,
\ a:linter,
\ function('s:HandleLSPResponse'),
\)
if !l:id
if g:ale_history_enabled
call ale#history#Add(a:buffer, 'failed', l:id, l:command)
endif
if empty(l:lsp_details)
return 0
endif
if ale#lsp#OpenTSServerDocumentIfNeeded(l:id, a:buffer)
if g:ale_history_enabled
call ale#history#Add(a:buffer, 'started', l:id, l:command)
endif
endif
let l:id = l:lsp_details.connection_id
let l:root = l:lsp_details.project_root
call ale#lsp#Send(l:id, ale#lsp#tsserver_message#Change(a:buffer))
let l:request_id = ale#lsp#Send(
\ l:id,
\ ale#lsp#tsserver_message#Geterr(a:buffer),
\)
let l:change_message = a:linter.lsp ==# 'tsserver'
\ ? ale#lsp#tsserver_message#Geterr(a:buffer)
\ : ale#lsp#message#DidChange(a:buffer)
let l:request_id = ale#lsp#Send(l:id, l:change_message, l:root)
if l:request_id != 0
let l:info.waiting_for_tsserver = 1
call add(g:ale_buffer_info[a:buffer].active_linter_list, a:linter.name)
endif
return l:request_id != 0
@@ -614,15 +617,12 @@ endfunction
"
" Returns 1 if the linter was successfully run.
function! s:RunLinter(buffer, linter) abort
if empty(a:linter.lsp) || a:linter.lsp ==# 'tsserver'
if !empty(a:linter.lsp) || a:linter.lsp ==# 'tsserver'
return s:CheckWithLSP(a:buffer, a:linter)
else
let l:executable = ale#linter#GetExecutable(a:buffer, a:linter)
" Run this program if it can be executed.
if s:IsExecutable(l:executable)
if a:linter.lsp ==# 'tsserver'
return s:CheckWithTSServer(a:buffer, a:linter, l:executable)
endif
return s:InvokeChain(a:buffer, a:linter, 0, [])
endif
endif