mirror of
https://github.com/dense-analysis/ale.git
synced 2026-02-17 23:44:17 +08:00
Add tsserver support
This commit is contained in:
@@ -11,6 +11,15 @@ if !has_key(s:, 'job_info_map')
|
||||
let s:job_info_map = {}
|
||||
endif
|
||||
|
||||
" Stores information for each LSP command including:
|
||||
"
|
||||
" linter: The linter dictionary for the command.
|
||||
" buffer: The buffer number for the command.
|
||||
" message: The message we sent, [is_notification, command, params?]
|
||||
if !has_key(s:, 'lsp_command_info_map')
|
||||
let s:lsp_command_info_map = {}
|
||||
endif
|
||||
|
||||
let s:executable_cache_map = {}
|
||||
|
||||
" Check if files are executable, and if they are, remember that they are
|
||||
@@ -42,6 +51,8 @@ function! ale#engine#InitBufferInfo(buffer) abort
|
||||
\ 'temporary_file_list': [],
|
||||
\ 'temporary_directory_list': [],
|
||||
\ 'history': [],
|
||||
\ 'open_lsp_documents': [],
|
||||
\ 'lsp_command_list': [],
|
||||
\}
|
||||
endif
|
||||
endfunction
|
||||
@@ -103,6 +114,51 @@ function! s:GatherOutput(job_id, line) abort
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:HandleLoclist(linter, buffer, loclist) abort
|
||||
" 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, a:loclist)
|
||||
|
||||
" Remove previous items for this linter.
|
||||
call filter(g:ale_buffer_info[a:buffer].loclist, 'v:val.linter_name !=# a:linter.name')
|
||||
" Add the new items.
|
||||
call extend(g:ale_buffer_info[a:buffer].loclist, l:linter_loclist)
|
||||
|
||||
" Sort the loclist again.
|
||||
" We need a sorted list so we can run a binary search against it
|
||||
" for efficient lookup of the messages in the cursor handler.
|
||||
call sort(g:ale_buffer_info[a:buffer].loclist, 'ale#util#LocItemCompare')
|
||||
|
||||
let l:linting_is_done = empty(g:ale_buffer_info[a:buffer].job_list)
|
||||
\ && empty(g:ale_buffer_info[a:buffer].lsp_command_list)
|
||||
|
||||
if l:linting_is_done
|
||||
" Automatically remove all managed temporary files and directories
|
||||
" now that all jobs have completed.
|
||||
call ale#engine#RemoveManagedFiles(a:buffer)
|
||||
|
||||
" Figure out which linters are still enabled, and remove
|
||||
" problems for linters which are no longer enabled.
|
||||
let l:name_map = {}
|
||||
|
||||
for l:linter in ale#linter#Get(getbufvar(a:buffer, '&filetype'))
|
||||
let l:name_map[l:linter.name] = 1
|
||||
endfor
|
||||
|
||||
call filter(
|
||||
\ g:ale_buffer_info[a:buffer].loclist,
|
||||
\ 'get(l:name_map, v:val.linter_name)',
|
||||
\)
|
||||
endif
|
||||
|
||||
call ale#engine#SetResults(a:buffer, g:ale_buffer_info[a:buffer].loclist)
|
||||
|
||||
if l:linting_is_done
|
||||
" Call user autocommands. This allows users to hook into ALE's lint cycle.
|
||||
silent doautocmd User ALELint
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:HandleExit(job_id, exit_code) abort
|
||||
if !has_key(s:job_info_map, a:job_id)
|
||||
return
|
||||
@@ -143,55 +199,33 @@ function! s:HandleExit(job_id, exit_code) abort
|
||||
call ale#history#RememberOutput(l:buffer, a:job_id, l:output[:])
|
||||
endif
|
||||
|
||||
let l:linter_loclist = ale#util#GetFunction(l:linter.callback)(l:buffer, l:output)
|
||||
let l:loclist = ale#util#GetFunction(l:linter.callback)(l:buffer, l:output)
|
||||
|
||||
" 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(l:buffer, l:linter, l:linter_loclist)
|
||||
call s:HandleLoclist(l:linter, l:buffer, l:loclist)
|
||||
endfunction
|
||||
|
||||
" Remove previous items for this linter.
|
||||
call filter(g:ale_buffer_info[l:buffer].loclist, 'v:val.linter_name !=# l:linter.name')
|
||||
" Add the new items.
|
||||
call extend(g:ale_buffer_info[l:buffer].loclist, l:linter_loclist)
|
||||
function! s:HandleLSPResponse(request_id, response) abort
|
||||
let l:info = get(s:lsp_command_info_map, a:request_id, {})
|
||||
|
||||
" Sort the loclist again.
|
||||
" We need a sorted list so we can run a binary search against it
|
||||
" for efficient lookup of the messages in the cursor handler.
|
||||
call sort(g:ale_buffer_info[l:buffer].loclist, 'ale#util#LocItemCompare')
|
||||
|
||||
let l:linting_is_done = empty(g:ale_buffer_info[l:buffer].job_list)
|
||||
|
||||
if l:linting_is_done
|
||||
" Automatically remove all managed temporary files and directories
|
||||
" now that all jobs have completed.
|
||||
call ale#engine#RemoveManagedFiles(l:buffer)
|
||||
|
||||
" Figure out which linters are still enabled, and remove
|
||||
" problems for linters which are no longer enabled.
|
||||
let l:name_map = {}
|
||||
|
||||
for l:linter in ale#linter#Get(getbufvar(l:buffer, '&filetype'))
|
||||
let l:name_map[l:linter.name] = 1
|
||||
endfor
|
||||
|
||||
call filter(
|
||||
\ g:ale_buffer_info[l:buffer].loclist,
|
||||
\ 'get(l:name_map, v:val.linter_name)',
|
||||
\)
|
||||
if empty(l:info)
|
||||
return
|
||||
endif
|
||||
|
||||
call ale#engine#SetResults(l:buffer, g:ale_buffer_info[l:buffer].loclist)
|
||||
call remove(s:lsp_command_info_map, a:request_id)
|
||||
|
||||
if l:linting_is_done
|
||||
" Call user autocommands. This allows users to hook into ALE's lint cycle.
|
||||
silent doautocmd User ALELint
|
||||
endif
|
||||
let l:command_list = g:ale_buffer_info[l:info.buffer].lsp_command_list
|
||||
call filter(l:command_list, 'v:val != a:request_id')
|
||||
|
||||
let l:loclist = ale#lsp#response#ReadTSServerDiagnostics(a:response)
|
||||
|
||||
call s:HandleLoclist(l:info.linter, l:info.buffer, l:loclist)
|
||||
endfunction
|
||||
|
||||
function! ale#engine#SetResults(buffer, loclist) abort
|
||||
let l:info = get(g:ale_buffer_info, a:buffer, {})
|
||||
let l:job_list = get(l:info, 'job_list', [])
|
||||
let l:linting_is_done = empty(l:job_list)
|
||||
let l:lsp_command_list = get(l:info, 'lsp_command_list', [])
|
||||
let l:linting_is_done = empty(l:job_list) && empty(l:lsp_command_list)
|
||||
|
||||
" Set signs first. This could potentially fix some line numbers.
|
||||
" The List could be sorted again here by SetSigns.
|
||||
@@ -498,16 +532,63 @@ function! ale#engine#StopCurrentJobs(buffer, include_lint_file_jobs) abort
|
||||
|
||||
" Update the List, so it includes only the jobs we still need.
|
||||
let l:info.job_list = l:new_job_list
|
||||
" Ignore current LSP commands.
|
||||
" We should consider cancelling them in future.
|
||||
let l:info.lsp_command_list = []
|
||||
endfunction
|
||||
|
||||
function! s:CheckWithTSServer(buffer, linter, executable) abort
|
||||
let l:info = g:ale_buffer_info[a:buffer]
|
||||
let l:open_documents = l:info.open_lsp_documents
|
||||
let l:is_open = index(l:open_documents, a:linter.name) >= 0
|
||||
|
||||
if !l:is_open
|
||||
call add(l:open_documents, a:linter.name)
|
||||
call ale#lsp#SendMessageToProgram(
|
||||
\ a:executable,
|
||||
\ a:executable,
|
||||
\ ale#lsp#tsserver_message#Open(a:buffer),
|
||||
\)
|
||||
endif
|
||||
|
||||
call ale#lsp#SendMessageToProgram(
|
||||
\ a:executable,
|
||||
\ a:executable,
|
||||
\ ale#lsp#tsserver_message#Change(a:buffer),
|
||||
\)
|
||||
|
||||
let l:message = ale#lsp#tsserver_message#Geterr(a:buffer)
|
||||
let l:request_id = ale#lsp#SendMessageToProgram(
|
||||
\ a:executable,
|
||||
\ a:executable,
|
||||
\ l:message,
|
||||
\ function('s:HandleLSPResponse'),
|
||||
\)
|
||||
|
||||
if l:request_id > 0
|
||||
let s:lsp_command_info_map[l:request_id] = {
|
||||
\ 'buffer': a:buffer,
|
||||
\ 'linter': a:linter,
|
||||
\ 'message': l:message,
|
||||
\}
|
||||
call add(l:info.lsp_command_list, l:request_id)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#engine#Invoke(buffer, linter) abort
|
||||
let l:executable = has_key(a:linter, 'executable_callback')
|
||||
\ ? ale#util#GetFunction(a:linter.executable_callback)(a:buffer)
|
||||
\ : a:linter.executable
|
||||
if empty(a:linter.lsp) || a:linter.lsp ==# 'tsserver'
|
||||
let l:executable = has_key(a:linter, 'executable_callback')
|
||||
\ ? ale#util#GetFunction(a:linter.executable_callback)(a:buffer)
|
||||
\ : a:linter.executable
|
||||
|
||||
" Run this program if it can be executed.
|
||||
if s:IsExecutable(l:executable)
|
||||
call s:InvokeChain(a:buffer, a:linter, 0, [])
|
||||
" Run this program if it can be executed.
|
||||
if s:IsExecutable(l:executable)
|
||||
if a:linter.lsp ==# 'tsserver'
|
||||
call s:CheckWithTSServer(a:buffer, a:linter, l:executable)
|
||||
else
|
||||
call s:InvokeChain(a:buffer, a:linter, 0, [])
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
|
||||
Reference in New Issue
Block a user