2016-10-03 18:41:02 +00:00
|
|
|
" Author: w0rp <devw0rp@gmail.com>
|
First pass at optimizing ale to autoload (#80)
* First pass at optimizing ale to autoload
First off, the structure/function names should be revised a bit,
but I will wait for @w0rp's input before unifying the naming style.
Second off, the docs probably need some more work, I just did some
simple find-and-replace work.
With that said, this pull brings major performance gains for ale. On my
slowest system, fully loading ale and all its code takes around 150ms.
I have moved all of ale's autoload-able code to autoload/, and in
addition, implemented lazy-loading of linters. This brings load time on
that same system down to 5ms.
The only downside of lazy loading is that `g:ale_linters` cannot be
changed at runtime; however, it also speeds up performance at runtime by
simplfying the logic greatly.
Please let me know what you think!
Closes #59
* Address Travis/Vint errors
For some reason, ale isn't running vint for me...
* Incorporate feedback, make fixes
Lazy-loading logic is much improved.
* Add header comments; remove incorrect workaround
* Remove unneeded plugin guards
* Fix lazy-loading linter logic
Set the wrong variable....
* Fix capitialization
2016-10-10 18:51:29 +00:00
|
|
|
" Description: Backend execution and job management
|
|
|
|
" Executes linters in the background, using NeoVim or Vim 8 jobs
|
2016-09-17 11:06:53 +00:00
|
|
|
|
2018-05-28 18:19:20 +00:00
|
|
|
" Remapping of linter problems.
|
|
|
|
let g:ale_type_map = get(g:, 'ale_type_map', {})
|
2020-08-28 08:33:09 +00:00
|
|
|
let g:ale_filename_mappings = get(g:, 'ale_filename_mappings', {})
|
2018-05-28 18:19:20 +00:00
|
|
|
|
2017-08-23 20:41:29 +00:00
|
|
|
if !has_key(s:, 'executable_cache_map')
|
|
|
|
let s:executable_cache_map = {}
|
|
|
|
endif
|
|
|
|
|
2018-09-16 14:57:13 +00:00
|
|
|
function! ale#engine#CleanupEveryBuffer() abort
|
|
|
|
for l:key in keys(g:ale_buffer_info)
|
|
|
|
" The key could be a filename or a buffer number, so try and
|
|
|
|
" convert it to a number. We need a number for the other
|
|
|
|
" functions.
|
|
|
|
let l:buffer = str2nr(l:key)
|
|
|
|
|
|
|
|
if l:buffer > 0
|
|
|
|
" Stop all jobs and clear the results for everything, and delete
|
|
|
|
" all of the data we stored for the buffer.
|
|
|
|
call ale#engine#Cleanup(l:buffer)
|
|
|
|
endif
|
|
|
|
endfor
|
|
|
|
endfunction
|
|
|
|
|
2019-02-14 10:10:46 +00:00
|
|
|
function! ale#engine#MarkLinterActive(info, linter) abort
|
|
|
|
let l:found = 0
|
|
|
|
|
|
|
|
for l:other_linter in a:info.active_linter_list
|
|
|
|
if l:other_linter.name is# a:linter.name
|
|
|
|
let l:found = 1
|
|
|
|
break
|
|
|
|
endif
|
|
|
|
endfor
|
|
|
|
|
|
|
|
if !l:found
|
|
|
|
call add(a:info.active_linter_list, a:linter)
|
|
|
|
endif
|
|
|
|
endfunction
|
|
|
|
|
2019-04-17 17:12:25 +00:00
|
|
|
function! ale#engine#MarkLinterInactive(info, linter_name) abort
|
|
|
|
call filter(a:info.active_linter_list, 'v:val.name isnot# a:linter_name')
|
2019-02-14 10:10:46 +00:00
|
|
|
endfunction
|
|
|
|
|
2017-08-23 20:41:29 +00:00
|
|
|
function! ale#engine#ResetExecutableCache() abort
|
|
|
|
let s:executable_cache_map = {}
|
|
|
|
endfunction
|
2017-04-29 10:58:43 +00:00
|
|
|
|
|
|
|
" Check if files are executable, and if they are, remember that they are
|
|
|
|
" for subsequent calls. We'll keep checking until programs can be executed.
|
2017-08-23 20:41:29 +00:00
|
|
|
function! ale#engine#IsExecutable(buffer, executable) abort
|
2017-11-21 14:37:01 +00:00
|
|
|
if empty(a:executable)
|
|
|
|
" Don't log the executable check if the executable string is empty.
|
|
|
|
return 0
|
|
|
|
endif
|
|
|
|
|
2017-11-30 10:34:51 +00:00
|
|
|
" Check for a cached executable() check.
|
|
|
|
let l:result = get(s:executable_cache_map, a:executable, v:null)
|
2017-04-29 10:58:43 +00:00
|
|
|
|
2017-11-30 10:34:51 +00:00
|
|
|
if l:result isnot v:null
|
|
|
|
return l:result
|
|
|
|
endif
|
2017-08-23 20:41:29 +00:00
|
|
|
|
2017-11-30 10:34:51 +00:00
|
|
|
" Check if the file is executable, and convert -1 to 1.
|
|
|
|
let l:result = executable(a:executable) isnot 0
|
2017-04-29 10:58:43 +00:00
|
|
|
|
2017-11-30 10:34:51 +00:00
|
|
|
" Cache the executable check if we found it, or if the option to cache
|
|
|
|
" failing checks is on.
|
2018-05-28 18:19:20 +00:00
|
|
|
if l:result || get(g:, 'ale_cache_executable_check_failures', 0)
|
2017-11-30 10:34:51 +00:00
|
|
|
let s:executable_cache_map[a:executable] = l:result
|
2017-08-23 20:41:29 +00:00
|
|
|
endif
|
|
|
|
|
|
|
|
if g:ale_history_enabled
|
|
|
|
call ale#history#Add(a:buffer, l:result, 'executable', a:executable)
|
2017-04-29 10:58:43 +00:00
|
|
|
endif
|
|
|
|
|
2017-08-23 20:41:29 +00:00
|
|
|
return l:result
|
2017-04-29 10:58:43 +00:00
|
|
|
endfunction
|
2016-09-14 10:47:52 +00:00
|
|
|
|
2016-10-23 21:41:00 +00:00
|
|
|
function! ale#engine#InitBufferInfo(buffer) abort
|
|
|
|
if !has_key(g:ale_buffer_info, a:buffer)
|
2017-07-26 09:37:37 +00:00
|
|
|
" active_linter_list will hold the list of active linter names
|
2016-10-31 13:45:22 +00:00
|
|
|
" loclist holds the loclist items after all jobs have completed.
|
2016-10-23 21:41:00 +00:00
|
|
|
let g:ale_buffer_info[a:buffer] = {
|
2017-07-26 09:37:37 +00:00
|
|
|
\ 'active_linter_list': [],
|
2018-10-29 18:28:28 +00:00
|
|
|
\ 'active_other_sources_list': [],
|
2016-10-24 19:21:32 +00:00
|
|
|
\ 'loclist': [],
|
2016-10-23 21:41:00 +00:00
|
|
|
\}
|
2017-08-19 19:15:36 +00:00
|
|
|
|
|
|
|
return 1
|
2016-10-23 21:41:00 +00:00
|
|
|
endif
|
2017-08-19 19:15:36 +00:00
|
|
|
|
|
|
|
return 0
|
2016-10-23 21:41:00 +00:00
|
|
|
endfunction
|
|
|
|
|
2018-02-25 12:57:54 +00:00
|
|
|
" This function is documented and part of the public API.
|
|
|
|
"
|
2017-07-07 22:47:41 +00:00
|
|
|
" 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, {})
|
|
|
|
|
2017-07-26 09:44:27 +00:00
|
|
|
return !empty(get(l:info, 'active_linter_list', []))
|
2018-10-29 18:28:28 +00:00
|
|
|
\ || !empty(get(l:info, 'active_other_sources_list', []))
|
2017-07-07 22:47:41 +00:00
|
|
|
endfunction
|
|
|
|
|
2018-10-29 18:28:28 +00:00
|
|
|
function! ale#engine#HandleLoclist(linter_name, buffer, loclist, from_other_source) abort
|
2018-03-02 12:10:27 +00:00
|
|
|
let l:info = get(g:ale_buffer_info, a:buffer, {})
|
2017-07-26 09:37:37 +00:00
|
|
|
|
2018-03-02 12:10:27 +00:00
|
|
|
if empty(l:info)
|
2017-07-26 09:37:37 +00:00
|
|
|
return
|
|
|
|
endif
|
|
|
|
|
2018-10-29 18:28:28 +00:00
|
|
|
if !a:from_other_source
|
|
|
|
" Remove this linter from the list of active linters.
|
|
|
|
" This may have already been done when the job exits.
|
2019-02-06 22:00:11 +00:00
|
|
|
call filter(l:info.active_linter_list, 'v:val.name isnot# a:linter_name')
|
2018-10-29 18:28:28 +00:00
|
|
|
endif
|
2017-07-26 09:37:37 +00:00
|
|
|
|
2017-06-08 16:28:38 +00:00
|
|
|
" Make some adjustments to the loclists to fix common problems, and also
|
|
|
|
" to set default values for loclist items.
|
2018-10-29 18:28:28 +00:00
|
|
|
let l:linter_loclist = ale#engine#FixLocList(
|
|
|
|
\ a:buffer,
|
|
|
|
\ a:linter_name,
|
|
|
|
\ a:from_other_source,
|
|
|
|
\ a:loclist,
|
|
|
|
\)
|
2017-06-08 16:28:38 +00:00
|
|
|
|
|
|
|
" Remove previous items for this linter.
|
2018-03-02 12:10:27 +00:00
|
|
|
call filter(l:info.loclist, 'v:val.linter_name isnot# a:linter_name')
|
|
|
|
|
|
|
|
" We don't need to add items or sort the list when this list is empty.
|
|
|
|
if !empty(l:linter_loclist)
|
|
|
|
" Add the new items.
|
|
|
|
call extend(l:info.loclist, l:linter_loclist)
|
2017-06-08 16:28:38 +00:00
|
|
|
|
2018-03-02 12:10:27 +00:00
|
|
|
" 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(l:info.loclist, 'ale#util#LocItemCompare')
|
|
|
|
endif
|
2017-06-08 16:28:38 +00:00
|
|
|
|
2017-07-31 23:03:24 +00:00
|
|
|
if ale#ShouldDoNothing(a:buffer)
|
2017-07-07 22:47:41 +00:00
|
|
|
return
|
2017-06-08 16:28:38 +00:00
|
|
|
endif
|
|
|
|
|
2018-03-02 12:10:27 +00:00
|
|
|
call ale#engine#SetResults(a:buffer, l:info.loclist)
|
2017-06-08 16:28:38 +00:00
|
|
|
endfunction
|
|
|
|
|
2019-02-06 22:00:11 +00:00
|
|
|
function! s:HandleExit(job_info, buffer, output, data) abort
|
|
|
|
let l:buffer_info = get(g:ale_buffer_info, a:buffer)
|
|
|
|
|
|
|
|
if empty(l:buffer_info)
|
2016-09-08 23:23:26 +00:00
|
|
|
return
|
|
|
|
endif
|
|
|
|
|
2019-02-06 22:00:11 +00:00
|
|
|
let l:linter = a:job_info.linter
|
|
|
|
let l:executable = a:job_info.executable
|
2017-05-12 20:16:15 +00:00
|
|
|
|
2017-06-06 15:44:01 +00:00
|
|
|
" Remove this job from the list.
|
2019-04-17 17:12:25 +00:00
|
|
|
call ale#engine#MarkLinterInactive(l:buffer_info, l:linter.name)
|
2016-10-13 14:13:11 +00:00
|
|
|
|
2017-02-14 21:02:49 +00:00
|
|
|
" Stop here if we land in the handle for a job completing if we're in
|
|
|
|
" a sandbox.
|
|
|
|
if ale#util#InSandbox()
|
|
|
|
return
|
|
|
|
endif
|
|
|
|
|
2019-02-06 22:00:11 +00:00
|
|
|
if has('nvim') && !empty(a:output) && empty(a:output[-1])
|
|
|
|
call remove(a:output, -1)
|
2017-05-12 19:38:52 +00:00
|
|
|
endif
|
|
|
|
|
2018-07-13 08:47:26 +00:00
|
|
|
try
|
2019-02-06 22:00:11 +00:00
|
|
|
let l:loclist = ale#util#GetFunction(l:linter.callback)(a:buffer, a:output)
|
2018-07-13 08:47:26 +00:00
|
|
|
" Handle the function being unknown, or being deleted.
|
|
|
|
catch /E700/
|
|
|
|
let l:loclist = []
|
|
|
|
endtry
|
2016-10-10 18:56:05 +00:00
|
|
|
|
2019-02-06 22:00:11 +00:00
|
|
|
call ale#engine#HandleLoclist(l:linter.name, a:buffer, l:loclist, 0)
|
2017-06-08 16:28:38 +00:00
|
|
|
endfunction
|
2017-03-21 14:52:02 +00:00
|
|
|
|
2017-02-09 18:47:14 +00:00
|
|
|
function! ale#engine#SetResults(buffer, loclist) abort
|
2017-07-07 22:47:41 +00:00
|
|
|
let l:linting_is_done = !ale#engine#IsCheckingBuffer(a:buffer)
|
2017-06-07 22:12:45 +00:00
|
|
|
|
2017-03-14 23:04:25 +00:00
|
|
|
" Set signs first. This could potentially fix some line numbers.
|
2017-03-21 14:52:02 +00:00
|
|
|
" The List could be sorted again here by SetSigns.
|
2016-09-08 23:23:26 +00:00
|
|
|
if g:ale_set_signs
|
2017-02-09 18:47:14 +00:00
|
|
|
call ale#sign#SetSigns(a:buffer, a:loclist)
|
2016-09-08 23:23:26 +00:00
|
|
|
endif
|
|
|
|
|
2017-03-14 23:04:25 +00:00
|
|
|
if g:ale_set_quickfix || g:ale_set_loclist
|
|
|
|
call ale#list#SetLists(a:buffer, a:loclist)
|
|
|
|
endif
|
|
|
|
|
Implement a more efficient statusbar
The statusbar now keeps its state in a separate variable, in order to
avoid excess iterations. The engine now updates said variable on run,
and a new function is made available for external statusbars to call (to
avoid dependencies on internal implementation details of ale).
To keep things light, the status bar code is not loaded unless invoked
by the user or an external plugin. On the first load it will update
itself from the global loclist, after that, the engine will handle all
updates.
The external integration function, `ale#statusline#Count()`, will return
a tuple in the format [E, W] (where E is errors, W is warnings), unless
no data exists (ie, the plugin doesn't have a linter for a file or has
not run yet), in which case it returns 0/false.
2016-10-11 21:51:01 +00:00
|
|
|
if exists('*ale#statusline#Update')
|
|
|
|
" Don't load/run if not already loaded.
|
2017-02-09 18:47:14 +00:00
|
|
|
call ale#statusline#Update(a:buffer, a:loclist)
|
Implement a more efficient statusbar
The statusbar now keeps its state in a separate variable, in order to
avoid excess iterations. The engine now updates said variable on run,
and a new function is made available for external statusbars to call (to
avoid dependencies on internal implementation details of ale).
To keep things light, the status bar code is not loaded unless invoked
by the user or an external plugin. On the first load it will update
itself from the global loclist, after that, the engine will handle all
updates.
The external integration function, `ale#statusline#Count()`, will return
a tuple in the format [E, W] (where E is errors, W is warnings), unless
no data exists (ie, the plugin doesn't have a linter for a file or has
not run yet), in which case it returns 0/false.
2016-10-11 21:51:01 +00:00
|
|
|
endif
|
2017-02-13 00:18:51 +00:00
|
|
|
|
|
|
|
if g:ale_set_highlights
|
|
|
|
call ale#highlight#SetHighlights(a:buffer, a:loclist)
|
|
|
|
endif
|
2017-03-02 23:36:31 +00:00
|
|
|
|
2017-07-07 22:47:41 +00:00
|
|
|
if l:linting_is_done
|
2018-11-07 06:31:35 +00:00
|
|
|
if g:ale_echo_cursor
|
2017-12-18 11:14:10 +00:00
|
|
|
" Try and echo the warning now.
|
|
|
|
" This will only do something meaningful if we're in normal mode.
|
|
|
|
call ale#cursor#EchoCursorWarning()
|
|
|
|
endif
|
|
|
|
|
2018-11-07 06:31:35 +00:00
|
|
|
if g:ale_virtualtext_cursor
|
|
|
|
" Try and show the warning now.
|
|
|
|
" This will only do something meaningful if we're in normal mode.
|
|
|
|
call ale#virtualtext#ShowCursorWarning()
|
|
|
|
endif
|
|
|
|
|
2017-08-07 23:46:42 +00:00
|
|
|
" Reset the save event marker, used for opening windows, etc.
|
|
|
|
call setbufvar(a:buffer, 'ale_save_event_fired', 0)
|
2018-03-03 16:22:56 +00:00
|
|
|
" Set a marker showing how many times a buffer has been checked.
|
|
|
|
call setbufvar(
|
|
|
|
\ a:buffer,
|
|
|
|
\ 'ale_linted',
|
|
|
|
\ getbufvar(a:buffer, 'ale_linted', 0) + 1
|
|
|
|
\)
|
2017-08-07 23:46:42 +00:00
|
|
|
|
2017-07-07 22:47:41 +00:00
|
|
|
" Automatically remove all managed temporary files and directories
|
|
|
|
" now that all jobs have completed.
|
2019-01-26 19:33:52 +00:00
|
|
|
call ale#command#RemoveManagedFiles(a:buffer)
|
2017-07-07 22:47:41 +00:00
|
|
|
|
|
|
|
" Call user autocommands. This allows users to hook into ALE's lint cycle.
|
2017-12-10 13:03:03 +00:00
|
|
|
silent doautocmd <nomodeline> User ALELintPost
|
2017-07-07 22:47:41 +00:00
|
|
|
endif
|
2016-09-08 23:23:26 +00:00
|
|
|
endfunction
|
|
|
|
|
2017-06-14 16:59:13 +00:00
|
|
|
function! s:RemapItemTypes(type_map, loclist) abort
|
|
|
|
for l:item in a:loclist
|
|
|
|
let l:key = l:item.type
|
2017-08-08 07:39:13 +00:00
|
|
|
\ . (get(l:item, 'sub_type', '') is# 'style' ? 'S' : '')
|
2017-06-14 16:59:13 +00:00
|
|
|
let l:new_key = get(a:type_map, l:key, '')
|
|
|
|
|
2017-08-08 07:39:13 +00:00
|
|
|
if l:new_key is# 'E'
|
|
|
|
\|| l:new_key is# 'ES'
|
|
|
|
\|| l:new_key is# 'W'
|
|
|
|
\|| l:new_key is# 'WS'
|
|
|
|
\|| l:new_key is# 'I'
|
2017-06-14 16:59:13 +00:00
|
|
|
let l:item.type = l:new_key[0]
|
|
|
|
|
2017-08-08 07:39:13 +00:00
|
|
|
if l:new_key is# 'ES' || l:new_key is# 'WS'
|
2017-06-14 16:59:13 +00:00
|
|
|
let l:item.sub_type = 'style'
|
|
|
|
elseif has_key(l:item, 'sub_type')
|
|
|
|
call remove(l:item, 'sub_type')
|
|
|
|
endif
|
|
|
|
endif
|
|
|
|
endfor
|
|
|
|
endfunction
|
|
|
|
|
2018-10-29 18:28:28 +00:00
|
|
|
function! ale#engine#FixLocList(buffer, linter_name, from_other_source, loclist) abort
|
2020-08-23 18:55:42 +00:00
|
|
|
let l:mappings = ale#GetFilenameMappings(a:buffer, a:linter_name)
|
|
|
|
|
|
|
|
if !empty(l:mappings)
|
|
|
|
" We need to apply reverse filename mapping here.
|
|
|
|
let l:mappings = ale#filename_mapping#Invert(l:mappings)
|
|
|
|
endif
|
|
|
|
|
2017-08-10 22:08:32 +00:00
|
|
|
let l:bufnr_map = {}
|
2017-02-26 14:51:22 +00:00
|
|
|
let l:new_loclist = []
|
|
|
|
|
First pass at optimizing ale to autoload (#80)
* First pass at optimizing ale to autoload
First off, the structure/function names should be revised a bit,
but I will wait for @w0rp's input before unifying the naming style.
Second off, the docs probably need some more work, I just did some
simple find-and-replace work.
With that said, this pull brings major performance gains for ale. On my
slowest system, fully loading ale and all its code takes around 150ms.
I have moved all of ale's autoload-able code to autoload/, and in
addition, implemented lazy-loading of linters. This brings load time on
that same system down to 5ms.
The only downside of lazy loading is that `g:ale_linters` cannot be
changed at runtime; however, it also speeds up performance at runtime by
simplfying the logic greatly.
Please let me know what you think!
Closes #59
* Address Travis/Vint errors
For some reason, ale isn't running vint for me...
* Incorporate feedback, make fixes
Lazy-loading logic is much improved.
* Add header comments; remove incorrect workaround
* Remove unneeded plugin guards
* Fix lazy-loading linter logic
Set the wrong variable....
* Fix capitialization
2016-10-10 18:51:29 +00:00
|
|
|
" Some errors have line numbers beyond the end of the file,
|
|
|
|
" so we need to adjust them so they set the error at the last line
|
|
|
|
" of the file instead.
|
2016-10-10 23:00:09 +00:00
|
|
|
let l:last_line_number = ale#util#GetLineCount(a:buffer)
|
First pass at optimizing ale to autoload (#80)
* First pass at optimizing ale to autoload
First off, the structure/function names should be revised a bit,
but I will wait for @w0rp's input before unifying the naming style.
Second off, the docs probably need some more work, I just did some
simple find-and-replace work.
With that said, this pull brings major performance gains for ale. On my
slowest system, fully loading ale and all its code takes around 150ms.
I have moved all of ale's autoload-able code to autoload/, and in
addition, implemented lazy-loading of linters. This brings load time on
that same system down to 5ms.
The only downside of lazy loading is that `g:ale_linters` cannot be
changed at runtime; however, it also speeds up performance at runtime by
simplfying the logic greatly.
Please let me know what you think!
Closes #59
* Address Travis/Vint errors
For some reason, ale isn't running vint for me...
* Incorporate feedback, make fixes
Lazy-loading logic is much improved.
* Add header comments; remove incorrect workaround
* Remove unneeded plugin guards
* Fix lazy-loading linter logic
Set the wrong variable....
* Fix capitialization
2016-10-10 18:51:29 +00:00
|
|
|
|
2017-02-26 14:51:22 +00:00
|
|
|
for l:old_item in a:loclist
|
|
|
|
" Copy the loclist item with some default values and corrections.
|
|
|
|
"
|
|
|
|
" line and column numbers will be converted to numbers.
|
|
|
|
" The buffer will default to the buffer being checked.
|
|
|
|
" The vcol setting will default to 0, a byte index.
|
|
|
|
" The error type will default to 'E' for errors.
|
|
|
|
" The error number will default to -1.
|
|
|
|
"
|
|
|
|
" The line number and text are the only required keys.
|
|
|
|
"
|
|
|
|
" The linter_name will be set on the errors so it can be used in
|
|
|
|
" output, filtering, etc..
|
|
|
|
let l:item = {
|
2017-08-19 23:05:15 +00:00
|
|
|
\ 'bufnr': a:buffer,
|
2017-02-26 14:51:22 +00:00
|
|
|
\ 'text': l:old_item.text,
|
|
|
|
\ 'lnum': str2nr(l:old_item.lnum),
|
|
|
|
\ 'col': str2nr(get(l:old_item, 'col', 0)),
|
2018-04-08 16:17:30 +00:00
|
|
|
\ 'vcol': 0,
|
2017-02-26 14:51:22 +00:00
|
|
|
\ 'type': get(l:old_item, 'type', 'E'),
|
|
|
|
\ 'nr': get(l:old_item, 'nr', -1),
|
2017-06-13 16:53:47 +00:00
|
|
|
\ 'linter_name': a:linter_name,
|
2017-02-26 14:51:22 +00:00
|
|
|
\}
|
|
|
|
|
2018-10-29 18:28:28 +00:00
|
|
|
if a:from_other_source
|
|
|
|
let l:item.from_other_source = 1
|
|
|
|
endif
|
|
|
|
|
2017-11-13 23:34:00 +00:00
|
|
|
if has_key(l:old_item, 'code')
|
|
|
|
let l:item.code = l:old_item.code
|
|
|
|
endif
|
|
|
|
|
2020-08-23 18:55:42 +00:00
|
|
|
let l:old_name = get(l:old_item, 'filename', '')
|
|
|
|
|
|
|
|
" Map parsed from output to local filesystem files.
|
|
|
|
if !empty(l:old_name) && !empty(l:mappings)
|
|
|
|
let l:old_name = ale#filename_mapping#Map(l:old_name, l:mappings)
|
|
|
|
endif
|
|
|
|
|
|
|
|
if !empty(l:old_name) && !ale#path#IsTempName(l:old_name)
|
2017-08-10 22:08:32 +00:00
|
|
|
" Use the filename given.
|
2017-08-19 23:05:15 +00:00
|
|
|
" Temporary files are assumed to be for this buffer,
|
|
|
|
" and the filename is not included then, because it looks bad
|
|
|
|
" in the loclist window.
|
2020-08-23 18:55:42 +00:00
|
|
|
let l:filename = l:old_name
|
2017-08-10 22:08:32 +00:00
|
|
|
let l:item.filename = l:filename
|
|
|
|
|
|
|
|
if has_key(l:old_item, 'bufnr')
|
|
|
|
" If a buffer number is also given, include that too.
|
|
|
|
" If Vim detects that he buffer number is valid, it will
|
|
|
|
" be used instead of the filename.
|
|
|
|
let l:item.bufnr = l:old_item.bufnr
|
|
|
|
elseif has_key(l:bufnr_map, l:filename)
|
|
|
|
" Get the buffer number from the map, which can be faster.
|
|
|
|
let l:item.bufnr = l:bufnr_map[l:filename]
|
|
|
|
else
|
|
|
|
" Look up the buffer number.
|
|
|
|
let l:item.bufnr = bufnr(l:filename)
|
|
|
|
let l:bufnr_map[l:filename] = l:item.bufnr
|
|
|
|
endif
|
|
|
|
elseif has_key(l:old_item, 'bufnr')
|
|
|
|
let l:item.bufnr = l:old_item.bufnr
|
|
|
|
endif
|
|
|
|
|
2017-03-02 07:14:30 +00:00
|
|
|
if has_key(l:old_item, 'detail')
|
|
|
|
let l:item.detail = l:old_item.detail
|
|
|
|
endif
|
|
|
|
|
2017-05-31 12:14:39 +00:00
|
|
|
" Pass on a end_col key if set, used for highlights.
|
2017-05-16 17:12:49 +00:00
|
|
|
if has_key(l:old_item, 'end_col')
|
|
|
|
let l:item.end_col = str2nr(l:old_item.end_col)
|
|
|
|
endif
|
|
|
|
|
2017-05-31 12:14:39 +00:00
|
|
|
if has_key(l:old_item, 'end_lnum')
|
|
|
|
let l:item.end_lnum = str2nr(l:old_item.end_lnum)
|
2022-04-01 08:13:27 +00:00
|
|
|
|
|
|
|
" When the error ends after the end of the file, put it at the
|
|
|
|
" end. This is only done for the current buffer.
|
|
|
|
if l:item.bufnr == a:buffer && l:item.end_lnum > l:last_line_number
|
|
|
|
let l:item.end_lnum = l:last_line_number
|
|
|
|
endif
|
2017-05-31 12:14:39 +00:00
|
|
|
endif
|
|
|
|
|
2017-05-20 22:32:41 +00:00
|
|
|
if has_key(l:old_item, 'sub_type')
|
|
|
|
let l:item.sub_type = l:old_item.sub_type
|
|
|
|
endif
|
|
|
|
|
2017-06-24 11:35:01 +00:00
|
|
|
if l:item.lnum < 1
|
|
|
|
" When errors appear before line 1, put them at line 1.
|
2016-10-10 23:00:09 +00:00
|
|
|
let l:item.lnum = 1
|
2017-08-19 19:15:36 +00:00
|
|
|
elseif l:item.bufnr == a:buffer && l:item.lnum > l:last_line_number
|
2017-02-26 14:51:22 +00:00
|
|
|
" When errors go beyond the end of the file, put them at the end.
|
2017-08-19 19:15:36 +00:00
|
|
|
" This is only done for the current buffer.
|
2016-10-10 23:00:09 +00:00
|
|
|
let l:item.lnum = l:last_line_number
|
2018-04-08 16:17:30 +00:00
|
|
|
elseif get(l:old_item, 'vcol', 0)
|
|
|
|
" Convert virtual column positions to byte positions.
|
|
|
|
" The positions will be off if the buffer has changed recently.
|
|
|
|
let l:line = getbufline(a:buffer, l:item.lnum)[0]
|
|
|
|
|
|
|
|
let l:item.col = ale#util#Col(l:line, l:item.col)
|
|
|
|
|
|
|
|
if has_key(l:item, 'end_col')
|
|
|
|
let l:end_line = get(l:item, 'end_lnum', l:line) != l:line
|
|
|
|
\ ? getbufline(a:buffer, l:item.end_lnum)[0]
|
|
|
|
\ : l:line
|
|
|
|
|
|
|
|
let l:item.end_col = ale#util#Col(l:end_line, l:item.end_col)
|
|
|
|
endif
|
First pass at optimizing ale to autoload (#80)
* First pass at optimizing ale to autoload
First off, the structure/function names should be revised a bit,
but I will wait for @w0rp's input before unifying the naming style.
Second off, the docs probably need some more work, I just did some
simple find-and-replace work.
With that said, this pull brings major performance gains for ale. On my
slowest system, fully loading ale and all its code takes around 150ms.
I have moved all of ale's autoload-able code to autoload/, and in
addition, implemented lazy-loading of linters. This brings load time on
that same system down to 5ms.
The only downside of lazy loading is that `g:ale_linters` cannot be
changed at runtime; however, it also speeds up performance at runtime by
simplfying the logic greatly.
Please let me know what you think!
Closes #59
* Address Travis/Vint errors
For some reason, ale isn't running vint for me...
* Incorporate feedback, make fixes
Lazy-loading logic is much improved.
* Add header comments; remove incorrect workaround
* Remove unneeded plugin guards
* Fix lazy-loading linter logic
Set the wrong variable....
* Fix capitialization
2016-10-10 18:51:29 +00:00
|
|
|
endif
|
2017-02-26 14:51:22 +00:00
|
|
|
|
|
|
|
call add(l:new_loclist, l:item)
|
First pass at optimizing ale to autoload (#80)
* First pass at optimizing ale to autoload
First off, the structure/function names should be revised a bit,
but I will wait for @w0rp's input before unifying the naming style.
Second off, the docs probably need some more work, I just did some
simple find-and-replace work.
With that said, this pull brings major performance gains for ale. On my
slowest system, fully loading ale and all its code takes around 150ms.
I have moved all of ale's autoload-able code to autoload/, and in
addition, implemented lazy-loading of linters. This brings load time on
that same system down to 5ms.
The only downside of lazy loading is that `g:ale_linters` cannot be
changed at runtime; however, it also speeds up performance at runtime by
simplfying the logic greatly.
Please let me know what you think!
Closes #59
* Address Travis/Vint errors
For some reason, ale isn't running vint for me...
* Incorporate feedback, make fixes
Lazy-loading logic is much improved.
* Add header comments; remove incorrect workaround
* Remove unneeded plugin guards
* Fix lazy-loading linter logic
Set the wrong variable....
* Fix capitialization
2016-10-10 18:51:29 +00:00
|
|
|
endfor
|
2017-02-26 14:51:22 +00:00
|
|
|
|
2017-06-14 16:59:13 +00:00
|
|
|
let l:type_map = get(ale#Var(a:buffer, 'type_map'), a:linter_name, {})
|
|
|
|
|
|
|
|
if !empty(l:type_map)
|
|
|
|
call s:RemapItemTypes(l:type_map, l:new_loclist)
|
|
|
|
endif
|
|
|
|
|
2017-02-26 14:51:22 +00:00
|
|
|
return l:new_loclist
|
First pass at optimizing ale to autoload (#80)
* First pass at optimizing ale to autoload
First off, the structure/function names should be revised a bit,
but I will wait for @w0rp's input before unifying the naming style.
Second off, the docs probably need some more work, I just did some
simple find-and-replace work.
With that said, this pull brings major performance gains for ale. On my
slowest system, fully loading ale and all its code takes around 150ms.
I have moved all of ale's autoload-able code to autoload/, and in
addition, implemented lazy-loading of linters. This brings load time on
that same system down to 5ms.
The only downside of lazy loading is that `g:ale_linters` cannot be
changed at runtime; however, it also speeds up performance at runtime by
simplfying the logic greatly.
Please let me know what you think!
Closes #59
* Address Travis/Vint errors
For some reason, ale isn't running vint for me...
* Incorporate feedback, make fixes
Lazy-loading logic is much improved.
* Add header comments; remove incorrect workaround
* Remove unneeded plugin guards
* Fix lazy-loading linter logic
Set the wrong variable....
* Fix capitialization
2016-10-10 18:51:29 +00:00
|
|
|
endfunction
|
|
|
|
|
2017-02-11 18:14:18 +00:00
|
|
|
" Given part of a command, replace any % with %%, so that no characters in
|
|
|
|
" the string will be replaced with filenames, etc.
|
|
|
|
function! ale#engine#EscapeCommandPart(command_part) abort
|
2019-01-26 19:33:52 +00:00
|
|
|
" TODO: Emit deprecation warning here later.
|
|
|
|
return ale#command#EscapeCommandPart(a:command_part)
|
2017-02-11 18:14:18 +00:00
|
|
|
endfunction
|
|
|
|
|
2017-07-07 22:47:41 +00:00
|
|
|
" Run a job.
|
|
|
|
"
|
2019-02-21 21:24:41 +00:00
|
|
|
" Returns 1 when a job was started successfully.
|
2019-02-13 17:53:01 +00:00
|
|
|
function! s:RunJob(command, options) abort
|
2019-02-21 21:24:41 +00:00
|
|
|
if ale#command#IsDeferred(a:command)
|
|
|
|
let a:command.result_callback = {
|
|
|
|
\ command -> s:RunJob(command, a:options)
|
|
|
|
\}
|
|
|
|
|
|
|
|
return 1
|
|
|
|
endif
|
|
|
|
|
2019-02-13 17:53:01 +00:00
|
|
|
let l:command = a:command
|
2018-07-05 19:56:31 +00:00
|
|
|
|
|
|
|
if empty(l:command)
|
2019-02-13 17:53:01 +00:00
|
|
|
return 0
|
2018-07-05 19:56:31 +00:00
|
|
|
endif
|
|
|
|
|
2021-03-01 20:11:10 +00:00
|
|
|
let l:cwd = a:options.cwd
|
2018-07-05 19:56:31 +00:00
|
|
|
let l:executable = a:options.executable
|
2017-02-09 23:32:57 +00:00
|
|
|
let l:buffer = a:options.buffer
|
|
|
|
let l:linter = a:options.linter
|
|
|
|
let l:output_stream = a:options.output_stream
|
2020-08-28 13:02:05 +00:00
|
|
|
let l:read_buffer = a:options.read_buffer && !a:options.lint_file
|
2017-08-14 09:00:46 +00:00
|
|
|
let l:info = g:ale_buffer_info[l:buffer]
|
2016-09-11 15:49:55 +00:00
|
|
|
|
2019-02-08 08:41:38 +00:00
|
|
|
let l:Callback = function('s:HandleExit', [{
|
|
|
|
\ 'linter': l:linter,
|
|
|
|
\ 'executable': l:executable,
|
|
|
|
\}])
|
|
|
|
let l:result = ale#command#Run(l:buffer, l:command, l:Callback, {
|
2021-03-01 20:11:10 +00:00
|
|
|
\ 'cwd': l:cwd,
|
2019-02-06 22:00:11 +00:00
|
|
|
\ 'output_stream': l:output_stream,
|
|
|
|
\ 'executable': l:executable,
|
|
|
|
\ 'read_buffer': l:read_buffer,
|
2020-08-18 22:03:43 +00:00
|
|
|
\ 'log_output': 1,
|
2020-08-23 18:55:42 +00:00
|
|
|
\ 'filename_mappings': ale#GetFilenameMappings(l:buffer, l:linter.name),
|
2019-02-06 22:00:11 +00:00
|
|
|
\})
|
2017-02-14 23:44:37 +00:00
|
|
|
|
2019-02-14 10:10:46 +00:00
|
|
|
" Only proceed if the job is being run.
|
2019-02-21 21:24:41 +00:00
|
|
|
if empty(l:result)
|
2019-02-08 08:41:38 +00:00
|
|
|
return 0
|
|
|
|
endif
|
2017-08-14 09:00:46 +00:00
|
|
|
|
2019-02-14 10:10:46 +00:00
|
|
|
call ale#engine#MarkLinterActive(l:info, l:linter)
|
2017-02-14 23:44:37 +00:00
|
|
|
|
2019-02-08 08:41:38 +00:00
|
|
|
silent doautocmd <nomodeline> User ALEJobStarted
|
|
|
|
|
|
|
|
return 1
|
2016-09-08 23:23:26 +00:00
|
|
|
endfunction
|
2016-10-17 22:26:19 +00:00
|
|
|
|
2020-09-09 20:42:27 +00:00
|
|
|
function! s:StopCurrentJobs(buffer, clear_lint_file_jobs, linter_slots) abort
|
2019-02-14 10:10:46 +00:00
|
|
|
let l:info = get(g:ale_buffer_info, a:buffer, {})
|
2019-02-06 22:00:11 +00:00
|
|
|
call ale#command#StopJobs(a:buffer, 'linter')
|
|
|
|
|
2019-02-14 10:10:46 +00:00
|
|
|
" Update the active linter list, clearing out anything not running.
|
|
|
|
if a:clear_lint_file_jobs
|
2019-02-06 22:00:11 +00:00
|
|
|
call ale#command#StopJobs(a:buffer, 'file_linter')
|
2019-02-14 10:10:46 +00:00
|
|
|
let l:info.active_linter_list = []
|
|
|
|
else
|
2020-09-09 20:42:27 +00:00
|
|
|
let l:lint_file_map = {}
|
|
|
|
|
|
|
|
" Use a previously computed map of `lint_file` values to find
|
|
|
|
" linters that are used for linting files.
|
|
|
|
for [l:lint_file, l:linter] in a:linter_slots
|
|
|
|
if l:lint_file is 1
|
|
|
|
let l:lint_file_map[l:linter.name] = 1
|
|
|
|
endif
|
|
|
|
endfor
|
|
|
|
|
2019-02-06 22:00:11 +00:00
|
|
|
" Keep jobs for linting files when we're only linting buffers.
|
2020-09-09 20:42:27 +00:00
|
|
|
call filter(l:info.active_linter_list, 'get(l:lint_file_map, v:val.name)')
|
2019-02-14 10:10:46 +00:00
|
|
|
endif
|
2017-06-06 15:44:01 +00:00
|
|
|
endfunction
|
|
|
|
|
2020-09-08 20:40:10 +00:00
|
|
|
function! ale#engine#Stop(buffer) abort
|
2020-09-09 20:42:27 +00:00
|
|
|
call s:StopCurrentJobs(a:buffer, 1, [])
|
2020-09-08 20:40:10 +00:00
|
|
|
endfunction
|
|
|
|
|
2017-07-07 22:47:41 +00:00
|
|
|
function! s:RemoveProblemsForDisabledLinters(buffer, linters) abort
|
|
|
|
" Figure out which linters are still enabled, and remove
|
|
|
|
" problems for linters which are no longer enabled.
|
2018-10-29 18:28:28 +00:00
|
|
|
" Problems from other sources will be kept.
|
2017-07-07 22:47:41 +00:00
|
|
|
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', []),
|
2018-10-29 18:28:28 +00:00
|
|
|
\ 'get(v:val, ''from_other_source'') || get(l:name_map, get(v:val, ''linter_name''))',
|
2017-07-07 22:47:41 +00:00
|
|
|
\)
|
2017-06-08 16:28:38 +00:00
|
|
|
endfunction
|
2017-03-14 23:51:57 +00:00
|
|
|
|
2017-08-19 19:15:36 +00:00
|
|
|
function! s:AddProblemsFromOtherBuffers(buffer, linters) abort
|
|
|
|
let l:filename = expand('#' . a:buffer . ':p')
|
|
|
|
let l:loclist = []
|
|
|
|
let l:name_map = {}
|
|
|
|
|
|
|
|
" Build a map of the active linters.
|
|
|
|
for l:linter in a:linters
|
|
|
|
let l:name_map[l:linter.name] = 1
|
|
|
|
endfor
|
|
|
|
|
|
|
|
" Find the items from other buffers, for the linters that are enabled.
|
|
|
|
for l:info in values(g:ale_buffer_info)
|
|
|
|
for l:item in l:info.loclist
|
|
|
|
if has_key(l:item, 'filename')
|
|
|
|
\&& l:item.filename is# l:filename
|
|
|
|
\&& has_key(l:name_map, l:item.linter_name)
|
2017-08-22 21:45:55 +00:00
|
|
|
" Copy the items and set the buffer numbers to this one.
|
|
|
|
let l:new_item = copy(l:item)
|
|
|
|
let l:new_item.bufnr = a:buffer
|
|
|
|
call add(l:loclist, l:new_item)
|
2017-08-19 19:15:36 +00:00
|
|
|
endif
|
|
|
|
endfor
|
|
|
|
endfor
|
|
|
|
|
|
|
|
if !empty(l:loclist)
|
|
|
|
call sort(l:loclist, function('ale#util#LocItemCompareWithText'))
|
|
|
|
call uniq(l:loclist, function('ale#util#LocItemCompareWithText'))
|
|
|
|
|
2017-08-22 21:45:55 +00:00
|
|
|
" Set the loclist variable, used by some parts of ALE.
|
|
|
|
let g:ale_buffer_info[a:buffer].loclist = l:loclist
|
2017-08-19 19:15:36 +00:00
|
|
|
call ale#engine#SetResults(a:buffer, l:loclist)
|
|
|
|
endif
|
|
|
|
endfunction
|
|
|
|
|
2020-08-28 13:02:05 +00:00
|
|
|
function! s:RunIfExecutable(buffer, linter, lint_file, executable) abort
|
2019-02-12 18:05:33 +00:00
|
|
|
if ale#command#IsDeferred(a:executable)
|
|
|
|
let a:executable.result_callback = {
|
2020-08-28 13:02:05 +00:00
|
|
|
\ executable -> s:RunIfExecutable(
|
|
|
|
\ a:buffer,
|
|
|
|
\ a:linter,
|
|
|
|
\ a:lint_file,
|
|
|
|
\ executable
|
|
|
|
\ )
|
2019-02-12 18:05:33 +00:00
|
|
|
\}
|
|
|
|
|
|
|
|
return 1
|
|
|
|
endif
|
|
|
|
|
|
|
|
if ale#engine#IsExecutable(a:buffer, a:executable)
|
|
|
|
" Use different job types for file or linter jobs.
|
2020-08-28 13:02:05 +00:00
|
|
|
let l:job_type = a:lint_file ? 'file_linter' : 'linter'
|
2019-02-12 18:05:33 +00:00
|
|
|
call setbufvar(a:buffer, 'ale_job_type', l:job_type)
|
|
|
|
|
2021-03-01 20:11:10 +00:00
|
|
|
" Get the cwd for the linter and set it before we call GetCommand.
|
|
|
|
" This will ensure that ale#command#Run uses it by default.
|
|
|
|
let l:cwd = ale#linter#GetCwd(a:buffer, a:linter)
|
|
|
|
|
|
|
|
if l:cwd isnot v:null
|
|
|
|
call ale#command#SetCwd(a:buffer, l:cwd)
|
|
|
|
endif
|
|
|
|
|
2019-02-13 17:53:01 +00:00
|
|
|
let l:command = ale#linter#GetCommand(a:buffer, a:linter)
|
2021-03-01 20:11:10 +00:00
|
|
|
|
|
|
|
if l:cwd isnot v:null
|
|
|
|
call ale#command#ResetCwd(a:buffer)
|
|
|
|
endif
|
|
|
|
|
2019-02-13 17:53:01 +00:00
|
|
|
let l:options = {
|
2021-03-01 20:11:10 +00:00
|
|
|
\ 'cwd': l:cwd,
|
2019-02-13 17:53:01 +00:00
|
|
|
\ 'executable': a:executable,
|
|
|
|
\ 'buffer': a:buffer,
|
|
|
|
\ 'linter': a:linter,
|
|
|
|
\ 'output_stream': get(a:linter, 'output_stream', 'stdout'),
|
|
|
|
\ 'read_buffer': a:linter.read_buffer,
|
2020-08-28 13:02:05 +00:00
|
|
|
\ 'lint_file': a:lint_file,
|
2019-02-13 17:53:01 +00:00
|
|
|
\}
|
|
|
|
|
|
|
|
return s:RunJob(l:command, l:options)
|
2019-02-12 18:05:33 +00:00
|
|
|
endif
|
|
|
|
|
|
|
|
return 0
|
|
|
|
endfunction
|
|
|
|
|
2017-07-07 22:47:41 +00:00
|
|
|
" Run a linter for a buffer.
|
|
|
|
"
|
|
|
|
" Returns 1 if the linter was successfully run.
|
2020-08-28 13:02:05 +00:00
|
|
|
function! s:RunLinter(buffer, linter, lint_file) abort
|
2017-07-26 09:44:07 +00:00
|
|
|
if !empty(a:linter.lsp)
|
2018-06-15 08:53:13 +00:00
|
|
|
return ale#lsp_linter#CheckWithLSP(a:buffer, a:linter)
|
2017-07-26 09:37:37 +00:00
|
|
|
else
|
2017-07-02 12:17:24 +00:00
|
|
|
let l:executable = ale#linter#GetExecutable(a:buffer, a:linter)
|
2017-06-08 16:28:38 +00:00
|
|
|
|
2020-08-28 13:02:05 +00:00
|
|
|
return s:RunIfExecutable(a:buffer, a:linter, a:lint_file, l:executable)
|
2017-07-07 22:47:41 +00:00
|
|
|
endif
|
|
|
|
|
|
|
|
return 0
|
|
|
|
endfunction
|
|
|
|
|
2020-09-09 20:42:27 +00:00
|
|
|
function! s:GetLintFileSlots(buffer, linters) abort
|
|
|
|
let l:linter_slots = []
|
|
|
|
|
|
|
|
for l:linter in a:linters
|
|
|
|
let l:LintFile = l:linter.lint_file
|
|
|
|
|
|
|
|
if type(l:LintFile) is v:t_func
|
|
|
|
let l:LintFile = l:LintFile(a:buffer)
|
|
|
|
endif
|
|
|
|
|
|
|
|
call add(l:linter_slots, [l:LintFile, l:linter])
|
|
|
|
endfor
|
|
|
|
|
|
|
|
return l:linter_slots
|
|
|
|
endfunction
|
|
|
|
|
2020-08-28 13:02:05 +00:00
|
|
|
function! s:GetLintFileValues(slots, Callback) abort
|
|
|
|
let l:deferred_list = []
|
|
|
|
let l:new_slots = []
|
2017-07-07 22:47:41 +00:00
|
|
|
|
2020-08-28 13:02:05 +00:00
|
|
|
for [l:lint_file, l:linter] in a:slots
|
|
|
|
while ale#command#IsDeferred(l:lint_file) && has_key(l:lint_file, 'value')
|
|
|
|
" If we've already computed the return value, use it.
|
|
|
|
let l:lint_file = l:lint_file.value
|
|
|
|
endwhile
|
2017-07-07 22:47:41 +00:00
|
|
|
|
2020-08-28 13:02:05 +00:00
|
|
|
if ale#command#IsDeferred(l:lint_file)
|
|
|
|
" If we are going to return the result later, wait for it.
|
|
|
|
call add(l:deferred_list, l:lint_file)
|
|
|
|
else
|
|
|
|
" If we have the value now, coerce it to 0 or 1.
|
|
|
|
let l:lint_file = l:lint_file is 1
|
|
|
|
endif
|
2017-12-10 13:03:03 +00:00
|
|
|
|
2020-08-28 13:02:05 +00:00
|
|
|
call add(l:new_slots, [l:lint_file, l:linter])
|
|
|
|
endfor
|
|
|
|
|
|
|
|
if !empty(l:deferred_list)
|
|
|
|
for l:deferred in l:deferred_list
|
|
|
|
let l:deferred.result_callback =
|
|
|
|
\ {-> s:GetLintFileValues(l:new_slots, a:Callback)}
|
|
|
|
endfor
|
|
|
|
else
|
|
|
|
call a:Callback(l:new_slots)
|
|
|
|
endif
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
function! s:RunLinters(
|
|
|
|
\ buffer,
|
2020-09-09 20:42:27 +00:00
|
|
|
\ linters,
|
2020-08-28 13:02:05 +00:00
|
|
|
\ slots,
|
|
|
|
\ should_lint_file,
|
|
|
|
\ new_buffer,
|
|
|
|
\) abort
|
2020-09-09 20:42:27 +00:00
|
|
|
call s:StopCurrentJobs(a:buffer, a:should_lint_file, a:slots)
|
|
|
|
call s:RemoveProblemsForDisabledLinters(a:buffer, a:linters)
|
|
|
|
|
|
|
|
" We can only clear the results if we aren't checking the buffer.
|
|
|
|
let l:can_clear_results = !ale#engine#IsCheckingBuffer(a:buffer)
|
|
|
|
|
|
|
|
silent doautocmd <nomodeline> User ALELintPre
|
2020-08-28 13:02:05 +00:00
|
|
|
|
|
|
|
for [l:lint_file, l:linter] in a:slots
|
2017-07-31 21:36:30 +00:00
|
|
|
" Only run lint_file linters if we should.
|
2020-08-28 13:02:05 +00:00
|
|
|
if !l:lint_file || a:should_lint_file
|
|
|
|
if s:RunLinter(a:buffer, l:linter, l:lint_file)
|
2017-07-31 21:36:30 +00:00
|
|
|
" If a single linter ran, we shouldn't clear everything.
|
|
|
|
let l:can_clear_results = 0
|
|
|
|
endif
|
|
|
|
else
|
|
|
|
" If we skipped running a lint_file linter still in the list,
|
|
|
|
" we shouldn't clear everything.
|
|
|
|
let l:can_clear_results = 0
|
2017-06-08 16:28:38 +00:00
|
|
|
endif
|
2017-07-07 22:47:41 +00:00
|
|
|
endfor
|
|
|
|
|
2017-07-31 21:36:30 +00:00
|
|
|
" Clear the results if we can. This needs to be done when linters are
|
|
|
|
" disabled, or ALE itself is disabled.
|
|
|
|
if l:can_clear_results
|
2017-07-07 22:47:41 +00:00
|
|
|
call ale#engine#SetResults(a:buffer, [])
|
2020-08-28 13:02:05 +00:00
|
|
|
elseif a:new_buffer
|
|
|
|
call s:AddProblemsFromOtherBuffers(
|
|
|
|
\ a:buffer,
|
|
|
|
\ map(copy(a:slots), 'v:val[1]')
|
|
|
|
\)
|
2017-07-07 22:47:41 +00:00
|
|
|
endif
|
|
|
|
endfunction
|
|
|
|
|
2020-08-28 13:02:05 +00:00
|
|
|
function! ale#engine#RunLinters(buffer, linters, should_lint_file) abort
|
|
|
|
" Initialise the buffer information if needed.
|
|
|
|
let l:new_buffer = ale#engine#InitBufferInfo(a:buffer)
|
|
|
|
|
2020-09-09 20:42:27 +00:00
|
|
|
call s:GetLintFileValues(
|
|
|
|
\ s:GetLintFileSlots(a:buffer, a:linters),
|
|
|
|
\ {
|
|
|
|
\ slots -> s:RunLinters(
|
|
|
|
\ a:buffer,
|
|
|
|
\ a:linters,
|
|
|
|
\ slots,
|
|
|
|
\ a:should_lint_file,
|
|
|
|
\ l:new_buffer,
|
|
|
|
\ )
|
|
|
|
\ }
|
|
|
|
\)
|
2020-08-28 13:02:05 +00:00
|
|
|
endfunction
|
|
|
|
|
2017-07-07 22:47:41 +00:00
|
|
|
" 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
|
2017-10-14 18:22:19 +00:00
|
|
|
" Don't bother with cleanup code when newer NeoVim versions are exiting.
|
|
|
|
if get(v:, 'exiting', v:null) isnot v:null
|
|
|
|
return
|
|
|
|
endif
|
|
|
|
|
2019-05-13 23:21:58 +00:00
|
|
|
if exists('*ale#lsp#CloseDocument')
|
|
|
|
call ale#lsp#CloseDocument(a:buffer)
|
|
|
|
endif
|
|
|
|
|
2017-07-15 17:44:45 +00:00
|
|
|
if !has_key(g:ale_buffer_info, a:buffer)
|
|
|
|
return
|
|
|
|
endif
|
|
|
|
|
2017-07-07 22:47:41 +00:00
|
|
|
call ale#engine#RunLinters(a:buffer, [], 1)
|
|
|
|
|
|
|
|
call remove(g:ale_buffer_info, a:buffer)
|
2016-10-25 19:25:23 +00:00
|
|
|
endfunction
|
|
|
|
|
2016-10-24 19:21:32 +00:00
|
|
|
" Given a buffer number, return the warnings and errors for a given buffer.
|
|
|
|
function! ale#engine#GetLoclist(buffer) abort
|
|
|
|
if !has_key(g:ale_buffer_info, a:buffer)
|
|
|
|
return []
|
|
|
|
endif
|
|
|
|
|
|
|
|
return g:ale_buffer_info[a:buffer].loclist
|
|
|
|
endfunction
|