mirror of
https://github.com/dense-analysis/ale.git
synced 2026-01-09 13:02:28 +08:00
#697 - Clear all highlights every time items are set again, and refactor most things. Clear errors when linters are removed
This commit is contained in:
@@ -1,19 +0,0 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: Utility functions related to cleaning state.
|
||||
|
||||
function! ale#cleanup#Buffer(buffer) abort
|
||||
if has_key(g:ale_buffer_info, a:buffer)
|
||||
call ale#engine#RemoveManagedFiles(a:buffer)
|
||||
|
||||
" When buffers are removed, clear all of the jobs.
|
||||
call ale#engine#StopCurrentJobs(a:buffer, 1)
|
||||
|
||||
" Clear delayed highlights for a buffer being removed.
|
||||
if g:ale_set_highlights
|
||||
call ale#highlight#UnqueueHighlights(a:buffer)
|
||||
call ale#highlight#RemoveHighlights([])
|
||||
endif
|
||||
|
||||
call remove(g:ale_buffer_info, a:buffer)
|
||||
endif
|
||||
endfunction
|
||||
@@ -46,6 +46,14 @@ function! ale#engine#InitBufferInfo(buffer) abort
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Return 1 if ALE is busy checking a given buffer
|
||||
function! ale#engine#IsCheckingBuffer(buffer) abort
|
||||
let l:info = get(g:ale_buffer_info, a:buffer, {})
|
||||
|
||||
return get(l:info, 'waiting_for_tsserver') == 1
|
||||
\|| !empty(get(l:info, 'job_list'))
|
||||
endfunction
|
||||
|
||||
" Register a temporary file to be managed with the ALE engine for
|
||||
" a current job run.
|
||||
function! ale#engine#ManageFile(buffer, filename) abort
|
||||
@@ -69,9 +77,7 @@ function! ale#engine#CreateDirectory(buffer) abort
|
||||
endfunction
|
||||
|
||||
function! ale#engine#RemoveManagedFiles(buffer) abort
|
||||
if !has_key(g:ale_buffer_info, a:buffer)
|
||||
return
|
||||
endif
|
||||
let l:info = get(g:ale_buffer_info, a:buffer)
|
||||
|
||||
" We can't delete anything in a sandbox, so wait until we escape from
|
||||
" it to delete temporary files and directories.
|
||||
@@ -80,21 +86,25 @@ function! ale#engine#RemoveManagedFiles(buffer) abort
|
||||
endif
|
||||
|
||||
" Delete files with a call akin to a plan `rm` command.
|
||||
for l:filename in g:ale_buffer_info[a:buffer].temporary_file_list
|
||||
call delete(l:filename)
|
||||
endfor
|
||||
if has_key(l:info, 'temporary_file_list')
|
||||
for l:filename in l:info.temporary_file_list
|
||||
call delete(l:filename)
|
||||
endfor
|
||||
|
||||
let g:ale_buffer_info[a:buffer].temporary_file_list = []
|
||||
let l:info.temporary_file_list = []
|
||||
endif
|
||||
|
||||
" Delete directories like `rm -rf`.
|
||||
" Directories are handled differently from files, so paths that are
|
||||
" intended to be single files can be set up for automatic deletion without
|
||||
" accidentally deleting entire directories.
|
||||
for l:directory in g:ale_buffer_info[a:buffer].temporary_directory_list
|
||||
call delete(l:directory, 'rf')
|
||||
endfor
|
||||
if has_key(l:info, 'temporary_directory_list')
|
||||
for l:directory in l:info.temporary_directory_list
|
||||
call delete(l:directory, 'rf')
|
||||
endfor
|
||||
|
||||
let g:ale_buffer_info[a:buffer].temporary_directory_list = []
|
||||
let l:info.temporary_directory_list = []
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:GatherOutput(job_id, line) abort
|
||||
@@ -118,34 +128,11 @@ function! s:HandleLoclist(linter_name, buffer, loclist) abort
|
||||
" 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)
|
||||
\ && !get(g:ale_buffer_info[a:buffer], 'waiting_for_tsserver', 0)
|
||||
|
||||
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)',
|
||||
\)
|
||||
if ale#ShouldDoNothing()
|
||||
return
|
||||
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
|
||||
@@ -217,10 +204,7 @@ function! s:HandleLSPResponse(response) abort
|
||||
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:waiting_for_tsserver = get(l:info, 'waiting_for_tsserver', 0)
|
||||
let l:linting_is_done = empty(l:job_list) && !l:waiting_for_tsserver
|
||||
let l:linting_is_done = !ale#engine#IsCheckingBuffer(a:buffer)
|
||||
|
||||
" Set signs first. This could potentially fix some line numbers.
|
||||
" The List could be sorted again here by SetSigns.
|
||||
@@ -254,6 +238,15 @@ function! ale#engine#SetResults(buffer, loclist) abort
|
||||
" This will only do something meaningful if we're in normal mode.
|
||||
call ale#cursor#EchoCursorWarning()
|
||||
endif
|
||||
|
||||
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)
|
||||
|
||||
" Call user autocommands. This allows users to hook into ALE's lint cycle.
|
||||
silent doautocmd User ALELint
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:RemapItemTypes(type_map, loclist) abort
|
||||
@@ -371,6 +364,9 @@ function! s:CreateTemporaryFileForJob(buffer, temporary_file) abort
|
||||
return 1
|
||||
endfunction
|
||||
|
||||
" Run a job.
|
||||
"
|
||||
" Returns 1 when the job was started successfully.
|
||||
function! s:RunJob(options) abort
|
||||
let l:command = a:options.command
|
||||
let l:buffer = a:options.buffer
|
||||
@@ -379,6 +375,10 @@ function! s:RunJob(options) abort
|
||||
let l:next_chain_index = a:options.next_chain_index
|
||||
let l:read_buffer = a:options.read_buffer
|
||||
|
||||
if empty(l:command)
|
||||
return 0
|
||||
endif
|
||||
|
||||
let [l:temporary_file, l:command] = ale#command#FormatCommand(l:buffer, l:command, l:read_buffer)
|
||||
|
||||
if s:CreateTemporaryFileForJob(l:buffer, l:temporary_file)
|
||||
@@ -457,6 +457,8 @@ function! s:RunJob(options) abort
|
||||
|
||||
call l:job_options.exit_cb(l:job_id, v:shell_error)
|
||||
endif
|
||||
|
||||
return l:job_id != 0
|
||||
endfunction
|
||||
|
||||
" Determine which commands to run for a link in a command chain, or
|
||||
@@ -516,11 +518,6 @@ function! ale#engine#ProcessChain(buffer, linter, chain_index, input) abort
|
||||
let l:command = ale#linter#GetCommand(a:buffer, a:linter)
|
||||
endif
|
||||
|
||||
if empty(l:command)
|
||||
" Don't run any jobs if the command is an empty string.
|
||||
return {}
|
||||
endif
|
||||
|
||||
return {
|
||||
\ 'command': l:command,
|
||||
\ 'buffer': a:buffer,
|
||||
@@ -534,16 +531,10 @@ endfunction
|
||||
function! s:InvokeChain(buffer, linter, chain_index, input) abort
|
||||
let l:options = ale#engine#ProcessChain(a:buffer, a:linter, a:chain_index, a:input)
|
||||
|
||||
if !empty(l:options)
|
||||
call s:RunJob(l:options)
|
||||
elseif empty(g:ale_buffer_info[a:buffer].job_list)
|
||||
" If we cancelled running a command, and we have no jobs in progress,
|
||||
" then delete the managed temporary files now.
|
||||
call ale#engine#RemoveManagedFiles(a:buffer)
|
||||
endif
|
||||
return s:RunJob(l:options)
|
||||
endfunction
|
||||
|
||||
function! ale#engine#StopCurrentJobs(buffer, include_lint_file_jobs) abort
|
||||
function! s:StopCurrentJobs(buffer, include_lint_file_jobs) abort
|
||||
let l:info = get(g:ale_buffer_info, a:buffer, {})
|
||||
let l:new_job_list = []
|
||||
|
||||
@@ -562,9 +553,6 @@ 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
|
||||
@@ -584,7 +572,7 @@ function! s:CheckWithTSServer(buffer, linter, executable) abort
|
||||
call ale#history#Add(a:buffer, 'failed', l:id, l:command)
|
||||
endif
|
||||
|
||||
return
|
||||
return 0
|
||||
endif
|
||||
|
||||
if ale#lsp#OpenTSServerDocumentIfNeeded(l:id, a:buffer)
|
||||
@@ -603,21 +591,88 @@ function! s:CheckWithTSServer(buffer, linter, executable) abort
|
||||
if l:request_id != 0
|
||||
let l:info.waiting_for_tsserver = 1
|
||||
endif
|
||||
|
||||
return l:request_id != 0
|
||||
endfunction
|
||||
|
||||
function! ale#engine#Invoke(buffer, linter) abort
|
||||
function! s:RemoveProblemsForDisabledLinters(buffer, linters) abort
|
||||
" 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 a:linters
|
||||
let l:name_map[l:linter.name] = 1
|
||||
endfor
|
||||
|
||||
call filter(
|
||||
\ get(g:ale_buffer_info[a:buffer], 'loclist', []),
|
||||
\ 'get(l:name_map, v:val.linter_name)',
|
||||
\)
|
||||
endfunction
|
||||
|
||||
" Run a linter for a buffer.
|
||||
"
|
||||
" Returns 1 if the linter was successfully run.
|
||||
function! s:RunLinter(buffer, linter) abort
|
||||
if empty(a:linter.lsp) || a:linter.lsp ==# 'tsserver'
|
||||
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'
|
||||
call s:CheckWithTSServer(a:buffer, a:linter, l:executable)
|
||||
else
|
||||
call s:InvokeChain(a:buffer, a:linter, 0, [])
|
||||
return s:CheckWithTSServer(a:buffer, a:linter, l:executable)
|
||||
endif
|
||||
|
||||
return s:InvokeChain(a:buffer, a:linter, 0, [])
|
||||
endif
|
||||
endif
|
||||
|
||||
return 0
|
||||
endfunction
|
||||
|
||||
function! ale#engine#RunLinters(buffer, linters, should_lint_file) abort
|
||||
" Initialise the buffer information if needed.
|
||||
call ale#engine#InitBufferInfo(a:buffer)
|
||||
call s:StopCurrentJobs(a:buffer, a:should_lint_file)
|
||||
call s:RemoveProblemsForDisabledLinters(a:buffer, a:linters)
|
||||
|
||||
let l:any_linter_ran = 0
|
||||
|
||||
for l:linter in a:linters
|
||||
" Skip linters for checking files if we shouldn't check the file.
|
||||
if l:linter.lint_file && !a:should_lint_file
|
||||
continue
|
||||
endif
|
||||
|
||||
if s:RunLinter(a:buffer, l:linter)
|
||||
let l:any_linter_ran = 1
|
||||
endif
|
||||
endfor
|
||||
|
||||
" If we didn't manage to start checking the buffer with anything,
|
||||
" and there's nothing running currently for the buffer, then clear the
|
||||
" results.
|
||||
"
|
||||
" We need to use both checks, as we run some tests synchronously.
|
||||
if !l:any_linter_ran && !ale#engine#IsCheckingBuffer(a:buffer)
|
||||
call ale#engine#SetResults(a:buffer, [])
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Clean up a buffer.
|
||||
"
|
||||
" This function will stop all current jobs for the buffer,
|
||||
" clear the state of everything, and remove the Dictionary for managing
|
||||
" the buffer.
|
||||
function! ale#engine#Cleanup(buffer) abort
|
||||
call ale#engine#RunLinters(a:buffer, [], 1)
|
||||
|
||||
if g:ale_set_highlights
|
||||
call ale#highlight#UnqueueHighlights(a:buffer)
|
||||
call ale#highlight#RemoveHighlights([])
|
||||
endif
|
||||
|
||||
call remove(g:ale_buffer_info, a:buffer)
|
||||
endfunction
|
||||
|
||||
" Given a buffer number, return the warnings and errors for a given buffer.
|
||||
|
||||
@@ -67,27 +67,11 @@ function! s:GetALEMatches() abort
|
||||
return filter(getmatches(), 'v:val.group =~# ''^ALE''')
|
||||
endfunction
|
||||
|
||||
function! s:GetCurrentMatchIDs(loclist) abort
|
||||
let l:current_id_map = {}
|
||||
|
||||
for l:item in a:loclist
|
||||
for l:id in get(l:item, 'match_id_list', [])
|
||||
let l:current_id_map[l:id] = 1
|
||||
endfor
|
||||
endfor
|
||||
|
||||
return l:current_id_map
|
||||
endfunction
|
||||
|
||||
" Given a loclist for current items to highlight, remove all highlights
|
||||
" except these which have matching loclist item entries.
|
||||
function! ale#highlight#RemoveHighlights(loclist) abort
|
||||
let l:current_id_map = s:GetCurrentMatchIDs(a:loclist)
|
||||
|
||||
for l:match in s:GetALEMatches()
|
||||
if !has_key(l:current_id_map, l:match.id)
|
||||
call matchdelete(l:match.id)
|
||||
endif
|
||||
call matchdelete(l:match.id)
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
@@ -100,9 +84,6 @@ function! ale#highlight#UpdateHighlights() abort
|
||||
call ale#highlight#RemoveHighlights(l:loclist)
|
||||
endif
|
||||
|
||||
" Remove anything with a current match_id
|
||||
call filter(l:loclist, '!has_key(v:val, ''match_id_list'')')
|
||||
|
||||
" Restore items from the map of hidden items,
|
||||
" if we don't have some new items to set already.
|
||||
if empty(l:loclist) && has_key(s:buffer_restore_map, l:buffer)
|
||||
@@ -132,10 +113,7 @@ function! ale#highlight#UpdateHighlights() abort
|
||||
|
||||
" Set all of the positions, which are chunked into Lists which
|
||||
" are as large as will be accepted by matchaddpos.
|
||||
"
|
||||
" We will remember the IDs we set, so we can preserve some
|
||||
" highlights when linting buffers after linting files.
|
||||
let l:item.match_id_list = map(
|
||||
call map(
|
||||
\ ale#highlight#CreatePositions(l:line, l:col, l:end_line, l:end_col),
|
||||
\ 'matchaddpos(l:group, v:val)'
|
||||
\)
|
||||
@@ -148,14 +126,6 @@ function! ale#highlight#BufferHidden(buffer) abort
|
||||
|
||||
" Remember loclist items, so they can be restored later.
|
||||
if !empty(l:loclist)
|
||||
" Remove match_ids, as they must be re-calculated when buffers are
|
||||
" shown again.
|
||||
for l:item in l:loclist
|
||||
if has_key(l:item, 'match_id_list')
|
||||
call remove(l:item, 'match_id_list')
|
||||
endif
|
||||
endfor
|
||||
|
||||
let s:buffer_restore_map[a:buffer] = filter(
|
||||
\ copy(l:loclist),
|
||||
\ 'v:val.bufnr == a:buffer && v:val.col > 0'
|
||||
|
||||
@@ -15,5 +15,9 @@ function! ale#test#SetFilename(path) abort
|
||||
let l:dir = getcwd()
|
||||
endif
|
||||
|
||||
silent noautocmd execute 'file ' . fnameescape(ale#path#Simplify(l:dir . '/' . a:path))
|
||||
let l:full_path = ale#path#IsAbsolute(a:path)
|
||||
\ ? a:path
|
||||
\ : l:dir . '/' . a:path
|
||||
|
||||
silent noautocmd execute 'file ' . fnameescape(ale#path#Simplify(l:full_path))
|
||||
endfunction
|
||||
|
||||
Reference in New Issue
Block a user