mirror of
				https://github.com/amix/vimrc
				synced 2025-10-31 06:33:35 +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
	 Amir Salihefendic
					Amir Salihefendic