mirror of
https://github.com/amix/vimrc
synced 2025-06-16 01:25:00 +08:00
Updated plugins
This commit is contained in:
@ -6,35 +6,12 @@
|
||||
let g:ale_echo_msg_error_str = get(g:, 'ale_echo_msg_error_str', 'Error')
|
||||
let g:ale_echo_msg_info_str = get(g:, 'ale_echo_msg_info_str', 'Info')
|
||||
let g:ale_echo_msg_warning_str = get(g:, 'ale_echo_msg_warning_str', 'Warning')
|
||||
" Ignoring linters, for disabling some, or ignoring LSP diagnostics.
|
||||
let g:ale_linters_ignore = get(g:, 'ale_linters_ignore', {})
|
||||
|
||||
let s:lint_timer = -1
|
||||
let s:queued_buffer_number = -1
|
||||
let s:should_lint_file_for_buffer = {}
|
||||
let s:error_delay_ms = 1000 * 60 * 2
|
||||
|
||||
let s:timestamp_map = {}
|
||||
|
||||
" Given a key for a script variable for tracking the time to wait until
|
||||
" a given function should be called, a funcref for a function to call, and
|
||||
" a List of arguments, call the function and return whatever value it returns.
|
||||
"
|
||||
" If the function throws an exception, then the function will not be called
|
||||
" for a while, and 0 will be returned instead.
|
||||
function! ale#CallWithCooldown(timestamp_key, func, arglist) abort
|
||||
let l:now = ale#util#ClockMilliseconds()
|
||||
|
||||
if l:now < get(s:timestamp_map, a:timestamp_key, -1)
|
||||
return 0
|
||||
endif
|
||||
|
||||
let s:timestamp_map[a:timestamp_key] = l:now + s:error_delay_ms
|
||||
|
||||
let l:return_value = call(a:func, a:arglist)
|
||||
|
||||
let s:timestamp_map[a:timestamp_key] = -1
|
||||
|
||||
return l:return_value
|
||||
endfunction
|
||||
|
||||
" Return 1 if a file is too large for ALE to handle.
|
||||
function! ale#FileTooLarge(buffer) abort
|
||||
@ -114,30 +91,22 @@ function! ale#Queue(delay, ...) abort
|
||||
let l:linting_flag = get(a:000, 0, '')
|
||||
let l:buffer = get(a:000, 1, bufnr(''))
|
||||
|
||||
return ale#CallWithCooldown(
|
||||
\ 'dont_queue_until',
|
||||
\ function('s:ALEQueueImpl'),
|
||||
\ [a:delay, l:linting_flag, l:buffer],
|
||||
\)
|
||||
endfunction
|
||||
|
||||
function! s:ALEQueueImpl(delay, linting_flag, buffer) abort
|
||||
if a:linting_flag isnot# '' && a:linting_flag isnot# 'lint_file'
|
||||
if l:linting_flag isnot# '' && l:linting_flag isnot# 'lint_file'
|
||||
throw "linting_flag must be either '' or 'lint_file'"
|
||||
endif
|
||||
|
||||
if type(a:buffer) != type(0)
|
||||
if type(l:buffer) != type(0)
|
||||
throw 'buffer_number must be a Number'
|
||||
endif
|
||||
|
||||
if ale#ShouldDoNothing(a:buffer)
|
||||
if ale#ShouldDoNothing(l:buffer)
|
||||
return
|
||||
endif
|
||||
|
||||
" Remember that we want to check files for this buffer.
|
||||
" We will remember this until we finally run the linters, via any event.
|
||||
if a:linting_flag is# 'lint_file'
|
||||
let s:should_lint_file_for_buffer[a:buffer] = 1
|
||||
if l:linting_flag is# 'lint_file'
|
||||
let s:should_lint_file_for_buffer[l:buffer] = 1
|
||||
endif
|
||||
|
||||
if s:lint_timer != -1
|
||||
@ -145,24 +114,24 @@ function! s:ALEQueueImpl(delay, linting_flag, buffer) abort
|
||||
let s:lint_timer = -1
|
||||
endif
|
||||
|
||||
let l:linters = ale#linter#Get(getbufvar(a:buffer, '&filetype'))
|
||||
let l:linters = ale#linter#Get(getbufvar(l:buffer, '&filetype'))
|
||||
|
||||
" Don't set up buffer data and so on if there are no linters to run.
|
||||
if empty(l:linters)
|
||||
" If we have some previous buffer data, then stop any jobs currently
|
||||
" running and clear everything.
|
||||
if has_key(g:ale_buffer_info, a:buffer)
|
||||
call ale#engine#RunLinters(a:buffer, [], 1)
|
||||
if has_key(g:ale_buffer_info, l:buffer)
|
||||
call ale#engine#RunLinters(l:buffer, [], 1)
|
||||
endif
|
||||
|
||||
return
|
||||
endif
|
||||
|
||||
if a:delay > 0
|
||||
let s:queued_buffer_number = a:buffer
|
||||
let s:queued_buffer_number = l:buffer
|
||||
let s:lint_timer = timer_start(a:delay, function('ale#Lint'))
|
||||
else
|
||||
call ale#Lint(-1, a:buffer)
|
||||
call ale#Lint(-1, l:buffer)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
@ -178,30 +147,29 @@ function! ale#Lint(...) abort
|
||||
let l:buffer = bufnr('')
|
||||
endif
|
||||
|
||||
return ale#CallWithCooldown(
|
||||
\ 'dont_lint_until',
|
||||
\ function('s:ALELintImpl'),
|
||||
\ [l:buffer],
|
||||
\)
|
||||
endfunction
|
||||
|
||||
function! s:ALELintImpl(buffer) abort
|
||||
if ale#ShouldDoNothing(a:buffer)
|
||||
if ale#ShouldDoNothing(l:buffer)
|
||||
return
|
||||
endif
|
||||
|
||||
" Use the filetype from the buffer
|
||||
let l:linters = ale#linter#Get(getbufvar(a:buffer, '&filetype'))
|
||||
let l:filetype = getbufvar(l:buffer, '&filetype')
|
||||
let l:linters = ale#linter#Get(l:filetype)
|
||||
let l:should_lint_file = 0
|
||||
|
||||
" Check if we previously requested checking the file.
|
||||
if has_key(s:should_lint_file_for_buffer, a:buffer)
|
||||
unlet s:should_lint_file_for_buffer[a:buffer]
|
||||
if has_key(s:should_lint_file_for_buffer, l:buffer)
|
||||
unlet s:should_lint_file_for_buffer[l:buffer]
|
||||
" Lint files if they exist.
|
||||
let l:should_lint_file = filereadable(expand('#' . a:buffer . ':p'))
|
||||
let l:should_lint_file = filereadable(expand('#' . l:buffer . ':p'))
|
||||
endif
|
||||
|
||||
call ale#engine#RunLinters(a:buffer, l:linters, l:should_lint_file)
|
||||
" Apply ignore lists for linters only if needed.
|
||||
let l:ignore_config = ale#Var(l:buffer, 'linters_ignore')
|
||||
let l:linters = !empty(l:ignore_config)
|
||||
\ ? ale#engine#ignore#Exclude(l:filetype, l:linters, l:ignore_config)
|
||||
\ : l:linters
|
||||
|
||||
call ale#engine#RunLinters(l:buffer, l:linters, l:should_lint_file)
|
||||
endfunction
|
||||
|
||||
" Reset flags indicating that files should be checked for all buffers.
|
||||
@ -209,10 +177,6 @@ function! ale#ResetLintFileMarkers() abort
|
||||
let s:should_lint_file_for_buffer = {}
|
||||
endfunction
|
||||
|
||||
function! ale#ResetErrorDelays() abort
|
||||
let s:timestamp_map = {}
|
||||
endfunction
|
||||
|
||||
let g:ale_has_override = get(g:, 'ale_has_override', {})
|
||||
|
||||
" Call has(), but check a global Dictionary so we can force flags on or off
|
||||
|
@ -1,77 +0,0 @@
|
||||
function! ale#autocmd#InitAuGroups() abort
|
||||
" This value used to be a Boolean as a Number, and is now a String.
|
||||
let l:text_changed = '' . g:ale_lint_on_text_changed
|
||||
|
||||
augroup ALEPatternOptionsGroup
|
||||
autocmd!
|
||||
autocmd BufEnter,BufRead * call ale#pattern_options#SetOptions(str2nr(expand('<abuf>')))
|
||||
augroup END
|
||||
|
||||
augroup ALERunOnTextChangedGroup
|
||||
autocmd!
|
||||
if g:ale_enabled
|
||||
if l:text_changed is? 'always' || l:text_changed is# '1'
|
||||
autocmd TextChanged,TextChangedI * call ale#Queue(g:ale_lint_delay)
|
||||
elseif l:text_changed is? 'normal'
|
||||
autocmd TextChanged * call ale#Queue(g:ale_lint_delay)
|
||||
elseif l:text_changed is? 'insert'
|
||||
autocmd TextChangedI * call ale#Queue(g:ale_lint_delay)
|
||||
endif
|
||||
endif
|
||||
augroup END
|
||||
|
||||
augroup ALERunOnEnterGroup
|
||||
autocmd!
|
||||
if g:ale_enabled
|
||||
" Handle everything that needs to happen when buffers are entered.
|
||||
autocmd BufEnter * call ale#events#EnterEvent(str2nr(expand('<abuf>')))
|
||||
endif
|
||||
if g:ale_enabled && g:ale_lint_on_enter
|
||||
autocmd BufWinEnter,BufRead * call ale#Queue(0, 'lint_file', str2nr(expand('<abuf>')))
|
||||
" Track when the file is changed outside of Vim.
|
||||
autocmd FileChangedShellPost * call ale#events#FileChangedEvent(str2nr(expand('<abuf>')))
|
||||
endif
|
||||
augroup END
|
||||
|
||||
augroup ALERunOnFiletypeChangeGroup
|
||||
autocmd!
|
||||
if g:ale_enabled && g:ale_lint_on_filetype_changed
|
||||
" Only start linting if the FileType actually changes after
|
||||
" opening a buffer. The FileType will fire when buffers are opened.
|
||||
autocmd FileType * call ale#events#FileTypeEvent(
|
||||
\ str2nr(expand('<abuf>')),
|
||||
\ expand('<amatch>')
|
||||
\)
|
||||
endif
|
||||
augroup END
|
||||
|
||||
augroup ALERunOnSaveGroup
|
||||
autocmd!
|
||||
autocmd BufWritePost * call ale#events#SaveEvent(str2nr(expand('<abuf>')))
|
||||
augroup END
|
||||
|
||||
augroup ALERunOnInsertLeave
|
||||
autocmd!
|
||||
if g:ale_enabled && g:ale_lint_on_insert_leave
|
||||
autocmd InsertLeave * call ale#Queue(0)
|
||||
endif
|
||||
augroup END
|
||||
|
||||
augroup ALECursorGroup
|
||||
autocmd!
|
||||
if g:ale_enabled && g:ale_echo_cursor
|
||||
autocmd CursorMoved,CursorHold * call ale#cursor#EchoCursorWarningWithDelay()
|
||||
" Look for a warning to echo as soon as we leave Insert mode.
|
||||
" The script's position variable used when moving the cursor will
|
||||
" not be changed here.
|
||||
autocmd InsertLeave * call ale#cursor#EchoCursorWarning()
|
||||
endif
|
||||
augroup END
|
||||
|
||||
if !g:ale_enabled
|
||||
augroup! ALERunOnTextChangedGroup
|
||||
augroup! ALERunOnEnterGroup
|
||||
augroup! ALERunOnInsertLeave
|
||||
augroup! ALECursorGroup
|
||||
endif
|
||||
endfunction
|
@ -34,7 +34,11 @@ function! ale#balloon#Expr() abort
|
||||
endfunction
|
||||
|
||||
function! ale#balloon#Disable() abort
|
||||
set noballooneval noballoonevalterm
|
||||
if has('balloon_eval_term')
|
||||
set noballoonevalterm
|
||||
endif
|
||||
|
||||
set noballooneval
|
||||
set balloonexpr=
|
||||
endfunction
|
||||
|
||||
|
@ -134,7 +134,11 @@ function! s:ReplaceCompleteopt() abort
|
||||
let b:ale_old_completopt = &l:completeopt
|
||||
endif
|
||||
|
||||
let &l:completeopt = 'menu,menuone,preview,noselect,noinsert'
|
||||
if &l:completeopt =~# 'preview'
|
||||
let &l:completeopt = 'menu,menuone,preview,noselect,noinsert'
|
||||
else
|
||||
let &l:completeopt = 'menu,menuone,noselect,noinsert'
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#completion#OmniFunc(findstart, base) abort
|
||||
@ -389,14 +393,13 @@ function! s:GetLSPCompletions(linter) abort
|
||||
\ ? function('ale#completion#HandleTSServerResponse')
|
||||
\ : function('ale#completion#HandleLSPResponse')
|
||||
|
||||
let l:lsp_details = ale#linter#StartLSP(l:buffer, a:linter, l:Callback)
|
||||
let l:lsp_details = ale#lsp_linter#StartLSP(l:buffer, a:linter, l:Callback)
|
||||
|
||||
if empty(l:lsp_details)
|
||||
return 0
|
||||
endif
|
||||
|
||||
let l:id = l:lsp_details.connection_id
|
||||
let l:root = l:lsp_details.project_root
|
||||
|
||||
if a:linter.lsp is# 'tsserver'
|
||||
let l:message = ale#lsp#tsserver_message#Completions(
|
||||
@ -408,7 +411,7 @@ function! s:GetLSPCompletions(linter) abort
|
||||
else
|
||||
" Send a message saying the buffer has changed first, otherwise
|
||||
" completions won't know what text is nearby.
|
||||
call ale#lsp#Send(l:id, ale#lsp#message#DidChange(l:buffer), l:root)
|
||||
call ale#lsp#NotifyForChanges(l:lsp_details)
|
||||
|
||||
" For LSP completions, we need to clamp the column to the length of
|
||||
" the line. python-language-server and perhaps others do not implement
|
||||
@ -424,7 +427,7 @@ function! s:GetLSPCompletions(linter) abort
|
||||
\)
|
||||
endif
|
||||
|
||||
let l:request_id = ale#lsp#Send(l:id, l:message, l:root)
|
||||
let l:request_id = ale#lsp#Send(l:id, l:message, l:lsp_details.project_root)
|
||||
|
||||
if l:request_id
|
||||
let b:ale_completion_info.conn_id = l:id
|
||||
|
@ -56,10 +56,6 @@ function! s:StopCursorTimer() abort
|
||||
endfunction
|
||||
|
||||
function! ale#cursor#EchoCursorWarning(...) abort
|
||||
return ale#CallWithCooldown('dont_echo_until', function('s:EchoImpl'), [])
|
||||
endfunction
|
||||
|
||||
function! s:EchoImpl() abort
|
||||
if !g:ale_echo_cursor
|
||||
return
|
||||
endif
|
||||
|
@ -214,10 +214,15 @@ function! ale#debugging#Info() abort
|
||||
" This must be done after linters are loaded.
|
||||
let l:variable_list = s:GetLinterVariables(l:filetype, l:enabled_names)
|
||||
|
||||
let l:fixers = ale#fix#registry#SuggestedFixers(l:filetype)
|
||||
let l:fixers = uniq(sort(l:fixers[0] + l:fixers[1]))
|
||||
let l:fixers_string = join(map(copy(l:fixers), '"\n " . v:val'), '')
|
||||
|
||||
call s:Echo(' Current Filetype: ' . l:filetype)
|
||||
call s:Echo('Available Linters: ' . string(l:all_names))
|
||||
call s:EchoLinterAliases(l:all_linters)
|
||||
call s:Echo(' Enabled Linters: ' . string(l:enabled_names))
|
||||
call s:Echo(' Suggested Fixers: ' . l:fixers_string)
|
||||
call s:Echo(' Linter Variables:')
|
||||
call s:Echo('')
|
||||
call s:EchoLinterVariables(l:variable_list)
|
||||
|
@ -65,14 +65,13 @@ function! s:GoToLSPDefinition(linter, options) abort
|
||||
\ ? function('ale#definition#HandleTSServerResponse')
|
||||
\ : function('ale#definition#HandleLSPResponse')
|
||||
|
||||
let l:lsp_details = ale#linter#StartLSP(l:buffer, a:linter, l:Callback)
|
||||
let l:lsp_details = ale#lsp_linter#StartLSP(l:buffer, a:linter, l:Callback)
|
||||
|
||||
if empty(l:lsp_details)
|
||||
return 0
|
||||
endif
|
||||
|
||||
let l:id = l:lsp_details.connection_id
|
||||
let l:root = l:lsp_details.project_root
|
||||
|
||||
if a:linter.lsp is# 'tsserver'
|
||||
let l:message = ale#lsp#tsserver_message#Definition(
|
||||
@ -83,7 +82,7 @@ function! s:GoToLSPDefinition(linter, options) abort
|
||||
else
|
||||
" Send a message saying the buffer has changed first, or the
|
||||
" definition position probably won't make sense.
|
||||
call ale#lsp#Send(l:id, ale#lsp#message#DidChange(l:buffer), l:root)
|
||||
call ale#lsp#NotifyForChanges(l:lsp_details)
|
||||
|
||||
let l:column = min([l:column, len(getline(l:line))])
|
||||
|
||||
@ -93,7 +92,7 @@ function! s:GoToLSPDefinition(linter, options) abort
|
||||
let l:message = ale#lsp#message#Definition(l:buffer, l:line, l:column)
|
||||
endif
|
||||
|
||||
let l:request_id = ale#lsp#Send(l:id, l:message, l:root)
|
||||
let l:request_id = ale#lsp#Send(l:id, l:message, l:lsp_details.project_root)
|
||||
|
||||
let s:go_to_definition_map[l:request_id] = {
|
||||
\ 'open_in_tab': get(a:options, 'open_in_tab', 0),
|
||||
|
@ -14,11 +14,6 @@ if !has_key(s:, 'job_info_map')
|
||||
let s:job_info_map = {}
|
||||
endif
|
||||
|
||||
" Associates LSP connection IDs with linter names.
|
||||
if !has_key(s:, 'lsp_linter_map')
|
||||
let s:lsp_linter_map = {}
|
||||
endif
|
||||
|
||||
if !has_key(s:, 'executable_cache_map')
|
||||
let s:executable_cache_map = {}
|
||||
endif
|
||||
@ -79,16 +74,6 @@ function! ale#engine#InitBufferInfo(buffer) abort
|
||||
return 0
|
||||
endfunction
|
||||
|
||||
" Clear LSP linter data for the linting engine.
|
||||
function! ale#engine#ClearLSPData() abort
|
||||
let s:lsp_linter_map = {}
|
||||
endfunction
|
||||
|
||||
" Just for tests.
|
||||
function! ale#engine#SetLSPLinterMap(replacement_map) abort
|
||||
let s:lsp_linter_map = a:replacement_map
|
||||
endfunction
|
||||
|
||||
" This function is documented and part of the public API.
|
||||
"
|
||||
" Return 1 if ALE is busy checking a given buffer
|
||||
@ -241,88 +226,6 @@ function! s:HandleExit(job_id, exit_code) abort
|
||||
call ale#engine#HandleLoclist(l:linter.name, l:buffer, l:loclist)
|
||||
endfunction
|
||||
|
||||
function! s:HandleLSPDiagnostics(conn_id, response) abort
|
||||
let l:linter_name = s:lsp_linter_map[a:conn_id]
|
||||
let l:filename = ale#path#FromURI(a:response.params.uri)
|
||||
let l:buffer = bufnr(l:filename)
|
||||
|
||||
if l:buffer <= 0
|
||||
return
|
||||
endif
|
||||
|
||||
let l:loclist = ale#lsp#response#ReadDiagnostics(a:response)
|
||||
|
||||
call ale#engine#HandleLoclist(l:linter_name, l:buffer, l:loclist)
|
||||
endfunction
|
||||
|
||||
function! s:HandleTSServerDiagnostics(response, error_type) 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:thislist = ale#lsp#response#ReadTSServerDiagnostics(a:response)
|
||||
|
||||
" tsserver sends syntax and semantic errors in separate messages, so we
|
||||
" have to collect the messages separately for each buffer and join them
|
||||
" back together again.
|
||||
if a:error_type is# 'syntax'
|
||||
let l:info.syntax_loclist = l:thislist
|
||||
else
|
||||
let l:info.semantic_loclist = l:thislist
|
||||
endif
|
||||
|
||||
let l:loclist = get(l:info, 'semantic_loclist', [])
|
||||
\ + get(l:info, 'syntax_loclist', [])
|
||||
|
||||
call ale#engine#HandleLoclist('tsserver', l:buffer, l:loclist)
|
||||
endfunction
|
||||
|
||||
function! s:HandleLSPErrorMessage(linter_name, response) abort
|
||||
if !g:ale_history_enabled || !g:ale_history_log_output
|
||||
return
|
||||
endif
|
||||
|
||||
if empty(a:linter_name)
|
||||
return
|
||||
endif
|
||||
|
||||
let l:message = ale#lsp#response#GetErrorMessage(a:response)
|
||||
|
||||
if empty(l:message)
|
||||
return
|
||||
endif
|
||||
|
||||
" This global variable is set here so we don't load the debugging.vim file
|
||||
" until someone uses :ALEInfo.
|
||||
let g:ale_lsp_error_messages = get(g:, 'ale_lsp_error_messages', {})
|
||||
|
||||
if !has_key(g:ale_lsp_error_messages, a:linter_name)
|
||||
let g:ale_lsp_error_messages[a:linter_name] = []
|
||||
endif
|
||||
|
||||
call add(g:ale_lsp_error_messages[a:linter_name], l:message)
|
||||
endfunction
|
||||
|
||||
function! ale#engine#HandleLSPResponse(conn_id, response) abort
|
||||
let l:method = get(a:response, 'method', '')
|
||||
let l:linter_name = get(s:lsp_linter_map, a:conn_id, '')
|
||||
|
||||
if get(a:response, 'jsonrpc', '') is# '2.0' && has_key(a:response, 'error')
|
||||
call s:HandleLSPErrorMessage(l:linter_name, a:response)
|
||||
elseif l:method is# 'textDocument/publishDiagnostics'
|
||||
call s:HandleLSPDiagnostics(a:conn_id, a:response)
|
||||
elseif get(a:response, 'type', '') is# 'event'
|
||||
\&& get(a:response, 'event', '') is# 'semanticDiag'
|
||||
call s:HandleTSServerDiagnostics(a:response, 'semantic')
|
||||
elseif get(a:response, 'type', '') is# 'event'
|
||||
\&& get(a:response, 'event', '') is# 'syntaxDiag'
|
||||
call s:HandleTSServerDiagnostics(a:response, 'syntax')
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#engine#SetResults(buffer, loclist) abort
|
||||
let l:linting_is_done = !ale#engine#IsCheckingBuffer(a:buffer)
|
||||
|
||||
@ -367,9 +270,6 @@ function! ale#engine#SetResults(buffer, loclist) abort
|
||||
|
||||
" Call user autocommands. This allows users to hook into ALE's lint cycle.
|
||||
silent doautocmd <nomodeline> User ALELintPost
|
||||
" remove in 2.0
|
||||
" Old DEPRECATED name; call it for backwards compatibility.
|
||||
silent doautocmd <nomodeline> User ALELint
|
||||
endif
|
||||
endfunction
|
||||
|
||||
@ -739,44 +639,6 @@ function! s:StopCurrentJobs(buffer, include_lint_file_jobs) abort
|
||||
let l:info.active_linter_list = l:new_active_linter_list
|
||||
endfunction
|
||||
|
||||
function! s:CheckWithLSP(buffer, linter) abort
|
||||
let l:info = g:ale_buffer_info[a:buffer]
|
||||
let l:lsp_details = ale#linter#StartLSP(
|
||||
\ a:buffer,
|
||||
\ a:linter,
|
||||
\ function('ale#engine#HandleLSPResponse'),
|
||||
\)
|
||||
|
||||
if empty(l:lsp_details)
|
||||
return 0
|
||||
endif
|
||||
|
||||
let l:id = l:lsp_details.connection_id
|
||||
let l:root = l:lsp_details.project_root
|
||||
|
||||
" Remember the linter this connection is for.
|
||||
let s:lsp_linter_map[l:id] = a:linter.name
|
||||
|
||||
let l:change_message = a:linter.lsp is# '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 this was a file save event, also notify the server of that.
|
||||
if a:linter.lsp isnot# 'tsserver'
|
||||
\&& getbufvar(a:buffer, 'ale_save_event_fired', 0)
|
||||
let l:save_message = ale#lsp#message#DidSave(a:buffer)
|
||||
let l:request_id = ale#lsp#Send(l:id, l:save_message, l:root)
|
||||
endif
|
||||
|
||||
if l:request_id != 0
|
||||
if index(l:info.active_linter_list, a:linter.name) < 0
|
||||
call add(l:info.active_linter_list, a:linter.name)
|
||||
endif
|
||||
endif
|
||||
|
||||
return l:request_id != 0
|
||||
endfunction
|
||||
|
||||
function! s:RemoveProblemsForDisabledLinters(buffer, linters) abort
|
||||
" Figure out which linters are still enabled, and remove
|
||||
@ -832,7 +694,7 @@ endfunction
|
||||
" Returns 1 if the linter was successfully run.
|
||||
function! s:RunLinter(buffer, linter) abort
|
||||
if !empty(a:linter.lsp)
|
||||
return s:CheckWithLSP(a:buffer, a:linter)
|
||||
return ale#lsp_linter#CheckWithLSP(a:buffer, a:linter)
|
||||
else
|
||||
let l:executable = ale#linter#GetExecutable(a:buffer, a:linter)
|
||||
|
||||
@ -914,7 +776,7 @@ endfunction
|
||||
" The time taken will be a very rough approximation, and more time may be
|
||||
" permitted than is specified.
|
||||
function! ale#engine#WaitForJobs(deadline) abort
|
||||
let l:start_time = ale#util#ClockMilliseconds()
|
||||
let l:start_time = ale#events#ClockMilliseconds()
|
||||
|
||||
if l:start_time == 0
|
||||
throw 'Failed to read milliseconds from the clock!'
|
||||
@ -945,7 +807,7 @@ function! ale#engine#WaitForJobs(deadline) abort
|
||||
|
||||
for l:job_id in l:job_list
|
||||
if ale#job#IsRunning(l:job_id)
|
||||
let l:now = ale#util#ClockMilliseconds()
|
||||
let l:now = ale#events#ClockMilliseconds()
|
||||
|
||||
if l:now - l:start_time > a:deadline
|
||||
" Stop waiting after a timeout, so we don't wait forever.
|
||||
@ -982,7 +844,7 @@ function! ale#engine#WaitForJobs(deadline) abort
|
||||
|
||||
if l:has_new_jobs
|
||||
" We have to wait more. Offset the timeout by the time taken so far.
|
||||
let l:now = ale#util#ClockMilliseconds()
|
||||
let l:now = ale#events#ClockMilliseconds()
|
||||
let l:new_deadline = a:deadline - (l:now - l:start_time)
|
||||
|
||||
if l:new_deadline <= 0
|
||||
|
46
sources_non_forked/ale/autoload/ale/engine/ignore.vim
Normal file
46
sources_non_forked/ale/autoload/ale/engine/ignore.vim
Normal file
@ -0,0 +1,46 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: Code for ignoring linters. Only loaded and if configured.
|
||||
|
||||
" Given a filetype and a configuration for ignoring linters, return a List of
|
||||
" Strings for linter names to ignore.
|
||||
function! ale#engine#ignore#GetList(filetype, config) abort
|
||||
if type(a:config) is type([])
|
||||
return a:config
|
||||
endif
|
||||
|
||||
if type(a:config) is type({})
|
||||
let l:names_to_remove = []
|
||||
|
||||
for l:part in split(a:filetype , '\.')
|
||||
call extend(l:names_to_remove, get(a:config, l:part, []))
|
||||
endfor
|
||||
|
||||
return l:names_to_remove
|
||||
endif
|
||||
|
||||
return []
|
||||
endfunction
|
||||
|
||||
" Given a List of linter descriptions, exclude the linters to be ignored.
|
||||
function! ale#engine#ignore#Exclude(filetype, all_linters, config) abort
|
||||
let l:names_to_remove = ale#engine#ignore#GetList(a:filetype, a:config)
|
||||
let l:filtered_linters = []
|
||||
|
||||
for l:linter in a:all_linters
|
||||
let l:name_list = [l:linter.name] + l:linter.aliases
|
||||
let l:should_include = 1
|
||||
|
||||
for l:name in l:name_list
|
||||
if index(l:names_to_remove, l:name) >= 0
|
||||
let l:should_include = 0
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
|
||||
if l:should_include
|
||||
call add(l:filtered_linters, l:linter)
|
||||
endif
|
||||
endfor
|
||||
|
||||
return l:filtered_linters
|
||||
endfunction
|
@ -1,14 +1,25 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: ALE functions for autocmd events.
|
||||
|
||||
" Get the number of milliseconds since some vague, but consistent, point in
|
||||
" the past.
|
||||
"
|
||||
" This function can be used for timing execution, etc.
|
||||
"
|
||||
" The time will be returned as a Number.
|
||||
function! ale#events#ClockMilliseconds() abort
|
||||
return float2nr(reltimefloat(reltime()) * 1000)
|
||||
endfunction
|
||||
|
||||
function! ale#events#QuitEvent(buffer) abort
|
||||
" Remember when ALE is quitting for BufWrite, etc.
|
||||
call setbufvar(a:buffer, 'ale_quitting', ale#util#ClockMilliseconds())
|
||||
call setbufvar(a:buffer, 'ale_quitting', ale#events#ClockMilliseconds())
|
||||
endfunction
|
||||
|
||||
function! ale#events#QuitRecently(buffer) abort
|
||||
let l:time = getbufvar(a:buffer, 'ale_quitting', 0)
|
||||
|
||||
return l:time && ale#util#ClockMilliseconds() - l:time < 1000
|
||||
return l:time && ale#events#ClockMilliseconds() - l:time < 1000
|
||||
endfunction
|
||||
|
||||
function! ale#events#SaveEvent(buffer) abort
|
||||
@ -67,3 +78,56 @@ function! ale#events#FileChangedEvent(buffer) abort
|
||||
call s:LintOnEnter(a:buffer)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#events#Init() abort
|
||||
" This value used to be a Boolean as a Number, and is now a String.
|
||||
let l:text_changed = '' . g:ale_lint_on_text_changed
|
||||
|
||||
augroup ALEEvents
|
||||
autocmd!
|
||||
|
||||
" These events always need to be set up.
|
||||
autocmd BufEnter,BufRead * call ale#pattern_options#SetOptions(str2nr(expand('<abuf>')))
|
||||
autocmd BufWritePost * call ale#events#SaveEvent(str2nr(expand('<abuf>')))
|
||||
|
||||
if g:ale_enabled
|
||||
if l:text_changed is? 'always' || l:text_changed is# '1'
|
||||
autocmd TextChanged,TextChangedI * call ale#Queue(g:ale_lint_delay)
|
||||
elseif l:text_changed is? 'normal'
|
||||
autocmd TextChanged * call ale#Queue(g:ale_lint_delay)
|
||||
elseif l:text_changed is? 'insert'
|
||||
autocmd TextChangedI * call ale#Queue(g:ale_lint_delay)
|
||||
endif
|
||||
|
||||
" Handle everything that needs to happen when buffers are entered.
|
||||
autocmd BufEnter * call ale#events#EnterEvent(str2nr(expand('<abuf>')))
|
||||
|
||||
if g:ale_lint_on_enter
|
||||
autocmd BufWinEnter,BufRead * call ale#Queue(0, 'lint_file', str2nr(expand('<abuf>')))
|
||||
" Track when the file is changed outside of Vim.
|
||||
autocmd FileChangedShellPost * call ale#events#FileChangedEvent(str2nr(expand('<abuf>')))
|
||||
endif
|
||||
|
||||
if g:ale_lint_on_filetype_changed
|
||||
" Only start linting if the FileType actually changes after
|
||||
" opening a buffer. The FileType will fire when buffers are opened.
|
||||
autocmd FileType * call ale#events#FileTypeEvent(
|
||||
\ str2nr(expand('<abuf>')),
|
||||
\ expand('<amatch>')
|
||||
\)
|
||||
endif
|
||||
|
||||
if g:ale_lint_on_insert_leave
|
||||
autocmd InsertLeave * call ale#Queue(0)
|
||||
endif
|
||||
|
||||
if g:ale_echo_cursor
|
||||
autocmd CursorMoved,CursorHold * if exists('*ale#engine#Cleanup') | call ale#cursor#EchoCursorWarningWithDelay() | endif
|
||||
" Look for a warning to echo as soon as we leave Insert mode.
|
||||
" The script's position variable used when moving the cursor will
|
||||
" not be changed here.
|
||||
autocmd InsertLeave * if exists('*ale#engine#Cleanup') | call ale#cursor#EchoCursorWarning() | endif
|
||||
endif
|
||||
endif
|
||||
augroup END
|
||||
endfunction
|
||||
|
@ -356,9 +356,21 @@ function! s:RunFixer(options) abort
|
||||
call ale#fix#ApplyFixes(l:buffer, l:input)
|
||||
endfunction
|
||||
|
||||
function! s:GetCallbacks(buffer, linters) abort
|
||||
if len(a:linters)
|
||||
let l:callback_list = a:linters
|
||||
function! s:AddSubCallbacks(full_list, callbacks) abort
|
||||
if type(a:callbacks) == type('')
|
||||
call add(a:full_list, a:callbacks)
|
||||
elseif type(a:callbacks) == type([])
|
||||
call extend(a:full_list, a:callbacks)
|
||||
else
|
||||
return 0
|
||||
endif
|
||||
|
||||
return 1
|
||||
endfunction
|
||||
|
||||
function! s:GetCallbacks(buffer, fixers) abort
|
||||
if len(a:fixers)
|
||||
let l:callback_list = a:fixers
|
||||
elseif type(get(b:, 'ale_fixers')) is type([])
|
||||
" Lists can be used for buffer-local variables only
|
||||
let l:callback_list = b:ale_fixers
|
||||
@ -367,16 +379,18 @@ function! s:GetCallbacks(buffer, linters) abort
|
||||
" callbacks to run.
|
||||
let l:fixers = ale#Var(a:buffer, 'fixers')
|
||||
let l:callback_list = []
|
||||
let l:matched = 0
|
||||
|
||||
for l:sub_type in split(&filetype, '\.')
|
||||
let l:sub_type_callacks = get(l:fixers, l:sub_type, [])
|
||||
|
||||
if type(l:sub_type_callacks) == type('')
|
||||
call add(l:callback_list, l:sub_type_callacks)
|
||||
else
|
||||
call extend(l:callback_list, l:sub_type_callacks)
|
||||
if s:AddSubCallbacks(l:callback_list, get(l:fixers, l:sub_type))
|
||||
let l:matched = 1
|
||||
endif
|
||||
endfor
|
||||
|
||||
" If we couldn't find fixers for a filetype, default to '*' fixers.
|
||||
if !l:matched
|
||||
call s:AddSubCallbacks(l:callback_list, get(l:fixers, '*'))
|
||||
endif
|
||||
endif
|
||||
|
||||
if empty(l:callback_list)
|
||||
|
@ -22,6 +22,11 @@ let s:default_registry = {
|
||||
\ 'suggested_filetypes': ['python'],
|
||||
\ 'description': 'Fix PEP8 issues with black.',
|
||||
\ },
|
||||
\ 'tidy': {
|
||||
\ 'function': 'ale#fixers#tidy#Fix',
|
||||
\ 'suggested_filetypes': ['html'],
|
||||
\ 'description': 'Fix HTML files with tidy.',
|
||||
\ },
|
||||
\ 'prettier_standard': {
|
||||
\ 'function': 'ale#fixers#prettier_standard#Fix',
|
||||
\ 'suggested_filetypes': ['javascript'],
|
||||
@ -51,7 +56,7 @@ let s:default_registry = {
|
||||
\ },
|
||||
\ 'prettier': {
|
||||
\ 'function': 'ale#fixers#prettier#Fix',
|
||||
\ 'suggested_filetypes': ['javascript', 'typescript', 'json', 'css', 'scss', 'less', 'markdown', 'graphql', 'vue'],
|
||||
\ 'suggested_filetypes': ['javascript', 'typescript', 'css', 'less', 'scss', 'json', 'json5', 'graphql', 'markdown', 'vue'],
|
||||
\ 'description': 'Apply prettier to a file.',
|
||||
\ },
|
||||
\ 'prettier_eslint': {
|
||||
@ -205,6 +210,11 @@ let s:default_registry = {
|
||||
\ 'suggested_filetypes': ['qml'],
|
||||
\ 'description': 'Fix QML files with qmlfmt.',
|
||||
\ },
|
||||
\ 'dartfmt': {
|
||||
\ 'function': 'ale#fixers#dartfmt#Fix',
|
||||
\ 'suggested_filetypes': ['dart'],
|
||||
\ 'description': 'Fix Dart files with dartfmt.',
|
||||
\ },
|
||||
\}
|
||||
|
||||
" Reset the function registry to the default entries.
|
||||
@ -345,8 +355,7 @@ function! ale#fix#registry#CompleteFixers(ArgLead, CmdLine, CursorPos) abort
|
||||
return filter(ale#fix#registry#GetApplicableFixers(&filetype), 'v:val =~? a:ArgLead')
|
||||
endfunction
|
||||
|
||||
" Suggest functions to use from the registry.
|
||||
function! ale#fix#registry#Suggest(filetype) abort
|
||||
function! ale#fix#registry#SuggestedFixers(filetype) abort
|
||||
let l:type_list = split(a:filetype, '\.')
|
||||
let l:filetype_fixer_list = []
|
||||
|
||||
@ -372,6 +381,15 @@ function! ale#fix#registry#Suggest(filetype) abort
|
||||
endif
|
||||
endfor
|
||||
|
||||
return [l:filetype_fixer_list, l:generic_fixer_list]
|
||||
endfunction
|
||||
|
||||
" Suggest functions to use from the registry.
|
||||
function! ale#fix#registry#Suggest(filetype) abort
|
||||
let l:suggested = ale#fix#registry#SuggestedFixers(a:filetype)
|
||||
let l:filetype_fixer_list = l:suggested[0]
|
||||
let l:generic_fixer_list = l:suggested[1]
|
||||
|
||||
let l:filetype_fixer_header = !empty(l:filetype_fixer_list)
|
||||
\ ? ['Try the following fixers appropriate for the filetype:', '']
|
||||
\ : []
|
||||
|
18
sources_non_forked/ale/autoload/ale/fixers/dartfmt.vim
Normal file
18
sources_non_forked/ale/autoload/ale/fixers/dartfmt.vim
Normal file
@ -0,0 +1,18 @@
|
||||
" Author: reisub0 <reisub0@gmail.com>
|
||||
" Description: Integration of dartfmt with ALE.
|
||||
|
||||
call ale#Set('dart_dartfmt_executable', 'dartfmt')
|
||||
call ale#Set('dart_dartfmt_options', '')
|
||||
|
||||
function! ale#fixers#dartfmt#Fix(buffer) abort
|
||||
let l:executable = ale#Var(a:buffer, 'dart_dartfmt_executable')
|
||||
let l:options = ale#Var(a:buffer, 'dart_dartfmt_options')
|
||||
|
||||
return {
|
||||
\ 'command': ale#Escape(l:executable)
|
||||
\ . ' -w'
|
||||
\ . (empty(l:options) ? '' : ' ' . l:options)
|
||||
\ . ' %t',
|
||||
\ 'read_temporary_file': 1,
|
||||
\}
|
||||
endfunction
|
@ -30,8 +30,26 @@ endfunction
|
||||
function! ale#fixers#prettier#ApplyFixForVersion(buffer, version_output) abort
|
||||
let l:executable = ale#fixers#prettier#GetExecutable(a:buffer)
|
||||
let l:options = ale#Var(a:buffer, 'javascript_prettier_options')
|
||||
|
||||
let l:version = ale#semver#GetVersion(l:executable, a:version_output)
|
||||
let l:parser = ''
|
||||
|
||||
" Append the --parser flag depending on the current filetype (unless it's
|
||||
" already set in g:javascript_prettier_options).
|
||||
if empty(expand('#' . a:buffer . ':e')) && match(l:options, '--parser') == -1
|
||||
let l:prettier_parsers = ['typescript', 'css', 'less', 'scss', 'json', 'json5', 'graphql', 'markdown', 'vue']
|
||||
let l:parser = 'babylon'
|
||||
|
||||
for l:filetype in split(getbufvar(a:buffer, '&filetype'), '\.')
|
||||
if index(l:prettier_parsers, l:filetype) > -1
|
||||
let l:parser = l:filetype
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
|
||||
if !empty(l:parser)
|
||||
let l:options = (!empty(l:options) ? l:options . ' ' : '') . '--parser ' . l:parser
|
||||
endif
|
||||
|
||||
" 1.4.0 is the first version with --stdin-filepath
|
||||
if ale#semver#GTE(l:version, [1, 4, 0])
|
||||
|
26
sources_non_forked/ale/autoload/ale/fixers/tidy.vim
Normal file
26
sources_non_forked/ale/autoload/ale/fixers/tidy.vim
Normal file
@ -0,0 +1,26 @@
|
||||
" Author: meain <abinsimon10@gmail.com>
|
||||
" Description: Fixing HTML files with tidy.
|
||||
|
||||
call ale#Set('html_tidy_executable', 'tidy')
|
||||
call ale#Set('html_tidy_use_global', get(g:, 'ale_use_global_executables', 0))
|
||||
|
||||
function! ale#fixers#tidy#Fix(buffer) abort
|
||||
let l:executable = ale#node#FindExecutable(
|
||||
\ a:buffer,
|
||||
\ 'html_tidy',
|
||||
\ ['tidy'],
|
||||
\)
|
||||
|
||||
if !executable(l:executable)
|
||||
return 0
|
||||
endif
|
||||
|
||||
let l:config = ale#path#FindNearestFile(a:buffer, '.tidyrc')
|
||||
let l:config_options = !empty(l:config)
|
||||
\ ? ' -q --tidy-mark no --show-errors 0 --show-warnings 0 -config ' . ale#Escape(l:config)
|
||||
\ : ' -q --tidy-mark no --show-errors 0 --show-warnings 0'
|
||||
|
||||
return {
|
||||
\ 'command': ale#Escape(l:executable) . l:config_options,
|
||||
\}
|
||||
endfunction
|
@ -97,14 +97,14 @@ function! s:ShowDetails(linter, buffer, line, column, opt) abort
|
||||
\ ? function('ale#hover#HandleTSServerResponse')
|
||||
\ : function('ale#hover#HandleLSPResponse')
|
||||
|
||||
let l:lsp_details = ale#linter#StartLSP(a:buffer, a:linter, l:Callback)
|
||||
let l:lsp_details = ale#lsp_linter#StartLSP(a:buffer, a:linter, l:Callback)
|
||||
|
||||
if empty(l:lsp_details)
|
||||
return 0
|
||||
endif
|
||||
|
||||
let l:id = l:lsp_details.connection_id
|
||||
let l:root = l:lsp_details.project_root
|
||||
let l:language_id = l:lsp_details.language_id
|
||||
|
||||
if a:linter.lsp is# 'tsserver'
|
||||
let l:column = a:column
|
||||
@ -117,14 +117,14 @@ function! s:ShowDetails(linter, buffer, line, column, opt) abort
|
||||
else
|
||||
" Send a message saying the buffer has changed first, or the
|
||||
" hover position probably won't make sense.
|
||||
call ale#lsp#Send(l:id, ale#lsp#message#DidChange(a:buffer), l:root)
|
||||
call ale#lsp#NotifyForChanges(l:lsp_details)
|
||||
|
||||
let l:column = min([a:column, len(getbufline(a:buffer, a:line)[0])])
|
||||
|
||||
let l:message = ale#lsp#message#Hover(a:buffer, a:line, l:column)
|
||||
endif
|
||||
|
||||
let l:request_id = ale#lsp#Send(l:id, l:message, l:root)
|
||||
let l:request_id = ale#lsp#Send(l:id, l:message, l:lsp_details.project_root)
|
||||
|
||||
let s:hover_map[l:request_id] = {
|
||||
\ 'buffer': a:buffer,
|
||||
|
@ -26,34 +26,11 @@ function! s:KillHandler(timer) abort
|
||||
call job_stop(l:job, 'kill')
|
||||
endfunction
|
||||
|
||||
" Note that jobs and IDs are the same thing on NeoVim.
|
||||
function! ale#job#JoinNeovimOutput(job, last_line, data, mode, callback) abort
|
||||
if a:mode is# 'raw'
|
||||
call a:callback(a:job, join(a:data, "\n"))
|
||||
return ''
|
||||
endif
|
||||
|
||||
let l:lines = a:data[:-2]
|
||||
|
||||
if len(a:data) > 1
|
||||
let l:lines[0] = a:last_line . l:lines[0]
|
||||
let l:new_last_line = a:data[-1]
|
||||
else
|
||||
let l:new_last_line = a:last_line . get(a:data, 0, '')
|
||||
endif
|
||||
|
||||
for l:line in l:lines
|
||||
call a:callback(a:job, l:line)
|
||||
endfor
|
||||
|
||||
return l:new_last_line
|
||||
endfunction
|
||||
|
||||
function! s:NeoVimCallback(job, data, event) abort
|
||||
let l:info = s:job_map[a:job]
|
||||
|
||||
if a:event is# 'stdout'
|
||||
let l:info.out_cb_line = ale#job#JoinNeovimOutput(
|
||||
let l:info.out_cb_line = ale#util#JoinNeovimOutput(
|
||||
\ a:job,
|
||||
\ l:info.out_cb_line,
|
||||
\ a:data,
|
||||
@ -61,7 +38,7 @@ function! s:NeoVimCallback(job, data, event) abort
|
||||
\ ale#util#GetFunction(l:info.out_cb),
|
||||
\)
|
||||
elseif a:event is# 'stderr'
|
||||
let l:info.err_cb_line = ale#job#JoinNeovimOutput(
|
||||
let l:info.err_cb_line = ale#util#JoinNeovimOutput(
|
||||
\ a:job,
|
||||
\ l:info.err_cb_line,
|
||||
\ a:data,
|
||||
|
@ -15,6 +15,7 @@ let s:default_ale_linter_aliases = {
|
||||
\ 'csh': 'sh',
|
||||
\ 'plaintex': 'tex',
|
||||
\ 'systemverilog': 'verilog',
|
||||
\ 'verilog_systemverilog': ['verilog_systemverilog', 'verilog'],
|
||||
\ 'vimwiki': 'markdown',
|
||||
\ 'zsh': 'sh',
|
||||
\}
|
||||
@ -451,81 +452,3 @@ function! ale#linter#GetAddress(buffer, linter) abort
|
||||
\ ? ale#util#GetFunction(a:linter.address_callback)(a:buffer)
|
||||
\ : a:linter.address
|
||||
endfunction
|
||||
|
||||
" Given a buffer, an LSP linter, and a callback to register for handling
|
||||
" messages, start up an LSP linter and get ready to receive errors or
|
||||
" completions.
|
||||
function! ale#linter#StartLSP(buffer, linter, callback) abort
|
||||
let l:command = ''
|
||||
let l:address = ''
|
||||
let l:root = ale#util#GetFunction(a:linter.project_root_callback)(a:buffer)
|
||||
|
||||
if empty(l:root) && a:linter.lsp isnot# 'tsserver'
|
||||
" If there's no project root, then we can't check files with LSP,
|
||||
" unless we are using tsserver, which doesn't use project roots.
|
||||
return {}
|
||||
endif
|
||||
|
||||
let l:initialization_options = {}
|
||||
if has_key(a:linter, 'initialization_options_callback')
|
||||
let l:initialization_options = ale#util#GetFunction(a:linter.initialization_options_callback)(a:buffer)
|
||||
elseif has_key(a:linter, 'initialization_options')
|
||||
let l:initialization_options = a:linter.initialization_options
|
||||
endif
|
||||
|
||||
if a:linter.lsp is# 'socket'
|
||||
let l:address = ale#linter#GetAddress(a:buffer, a:linter)
|
||||
let l:conn_id = ale#lsp#ConnectToAddress(
|
||||
\ l:address,
|
||||
\ l:root,
|
||||
\ a:callback,
|
||||
\ l:initialization_options,
|
||||
\)
|
||||
else
|
||||
let l:executable = ale#linter#GetExecutable(a:buffer, a:linter)
|
||||
|
||||
if !executable(l:executable)
|
||||
return {}
|
||||
endif
|
||||
|
||||
let l:command = ale#job#PrepareCommand(
|
||||
\ a:buffer,
|
||||
\ ale#linter#GetCommand(a:buffer, a:linter),
|
||||
\)
|
||||
let l:conn_id = ale#lsp#StartProgram(
|
||||
\ l:executable,
|
||||
\ l:command,
|
||||
\ l:root,
|
||||
\ a:callback,
|
||||
\ l:initialization_options,
|
||||
\)
|
||||
endif
|
||||
|
||||
let l:language_id = ale#util#GetFunction(a:linter.language_callback)(a:buffer)
|
||||
|
||||
if !l:conn_id
|
||||
if g:ale_history_enabled && !empty(l:command)
|
||||
call ale#history#Add(a:buffer, 'failed', l:conn_id, l:command)
|
||||
endif
|
||||
|
||||
return {}
|
||||
endif
|
||||
|
||||
if ale#lsp#OpenDocumentIfNeeded(l:conn_id, a:buffer, l:root, l:language_id)
|
||||
if g:ale_history_enabled && !empty(l:command)
|
||||
call ale#history#Add(a:buffer, 'started', l:conn_id, l:command)
|
||||
endif
|
||||
endif
|
||||
|
||||
" The change message needs to be sent for tsserver before doing anything.
|
||||
if a:linter.lsp is# 'tsserver'
|
||||
call ale#lsp#Send(l:conn_id, ale#lsp#tsserver_message#Change(a:buffer))
|
||||
endif
|
||||
|
||||
return {
|
||||
\ 'connection_id': l:conn_id,
|
||||
\ 'command': l:command,
|
||||
\ 'project_root': l:root,
|
||||
\ 'language_id': l:language_id,
|
||||
\}
|
||||
endfunction
|
||||
|
@ -3,20 +3,23 @@
|
||||
|
||||
" A List of connections, used for tracking servers which have been connected
|
||||
" to, and programs which are run.
|
||||
let s:connections = []
|
||||
let s:connections = get(s:, 'connections', [])
|
||||
let g:ale_lsp_next_message_id = 1
|
||||
|
||||
function! s:NewConnection(initialization_options) abort
|
||||
" Exposed only so tests can get at it.
|
||||
" Do not call this function basically anywhere.
|
||||
function! ale#lsp#NewConnection(initialization_options) abort
|
||||
" id: The job ID as a Number, or the server address as a string.
|
||||
" data: The message data received so far.
|
||||
" executable: An executable only set for program connections.
|
||||
" open_documents: A list of buffers we told the server we opened.
|
||||
" open_documents: A Dictionary mapping buffers to b:changedtick, keeping
|
||||
" track of when documents were opened, and when we last changed them.
|
||||
" callback_list: A list of callbacks for handling LSP responses.
|
||||
let l:conn = {
|
||||
\ 'id': '',
|
||||
\ 'data': '',
|
||||
\ 'projects': {},
|
||||
\ 'open_documents': [],
|
||||
\ 'open_documents': {},
|
||||
\ 'callback_list': [],
|
||||
\ 'initialization_options': a:initialization_options,
|
||||
\}
|
||||
@ -26,9 +29,14 @@ function! s:NewConnection(initialization_options) abort
|
||||
return l:conn
|
||||
endfunction
|
||||
|
||||
" Remove an LSP connection with a given ID. This is only for tests.
|
||||
function! ale#lsp#RemoveConnectionWithID(id) abort
|
||||
call filter(s:connections, 'v:val.id isnot a:id')
|
||||
endfunction
|
||||
|
||||
function! s:FindConnection(key, value) abort
|
||||
for l:conn in s:connections
|
||||
if has_key(l:conn, a:key) && get(l:conn, a:key) == a:value
|
||||
if has_key(l:conn, a:key) && get(l:conn, a:key) is# a:value
|
||||
return l:conn
|
||||
endif
|
||||
endfor
|
||||
@ -233,9 +241,8 @@ function! ale#lsp#HandleMessage(conn, message) abort
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
function! s:HandleChannelMessage(channel, message) abort
|
||||
let l:info = ch_info(a:channel)
|
||||
let l:address = l:info.hostname . l:info.address
|
||||
function! s:HandleChannelMessage(channel_id, message) abort
|
||||
let l:address = ale#socket#GetAddress(a:channel_id)
|
||||
let l:conn = s:FindConnection('id', l:address)
|
||||
|
||||
call ale#lsp#HandleMessage(l:conn, a:message)
|
||||
@ -280,7 +287,7 @@ function! ale#lsp#StartProgram(executable, command, project_root, callback, init
|
||||
let l:conn = s:FindConnection('executable', a:executable)
|
||||
|
||||
" Get the current connection or a new one.
|
||||
let l:conn = !empty(l:conn) ? l:conn : s:NewConnection(a:initialization_options)
|
||||
let l:conn = !empty(l:conn) ? l:conn : ale#lsp#NewConnection(a:initialization_options)
|
||||
let l:conn.executable = a:executable
|
||||
|
||||
if !has_key(l:conn, 'id') || !ale#job#IsRunning(l:conn.id)
|
||||
@ -309,18 +316,16 @@ endfunction
|
||||
function! ale#lsp#ConnectToAddress(address, project_root, callback, initialization_options) abort
|
||||
let l:conn = s:FindConnection('id', a:address)
|
||||
" Get the current connection or a new one.
|
||||
let l:conn = !empty(l:conn) ? l:conn : s:NewConnection(a:initialization_options)
|
||||
let l:conn = !empty(l:conn) ? l:conn : ale#lsp#NewConnection(a:initialization_options)
|
||||
|
||||
if !has_key(l:conn, 'channel') || ch_status(l:conn.channel) isnot# 'open'
|
||||
let l:conn.channnel = ch_open(a:address, {
|
||||
\ 'mode': 'raw',
|
||||
\ 'waittime': 0,
|
||||
if !has_key(l:conn, 'channel_id') || !ale#socket#IsOpen(l:conn.channel_id)
|
||||
let l:conn.channel_id = ale#socket#Open(a:address, {
|
||||
\ 'callback': function('s:HandleChannelMessage'),
|
||||
\})
|
||||
endif
|
||||
|
||||
if ch_status(l:conn.channnel) is# 'fail'
|
||||
return 0
|
||||
if l:conn.channel_id < 0
|
||||
return ''
|
||||
endif
|
||||
|
||||
let l:conn.id = a:address
|
||||
@ -328,15 +333,15 @@ function! ale#lsp#ConnectToAddress(address, project_root, callback, initializati
|
||||
call uniq(sort(add(l:conn.callback_list, a:callback)))
|
||||
call ale#lsp#RegisterProject(l:conn, a:project_root)
|
||||
|
||||
return 1
|
||||
return a:address
|
||||
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)
|
||||
if has_key(l:conn, 'channel_id')
|
||||
call ale#socket#Close(l:conn.channel_id)
|
||||
else
|
||||
call ale#job#Stop(l:conn.id)
|
||||
endif
|
||||
@ -348,9 +353,9 @@ endfunction
|
||||
function! s:SendMessageData(conn, data) abort
|
||||
if has_key(a:conn, 'executable')
|
||||
call ale#job#SendRaw(a:conn.id, a:data)
|
||||
elseif has_key(a:conn, 'channel') && ch_status(a:conn.channnel) is# 'open'
|
||||
elseif has_key(a:conn, 'channel_id') && ale#socket#IsOpen(a:conn.channel_id)
|
||||
" Send the message to the server
|
||||
call ch_sendraw(a:conn.channel, a:data)
|
||||
call ale#socket#Send(a:conn.channel_id, a:data)
|
||||
else
|
||||
return 0
|
||||
endif
|
||||
@ -406,21 +411,72 @@ function! ale#lsp#Send(conn_id, message, ...) abort
|
||||
return l:id == 0 ? -1 : l:id
|
||||
endfunction
|
||||
|
||||
function! ale#lsp#OpenDocumentIfNeeded(conn_id, buffer, project_root, language_id) abort
|
||||
let l:conn = s:FindConnection('id', a:conn_id)
|
||||
" The Document details Dictionary should contain the following keys.
|
||||
"
|
||||
" buffer - The buffer number for the document.
|
||||
" connection_id - The connection ID for the LSP server.
|
||||
" command - The command to run to start the LSP connection.
|
||||
" project_root - The project root for the LSP project.
|
||||
" language_id - The language ID for the project, like 'python', 'rust', etc.
|
||||
|
||||
" Create a new Dictionary containing more connection details, with the
|
||||
" following information added:
|
||||
"
|
||||
" conn - An existing LSP connection for the document.
|
||||
" document_open - 1 if the document is currently open, 0 otherwise.
|
||||
function! s:ExtendDocumentDetails(details) abort
|
||||
let l:extended = copy(a:details)
|
||||
let l:conn = s:FindConnection('id', a:details.connection_id)
|
||||
|
||||
let l:extended.conn = l:conn
|
||||
let l:extended.document_open = !empty(l:conn)
|
||||
\ && has_key(l:conn.open_documents, a:details.buffer)
|
||||
|
||||
return l:extended
|
||||
endfunction
|
||||
|
||||
" Notify LSP servers or tsserver if a document is opened, if needed.
|
||||
" If a document is opened, 1 will be returned, otherwise 0 will be returned.
|
||||
function! ale#lsp#OpenDocument(basic_details) abort
|
||||
let l:d = s:ExtendDocumentDetails(a:basic_details)
|
||||
let l:opened = 0
|
||||
|
||||
if !empty(l:conn) && index(l:conn.open_documents, a:buffer) < 0
|
||||
if empty(a:language_id)
|
||||
let l:message = ale#lsp#tsserver_message#Open(a:buffer)
|
||||
if !empty(l:d.conn) && !l:d.document_open
|
||||
if empty(l:d.language_id)
|
||||
let l:message = ale#lsp#tsserver_message#Open(l:d.buffer)
|
||||
else
|
||||
let l:message = ale#lsp#message#DidOpen(a:buffer, a:language_id)
|
||||
let l:message = ale#lsp#message#DidOpen(l:d.buffer, l:d.language_id)
|
||||
endif
|
||||
|
||||
call ale#lsp#Send(a:conn_id, l:message, a:project_root)
|
||||
call add(l:conn.open_documents, a:buffer)
|
||||
call ale#lsp#Send(l:d.connection_id, l:message, l:d.project_root)
|
||||
let l:d.conn.open_documents[l:d.buffer] = getbufvar(l:d.buffer, 'changedtick')
|
||||
let l:opened = 1
|
||||
endif
|
||||
|
||||
return l:opened
|
||||
endfunction
|
||||
|
||||
" Notify LSP servers or tsserver that a document has changed, if needed.
|
||||
" If a notification is sent, 1 will be returned, otherwise 0 will be returned.
|
||||
function! ale#lsp#NotifyForChanges(basic_details) abort
|
||||
let l:d = s:ExtendDocumentDetails(a:basic_details)
|
||||
let l:notified = 0
|
||||
|
||||
if l:d.document_open
|
||||
let l:new_tick = getbufvar(l:d.buffer, 'changedtick')
|
||||
|
||||
if l:d.conn.open_documents[l:d.buffer] < l:new_tick
|
||||
if empty(l:d.language_id)
|
||||
let l:message = ale#lsp#tsserver_message#Change(l:d.buffer)
|
||||
else
|
||||
let l:message = ale#lsp#message#DidChange(l:d.buffer)
|
||||
endif
|
||||
|
||||
call ale#lsp#Send(l:d.connection_id, l:message, l:d.project_root)
|
||||
let l:d.conn.open_documents[l:d.buffer] = l:new_tick
|
||||
let l:notified = 1
|
||||
endif
|
||||
endif
|
||||
|
||||
return l:notified
|
||||
endfunction
|
||||
|
@ -7,9 +7,9 @@ function! ale#lsp#reset#StopAllLSPs() abort
|
||||
call ale#definition#ClearLSPData()
|
||||
endif
|
||||
|
||||
if exists('*ale#engine#ClearLSPData')
|
||||
if exists('*ale#lsp_linter#ClearLSPData')
|
||||
" Clear the mapping for connections, etc.
|
||||
call ale#engine#ClearLSPData()
|
||||
call ale#lsp_linter#ClearLSPData()
|
||||
|
||||
" Remove the problems for all of the LSP linters in every buffer.
|
||||
for l:buffer_string in keys(g:ale_buffer_info)
|
||||
|
252
sources_non_forked/ale/autoload/ale/lsp_linter.vim
Normal file
252
sources_non_forked/ale/autoload/ale/lsp_linter.vim
Normal file
@ -0,0 +1,252 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: Integration between linters and LSP/tsserver.
|
||||
|
||||
" This code isn't loaded if a user never users LSP features or linters.
|
||||
|
||||
" Associates LSP connection IDs with linter names.
|
||||
if !has_key(s:, 'lsp_linter_map')
|
||||
let s:lsp_linter_map = {}
|
||||
endif
|
||||
|
||||
" Check if diagnostics for a particular linter should be ignored.
|
||||
function! s:ShouldIgnore(buffer, linter_name) abort
|
||||
let l:config = ale#Var(a:buffer, 'linters_ignore')
|
||||
|
||||
" Don't load code for ignoring diagnostics if there's nothing to ignore.
|
||||
if empty(l:config)
|
||||
return 0
|
||||
endif
|
||||
|
||||
let l:filetype = getbufvar(a:buffer, '&filetype')
|
||||
let l:ignore_list = ale#engine#ignore#GetList(l:filetype, l:config)
|
||||
|
||||
return index(l:ignore_list, a:linter_name) >= 0
|
||||
endfunction
|
||||
|
||||
function! s:HandleLSPDiagnostics(conn_id, response) abort
|
||||
let l:linter_name = s:lsp_linter_map[a:conn_id]
|
||||
let l:filename = ale#path#FromURI(a:response.params.uri)
|
||||
let l:buffer = bufnr(l:filename)
|
||||
|
||||
if s:ShouldIgnore(l:buffer, l:linter_name)
|
||||
return
|
||||
endif
|
||||
|
||||
if l:buffer <= 0
|
||||
return
|
||||
endif
|
||||
|
||||
let l:loclist = ale#lsp#response#ReadDiagnostics(a:response)
|
||||
|
||||
call ale#engine#HandleLoclist(l:linter_name, l:buffer, l:loclist)
|
||||
endfunction
|
||||
|
||||
function! s:HandleTSServerDiagnostics(response, error_type) abort
|
||||
let l:linter_name = 'tsserver'
|
||||
let l:buffer = bufnr(a:response.body.file)
|
||||
let l:info = get(g:ale_buffer_info, l:buffer, {})
|
||||
|
||||
if empty(l:info)
|
||||
return
|
||||
endif
|
||||
|
||||
if s:ShouldIgnore(l:buffer, l:linter_name)
|
||||
return
|
||||
endif
|
||||
|
||||
let l:thislist = ale#lsp#response#ReadTSServerDiagnostics(a:response)
|
||||
|
||||
" tsserver sends syntax and semantic errors in separate messages, so we
|
||||
" have to collect the messages separately for each buffer and join them
|
||||
" back together again.
|
||||
if a:error_type is# 'syntax'
|
||||
let l:info.syntax_loclist = l:thislist
|
||||
else
|
||||
let l:info.semantic_loclist = l:thislist
|
||||
endif
|
||||
|
||||
let l:loclist = get(l:info, 'semantic_loclist', [])
|
||||
\ + get(l:info, 'syntax_loclist', [])
|
||||
|
||||
call ale#engine#HandleLoclist(l:linter_name, l:buffer, l:loclist)
|
||||
endfunction
|
||||
|
||||
function! s:HandleLSPErrorMessage(linter_name, response) abort
|
||||
if !g:ale_history_enabled || !g:ale_history_log_output
|
||||
return
|
||||
endif
|
||||
|
||||
if empty(a:linter_name)
|
||||
return
|
||||
endif
|
||||
|
||||
let l:message = ale#lsp#response#GetErrorMessage(a:response)
|
||||
|
||||
if empty(l:message)
|
||||
return
|
||||
endif
|
||||
|
||||
" This global variable is set here so we don't load the debugging.vim file
|
||||
" until someone uses :ALEInfo.
|
||||
let g:ale_lsp_error_messages = get(g:, 'ale_lsp_error_messages', {})
|
||||
|
||||
if !has_key(g:ale_lsp_error_messages, a:linter_name)
|
||||
let g:ale_lsp_error_messages[a:linter_name] = []
|
||||
endif
|
||||
|
||||
call add(g:ale_lsp_error_messages[a:linter_name], l:message)
|
||||
endfunction
|
||||
|
||||
function! ale#lsp_linter#HandleLSPResponse(conn_id, response) abort
|
||||
let l:method = get(a:response, 'method', '')
|
||||
let l:linter_name = get(s:lsp_linter_map, a:conn_id, '')
|
||||
|
||||
if get(a:response, 'jsonrpc', '') is# '2.0' && has_key(a:response, 'error')
|
||||
call s:HandleLSPErrorMessage(l:linter_name, a:response)
|
||||
elseif l:method is# 'textDocument/publishDiagnostics'
|
||||
call s:HandleLSPDiagnostics(a:conn_id, a:response)
|
||||
elseif get(a:response, 'type', '') is# 'event'
|
||||
\&& get(a:response, 'event', '') is# 'semanticDiag'
|
||||
call s:HandleTSServerDiagnostics(a:response, 'semantic')
|
||||
elseif get(a:response, 'type', '') is# 'event'
|
||||
\&& get(a:response, 'event', '') is# 'syntaxDiag'
|
||||
call s:HandleTSServerDiagnostics(a:response, 'syntax')
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Given a buffer, an LSP linter, and a callback to register for handling
|
||||
" messages, start up an LSP linter and get ready to receive errors or
|
||||
" completions.
|
||||
function! ale#lsp_linter#StartLSP(buffer, linter, callback) abort
|
||||
let l:command = ''
|
||||
let l:address = ''
|
||||
let l:root = ale#util#GetFunction(a:linter.project_root_callback)(a:buffer)
|
||||
|
||||
if empty(l:root) && a:linter.lsp isnot# 'tsserver'
|
||||
" If there's no project root, then we can't check files with LSP,
|
||||
" unless we are using tsserver, which doesn't use project roots.
|
||||
return {}
|
||||
endif
|
||||
|
||||
let l:initialization_options = {}
|
||||
|
||||
if has_key(a:linter, 'initialization_options_callback')
|
||||
let l:initialization_options = ale#util#GetFunction(a:linter.initialization_options_callback)(a:buffer)
|
||||
elseif has_key(a:linter, 'initialization_options')
|
||||
let l:initialization_options = a:linter.initialization_options
|
||||
endif
|
||||
|
||||
if a:linter.lsp is# 'socket'
|
||||
let l:address = ale#linter#GetAddress(a:buffer, a:linter)
|
||||
let l:conn_id = ale#lsp#ConnectToAddress(
|
||||
\ l:address,
|
||||
\ l:root,
|
||||
\ a:callback,
|
||||
\ l:initialization_options,
|
||||
\)
|
||||
else
|
||||
let l:executable = ale#linter#GetExecutable(a:buffer, a:linter)
|
||||
|
||||
if !executable(l:executable)
|
||||
return {}
|
||||
endif
|
||||
|
||||
let l:command = ale#job#PrepareCommand(
|
||||
\ a:buffer,
|
||||
\ ale#linter#GetCommand(a:buffer, a:linter),
|
||||
\)
|
||||
let l:conn_id = ale#lsp#StartProgram(
|
||||
\ l:executable,
|
||||
\ l:command,
|
||||
\ l:root,
|
||||
\ a:callback,
|
||||
\ l:initialization_options,
|
||||
\)
|
||||
endif
|
||||
|
||||
let l:language_id = ale#util#GetFunction(a:linter.language_callback)(a:buffer)
|
||||
|
||||
if empty(l:conn_id)
|
||||
if g:ale_history_enabled && !empty(l:command)
|
||||
call ale#history#Add(a:buffer, 'failed', l:conn_id, l:command)
|
||||
endif
|
||||
|
||||
return {}
|
||||
endif
|
||||
|
||||
let l:details = {
|
||||
\ 'buffer': a:buffer,
|
||||
\ 'connection_id': l:conn_id,
|
||||
\ 'command': l:command,
|
||||
\ 'project_root': l:root,
|
||||
\ 'language_id': l:language_id,
|
||||
\}
|
||||
|
||||
if ale#lsp#OpenDocument(l:details)
|
||||
if g:ale_history_enabled && !empty(l:command)
|
||||
call ale#history#Add(a:buffer, 'started', l:conn_id, l:command)
|
||||
endif
|
||||
endif
|
||||
|
||||
" The change message needs to be sent for tsserver before doing anything.
|
||||
if a:linter.lsp is# 'tsserver'
|
||||
call ale#lsp#NotifyForChanges(l:details)
|
||||
endif
|
||||
|
||||
return l:details
|
||||
endfunction
|
||||
|
||||
function! ale#lsp_linter#CheckWithLSP(buffer, linter) abort
|
||||
let l:info = g:ale_buffer_info[a:buffer]
|
||||
let l:lsp_details = ale#lsp_linter#StartLSP(
|
||||
\ a:buffer,
|
||||
\ a:linter,
|
||||
\ function('ale#lsp_linter#HandleLSPResponse'),
|
||||
\)
|
||||
|
||||
if empty(l:lsp_details)
|
||||
return 0
|
||||
endif
|
||||
|
||||
let l:id = l:lsp_details.connection_id
|
||||
let l:root = l:lsp_details.project_root
|
||||
|
||||
" Remember the linter this connection is for.
|
||||
let s:lsp_linter_map[l:id] = a:linter.name
|
||||
|
||||
if a:linter.lsp is# 'tsserver'
|
||||
let l:message = ale#lsp#tsserver_message#Geterr(a:buffer)
|
||||
let l:request_id = ale#lsp#Send(l:id, l:message, l:root)
|
||||
|
||||
let l:notified = l:request_id != 0
|
||||
else
|
||||
let l:notified = ale#lsp#NotifyForChanges(l:lsp_details)
|
||||
endif
|
||||
|
||||
" If this was a file save event, also notify the server of that.
|
||||
if a:linter.lsp isnot# 'tsserver'
|
||||
\&& getbufvar(a:buffer, 'ale_save_event_fired', 0)
|
||||
let l:save_message = ale#lsp#message#DidSave(a:buffer)
|
||||
let l:request_id = ale#lsp#Send(l:id, l:save_message, l:root)
|
||||
|
||||
let l:notified = l:request_id != 0
|
||||
endif
|
||||
|
||||
if l:notified
|
||||
if index(l:info.active_linter_list, a:linter.name) < 0
|
||||
call add(l:info.active_linter_list, a:linter.name)
|
||||
endif
|
||||
endif
|
||||
|
||||
return l:notified
|
||||
endfunction
|
||||
|
||||
" Clear LSP linter data for the linting engine.
|
||||
function! ale#lsp_linter#ClearLSPData() abort
|
||||
let s:lsp_linter_map = {}
|
||||
endfunction
|
||||
|
||||
" Just for tests.
|
||||
function! ale#lsp_linter#SetLSPLinterMap(replacement_map) abort
|
||||
let s:lsp_linter_map = a:replacement_map
|
||||
endfunction
|
@ -2,22 +2,41 @@
|
||||
" Description: Preview windows for showing whatever information in.
|
||||
|
||||
" Open a preview window and show some lines in it.
|
||||
" An optional second argument can set an alternative filetype for the window.
|
||||
" A second argument can be passed as a Dictionary with options. They are...
|
||||
"
|
||||
" filetype - The filetype to use, defaulting to 'ale-preview'
|
||||
" stay_here - If 1, stay in the window you came from.
|
||||
function! ale#preview#Show(lines, ...) abort
|
||||
let l:filetype = get(a:000, 0, 'ale-preview')
|
||||
let l:options = get(a:000, 0, {})
|
||||
|
||||
silent pedit ALEPreviewWindow
|
||||
wincmd P
|
||||
|
||||
setlocal modifiable
|
||||
setlocal noreadonly
|
||||
setlocal nobuflisted
|
||||
let &l:filetype = l:filetype
|
||||
let &l:filetype = get(l:options, 'filetype', 'ale-preview')
|
||||
setlocal buftype=nofile
|
||||
setlocal bufhidden=wipe
|
||||
:%d
|
||||
call setline(1, a:lines)
|
||||
setlocal nomodifiable
|
||||
setlocal readonly
|
||||
|
||||
if get(l:options, 'stay_here')
|
||||
wincmd p
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Close the preview window if the filetype matches the given one.
|
||||
function! ale#preview#CloseIfTypeMatches(filetype) abort
|
||||
for l:win in getwininfo()
|
||||
let l:wintype = gettabwinvar(l:win.tabnr, l:win.winnr, '&filetype')
|
||||
|
||||
if l:wintype is# a:filetype
|
||||
silent! pclose!
|
||||
endif
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
" Show a location selection preview window, given some items.
|
||||
@ -35,7 +54,7 @@ function! ale#preview#ShowSelection(item_list) abort
|
||||
\)
|
||||
endfor
|
||||
|
||||
call ale#preview#Show(l:lines, 'ale-preview-selection')
|
||||
call ale#preview#Show(l:lines, {'filetype': 'ale-preview-selection'})
|
||||
let b:ale_preview_item_list = a:item_list
|
||||
endfunction
|
||||
|
||||
|
@ -72,14 +72,13 @@ function! s:FindReferences(linter) abort
|
||||
\ ? function('ale#references#HandleTSServerResponse')
|
||||
\ : function('ale#references#HandleLSPResponse')
|
||||
|
||||
let l:lsp_details = ale#linter#StartLSP(l:buffer, a:linter, l:Callback)
|
||||
let l:lsp_details = ale#lsp_linter#StartLSP(l:buffer, a:linter, l:Callback)
|
||||
|
||||
if empty(l:lsp_details)
|
||||
return 0
|
||||
endif
|
||||
|
||||
let l:id = l:lsp_details.connection_id
|
||||
let l:root = l:lsp_details.project_root
|
||||
|
||||
if a:linter.lsp is# 'tsserver'
|
||||
let l:message = ale#lsp#tsserver_message#References(
|
||||
@ -90,14 +89,14 @@ function! s:FindReferences(linter) abort
|
||||
else
|
||||
" Send a message saying the buffer has changed first, or the
|
||||
" references position probably won't make sense.
|
||||
call ale#lsp#Send(l:id, ale#lsp#message#DidChange(l:buffer), l:root)
|
||||
call ale#lsp#NotifyForChanges(l:lsp_details)
|
||||
|
||||
let l:column = min([l:column, len(getline(l:line))])
|
||||
|
||||
let l:message = ale#lsp#message#References(l:buffer, l:line, l:column)
|
||||
endif
|
||||
|
||||
let l:request_id = ale#lsp#Send(l:id, l:message, l:root)
|
||||
let l:request_id = ale#lsp#Send(l:id, l:message, l:lsp_details.project_root)
|
||||
|
||||
let s:references_map[l:request_id] = {}
|
||||
endfunction
|
||||
|
144
sources_non_forked/ale/autoload/ale/socket.vim
Normal file
144
sources_non_forked/ale/autoload/ale/socket.vim
Normal file
@ -0,0 +1,144 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: APIs for working with asynchronous sockets, with an API
|
||||
" normalised between Vim 8 and NeoVim. Socket connections only work in NeoVim
|
||||
" 0.3+, and silently do nothing in earlier NeoVim versions.
|
||||
"
|
||||
" Important functions are described below. They are:
|
||||
"
|
||||
" ale#socket#Open(address, options) -> channel_id (>= 0 if successful)
|
||||
" ale#socket#IsOpen(channel_id) -> 1 if open, 0 otherwise
|
||||
" ale#socket#Close(channel_id)
|
||||
" ale#socket#Send(channel_id, data)
|
||||
" ale#socket#GetAddress(channel_id) -> Return the address for a job
|
||||
|
||||
let s:channel_map = get(s:, 'channel_map', {})
|
||||
|
||||
function! s:VimOutputCallback(channel, data) abort
|
||||
let l:channel_id = ch_info(a:channel).id
|
||||
|
||||
" Only call the callbacks for jobs which are valid.
|
||||
if l:channel_id >= 0 && has_key(s:channel_map, l:channel_id)
|
||||
call ale#util#GetFunction(s:channel_map[l:channel_id].callback)(l:channel_id, a:data)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:NeoVimOutputCallback(channel_id, data, event) abort
|
||||
let l:info = s:channel_map[a:channel_id]
|
||||
|
||||
if a:event is# 'data'
|
||||
let l:info.last_line = ale#util#JoinNeovimOutput(
|
||||
\ a:channel_id,
|
||||
\ l:info.last_line,
|
||||
\ a:data,
|
||||
\ l:info.mode,
|
||||
\ ale#util#GetFunction(l:info.callback),
|
||||
\)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Open a socket for a given address. The following options are accepted:
|
||||
"
|
||||
" callback - A callback for receiving input. (required)
|
||||
"
|
||||
" A non-negative number representing a channel ID will be returned is the
|
||||
" connection was successful. 0 is a valid channel ID in Vim, so test if the
|
||||
" connection ID is >= 0.
|
||||
function! ale#socket#Open(address, options) abort
|
||||
let l:mode = get(a:options, 'mode', 'raw')
|
||||
let l:Callback = a:options.callback
|
||||
|
||||
let l:channel_info = {
|
||||
\ 'address': a:address,
|
||||
\ 'mode': l:mode,
|
||||
\ 'callback': a:options.callback,
|
||||
\}
|
||||
|
||||
if !has('nvim')
|
||||
" Vim
|
||||
let l:channel_info.channel = ch_open(a:address, {
|
||||
\ 'mode': l:mode,
|
||||
\ 'waittime': 0,
|
||||
\ 'callback': function('s:VimOutputCallback'),
|
||||
\})
|
||||
let l:vim_info = ch_info(l:channel_info.channel)
|
||||
let l:channel_id = !empty(l:vim_info) ? l:vim_info.id : -1
|
||||
elseif exists('*chansend') && exists('*sockconnect')
|
||||
" NeoVim 0.3+
|
||||
try
|
||||
let l:channel_id = sockconnect('tcp', a:address, {
|
||||
\ 'on_data': function('s:NeoVimOutputCallback'),
|
||||
\})
|
||||
let l:channel_info.last_line = ''
|
||||
catch /connection failed/
|
||||
let l:channel_id = -1
|
||||
endtry
|
||||
|
||||
" 0 means the connection failed some times in NeoVim, so make the ID
|
||||
" invalid to match Vim.
|
||||
if l:channel_id is 0
|
||||
let l:channel_id = -1
|
||||
endif
|
||||
|
||||
let l:channel_info.channel = l:channel_id
|
||||
else
|
||||
" Other Vim versions.
|
||||
let l:channel_id = -1
|
||||
endif
|
||||
|
||||
if l:channel_id >= 0
|
||||
let s:channel_map[l:channel_id] = l:channel_info
|
||||
endif
|
||||
|
||||
return l:channel_id
|
||||
endfunction
|
||||
|
||||
" Return 1 is a channel is open, 0 otherwise.
|
||||
function! ale#socket#IsOpen(channel_id) abort
|
||||
if !has_key(s:channel_map, a:channel_id)
|
||||
return 0
|
||||
endif
|
||||
|
||||
if has('nvim')
|
||||
" In NeoVim, we have to check if this channel is in the global list.
|
||||
return index(map(nvim_list_chans(), 'v:val.id'), a:channel_id) >= 0
|
||||
endif
|
||||
|
||||
let l:channel = s:channel_map[a:channel_id].channel
|
||||
return ch_status(l:channel) is# 'open'
|
||||
endfunction
|
||||
|
||||
" Close a socket, if it's still open.
|
||||
function! ale#socket#Close(channel_id) abort
|
||||
" IsRunning isn't called here, so we don't check nvim_list_chans()
|
||||
if !has_key(s:channel_map, a:channel_id)
|
||||
return 0
|
||||
endif
|
||||
|
||||
let l:channel = remove(s:channel_map, a:channel_id).channel
|
||||
|
||||
if has('nvim')
|
||||
silent! call chanclose(l:channel)
|
||||
elseif ch_status(l:channel) is# 'open'
|
||||
call ch_close(l:channel)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Send some data to a socket.
|
||||
function! ale#socket#Send(channel_id, data) abort
|
||||
if !has_key(s:channel_map, a:channel_id)
|
||||
return
|
||||
endif
|
||||
|
||||
let l:channel = s:channel_map[a:channel_id].channel
|
||||
|
||||
if has('nvim')
|
||||
call chansend(l:channel, a:data)
|
||||
else
|
||||
call ch_sendraw(l:channel, a:data)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Get an address for a channel, or an empty string.
|
||||
function! ale#socket#GetAddress(channel_id) abort
|
||||
return get(get(s:channel_map, a:channel_id, {}), 'address', '')
|
||||
endfunction
|
@ -1,14 +1,6 @@
|
||||
" Author: KabbAmine <amine.kabb@gmail.com>
|
||||
" Description: Statusline related function(s)
|
||||
|
||||
" remove in 2.0
|
||||
"
|
||||
" A deprecated setting for ale#statusline#Status()
|
||||
" See :help ale#statusline#Count() for getting status reports.
|
||||
let g:ale_statusline_format = get(g:, 'ale_statusline_format',
|
||||
\ ['%d error(s)', '%d warning(s)', 'OK']
|
||||
\)
|
||||
|
||||
function! s:CreateCountDict() abort
|
||||
" Keys 0 and 1 are for backwards compatibility.
|
||||
" The count object used to be a List of [error_count, warning_count].
|
||||
@ -76,47 +68,3 @@ function! ale#statusline#Count(buffer) abort
|
||||
" The Dictionary is copied here before exposing it to other plugins.
|
||||
return copy(s:GetCounts(a:buffer))
|
||||
endfunction
|
||||
|
||||
" This is the historical format setting which could be configured before.
|
||||
function! s:StatusForListFormat() abort
|
||||
let [l:error_format, l:warning_format, l:no_errors] = g:ale_statusline_format
|
||||
let l:counts = s:GetCounts(bufnr(''))
|
||||
|
||||
" Build strings based on user formatting preferences.
|
||||
let l:errors = l:counts[0] ? printf(l:error_format, l:counts[0]) : ''
|
||||
let l:warnings = l:counts[1] ? printf(l:warning_format, l:counts[1]) : ''
|
||||
|
||||
" Different formats based on the combination of errors and warnings.
|
||||
if empty(l:errors) && empty(l:warnings)
|
||||
let l:res = l:no_errors
|
||||
elseif !empty(l:errors) && !empty(l:warnings)
|
||||
let l:res = printf('%s %s', l:errors, l:warnings)
|
||||
else
|
||||
let l:res = empty(l:errors) ? l:warnings : l:errors
|
||||
endif
|
||||
|
||||
return l:res
|
||||
endfunction
|
||||
|
||||
" remove in 2.0
|
||||
"
|
||||
" Returns a formatted string that can be integrated in the statusline.
|
||||
"
|
||||
" This function is deprecated, and should not be used. Use the airline plugin
|
||||
" instead, or write your own status function with ale#statusline#Count()
|
||||
function! ale#statusline#Status() abort
|
||||
if !get(g:, 'ale_deprecation_ale_statusline_status', 0)
|
||||
execute 'echom ''ale#statusline#Status() is deprecated, use ale#statusline#Count() to write your own function.'''
|
||||
let g:ale_deprecation_ale_statusline_status = 1
|
||||
endif
|
||||
|
||||
if !exists('g:ale_statusline_format')
|
||||
return 'OK'
|
||||
endif
|
||||
|
||||
if type(g:ale_statusline_format) == type([])
|
||||
return s:StatusForListFormat()
|
||||
endif
|
||||
|
||||
return ''
|
||||
endfunction
|
||||
|
@ -48,7 +48,7 @@ function! ale#toggle#Toggle() abort
|
||||
endif
|
||||
endif
|
||||
|
||||
call ale#autocmd#InitAuGroups()
|
||||
call ale#events#Init()
|
||||
endfunction
|
||||
|
||||
function! ale#toggle#Enable() abort
|
||||
|
@ -17,11 +17,18 @@ endfunction
|
||||
" but NeoVim does. Small messages can be echoed in Vim 8, and larger messages
|
||||
" have to be shown in preview windows.
|
||||
function! ale#util#ShowMessage(string) abort
|
||||
if !has('nvim')
|
||||
call ale#preview#CloseIfTypeMatches('ale-preview.message')
|
||||
endif
|
||||
|
||||
" We have to assume the user is using a monospace font.
|
||||
if has('nvim') || (a:string !~? "\n" && len(a:string) < &columns)
|
||||
execute 'echo a:string'
|
||||
else
|
||||
call ale#preview#Show(split(a:string, "\n"))
|
||||
call ale#preview#Show(split(a:string, "\n"), {
|
||||
\ 'filetype': 'ale-preview.message',
|
||||
\ 'stay_here': 1,
|
||||
\})
|
||||
endif
|
||||
endfunction
|
||||
|
||||
@ -39,6 +46,33 @@ if !exists('g:ale#util#nul_file')
|
||||
endif
|
||||
endif
|
||||
|
||||
" Given a job, a buffered line of data, a list of parts of lines, a mode data
|
||||
" is being read in, and a callback, join the lines of output for a NeoVim job
|
||||
" or socket together, and call the callback with the joined output.
|
||||
"
|
||||
" Note that jobs and IDs are the same thing on NeoVim.
|
||||
function! ale#util#JoinNeovimOutput(job, last_line, data, mode, callback) abort
|
||||
if a:mode is# 'raw'
|
||||
call a:callback(a:job, join(a:data, "\n"))
|
||||
return ''
|
||||
endif
|
||||
|
||||
let l:lines = a:data[:-2]
|
||||
|
||||
if len(a:data) > 1
|
||||
let l:lines[0] = a:last_line . l:lines[0]
|
||||
let l:new_last_line = a:data[-1]
|
||||
else
|
||||
let l:new_last_line = a:last_line . get(a:data, 0, '')
|
||||
endif
|
||||
|
||||
for l:line in l:lines
|
||||
call a:callback(a:job, l:line)
|
||||
endfor
|
||||
|
||||
return l:new_last_line
|
||||
endfunction
|
||||
|
||||
" Return the number of lines for a given buffer.
|
||||
function! ale#util#GetLineCount(buffer) abort
|
||||
return len(getbufline(a:buffer, 1, '$'))
|
||||
@ -56,7 +90,10 @@ function! ale#util#Open(filename, line, column, options) abort
|
||||
if get(a:options, 'open_in_tab', 0)
|
||||
call ale#util#Execute('tabedit ' . fnameescape(a:filename))
|
||||
else
|
||||
call ale#util#Execute('edit ' . fnameescape(a:filename))
|
||||
" Open another file only if we need to.
|
||||
if bufnr(a:filename) isnot bufnr('')
|
||||
call ale#util#Execute('edit ' . fnameescape(a:filename))
|
||||
endif
|
||||
endif
|
||||
|
||||
call cursor(a:line, a:column)
|
||||
@ -241,16 +278,6 @@ function! ale#util#InSandbox() abort
|
||||
return 0
|
||||
endfunction
|
||||
|
||||
" Get the number of milliseconds since some vague, but consistent, point in
|
||||
" the past.
|
||||
"
|
||||
" This function can be used for timing execution, etc.
|
||||
"
|
||||
" The time will be returned as a Number.
|
||||
function! ale#util#ClockMilliseconds() abort
|
||||
return float2nr(reltimefloat(reltime()) * 1000)
|
||||
endfunction
|
||||
|
||||
" Given a single line, or a List of lines, and a single pattern, or a List
|
||||
" of patterns, return all of the matches for the lines(s) from the given
|
||||
" patterns, using matchlist().
|
||||
|
Reference in New Issue
Block a user