]> git.madduck.net Git - etc/vim.git/blobdiff - .vim/bundle/vim-lsp-ale/autoload/lsp/ale.vim

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Merge commit '294584081929424aec883f90c7d6515b3743358d' as '.vim/bundle/vim-lsp-ale'
[etc/vim.git] / .vim / bundle / vim-lsp-ale / autoload / lsp / ale.vim
diff --git a/.vim/bundle/vim-lsp-ale/autoload/lsp/ale.vim b/.vim/bundle/vim-lsp-ale/autoload/lsp/ale.vim
new file mode 100644 (file)
index 0000000..04db135
--- /dev/null
@@ -0,0 +1,203 @@
+" DiagnosticSeverity
+let s:ERROR = 1
+let s:WARN = 2
+let s:INFO = 3
+let s:HINT = 4
+
+let s:Dispose = v:null
+
+function! s:severity_threshold() abort
+    let s = g:lsp_ale_diagnostics_severity
+    if s ==? 'error'
+        return s:ERROR
+    elseif s ==? 'warning' || s ==? 'warn'
+        return s:WARN
+    elseif s ==? 'information' || s ==? 'info'
+        return s:INFO
+    elseif s ==? 'hint'
+        return s:HINT
+    else
+        throw 'vim-lsp-ale: Unexpected severity "' . s . '". Severity must be one of "error", "warning", "information", "hint"'
+    endif
+endfunction
+
+function! s:get_loc_type(severity) abort
+    if a:severity == s:ERROR
+        return 'E'
+    elseif a:severity == s:WARN
+        return 'W'
+    elseif a:severity == s:INFO
+        return 'I'
+    elseif a:severity == s:HINT
+        return 'H'
+    else
+        throw 'vim-lsp-ale: Unexpected severity: ' . a:severity
+    endif
+endfunction
+
+let s:prev_num_diags = {}
+function! lsp#ale#_reset_prev_num_diags() abort
+    let s:prev_num_diags = {}
+endfunction
+
+function! s:can_skip_diags(server, uri, diags) abort
+    if !has_key(s:prev_num_diags, a:server)
+        let s:prev_num_diags[a:server] = {}
+    endif
+    let prev = s:prev_num_diags[a:server]
+
+    let num_diags = len(a:diags)
+    if num_diags == 0 && get(prev, a:uri, -1) == 0
+        " Some language servers send diagnostics notifications even if the
+        " results are not changed from previous. It's hard to check the
+        " notifications are perfectly the same as previous. Here only checks
+        " emptiness and skip if both previous ones and current ones are
+        " empty.
+        " I believe programmers usually try to keep no lint errors in the
+        " source code they are writing :)
+        return v:true
+    endif
+
+    let prev[a:uri] = num_diags
+    return v:false
+endfunction
+
+function! s:can_skip_all_diags(uri, all_diags) abort
+    for [server, diags] in items(a:all_diags)
+        if !s:can_skip_diags(server, a:uri, diags.params.diagnostics)
+            return v:false
+        endif
+    endfor
+    return v:true
+endfunction
+
+function! s:is_active_linter() abort
+    if g:lsp_ale_auto_enable_linter
+        return v:true
+    endif
+    let active_linters = get(b:, 'ale_linters', get(g:ale_linters, &filetype, []))
+    return index(active_linters, 'vim-lsp') >= 0
+endf
+
+function! lsp#ale#on_ale_want_results(bufnr) abort
+    " Note: Checking lsp#internal#diagnostics#state#_is_enabled_for_buffer here. If previous lint
+    " errors remain in a buffer, they won't be updated when vim-lsp is disabled for the buffer.
+    if s:Dispose is v:null || !lsp#internal#diagnostics#state#_is_enabled_for_buffer(a:bufnr)
+        return
+    endif
+
+    let uri = lsp#utils#get_buffer_uri(a:bufnr)
+    let all_diags = lsp#internal#diagnostics#state#_get_all_diagnostics_grouped_by_server_for_uri(uri)
+    if empty(all_diags) || s:can_skip_all_diags(uri, all_diags)
+        " Do nothing when no diagnostics results
+        return
+    endif
+
+    if s:is_active_linter()
+        call ale#other_source#StartChecking(a:bufnr, 'vim-lsp')
+        " Avoid the issue that sign and highlight are not set
+        " https://github.com/dense-analysis/ale/issues/3690
+        call timer_start(0, {-> s:notify_diag_to_ale(a:bufnr, all_diags) })
+    endif
+endfunction
+
+function! s:notify_diag_to_ale(bufnr, diags) abort
+    try
+        let threshold = s:severity_threshold()
+        let results = []
+        for [server, diag] in items(a:diags)
+            " Note: Do not filter `diag` destructively since the object is also used by vim-lsp
+            let locs = lsp#ui#vim#utils#diagnostics_to_loc_list({'response': diag})
+            let idx = 0
+            for loc in locs
+                let severity = get(diag.params.diagnostics[idx], 'severity', s:ERROR)
+                if severity > threshold
+                    continue
+                endif
+                let loc.text = '[' . server . '] ' . loc.text
+                let loc.type = s:get_loc_type(severity)
+                let results += [loc]
+                let idx += 1
+            endfor
+        endfor
+    catch
+        " Since ale#other_source#StartChecking() was already called, ale#other_source#ShowResults()
+        " needs to be called to notify ALE that checking was done.
+        call ale#other_source#ShowResults(a:bufnr, 'vim-lsp', [])
+        let msg = v:exception . ' at ' . v:throwpoint
+        if msg !~# '^vim-lsp-ale: '
+            " Avoid E608 on rethrowing exceptions from Vim script runtime
+            let msg = 'vim-lsp-ale: Error while notifying results to ALE: ' . msg
+        endif
+        throw msg
+    endtry
+    call ale#other_source#ShowResults(a:bufnr, 'vim-lsp', results)
+endfunction
+
+function! s:notify_diag_to_ale_for_buf(bufnr) abort
+    if !s:is_active_linter()
+        return
+    endif
+
+    let uri = lsp#utils#get_buffer_uri(a:bufnr)
+    let diags = lsp#internal#diagnostics#state#_get_all_diagnostics_grouped_by_server_for_uri(uri)
+    call s:notify_diag_to_ale(a:bufnr, diags)
+endfunction
+
+function! s:on_diagnostics(res) abort
+    let uri = a:res.response.params.uri
+    if s:can_skip_diags(a:res.server, uri, a:res.response.params.diagnostics)
+        return
+    endif
+
+    let path = lsp#utils#uri_to_path(uri)
+    let bufnr = bufnr('^' . path . '$')
+    if bufnr == -1
+        " This branch is reachable when vim-lsp receives some notifications
+        " but the buffer for them was already deleted. This can happen since
+        " notifications are asynchronous
+        return
+    endif
+
+    call ale#other_source#StartChecking(bufnr, 'vim-lsp')
+    " Use timer_start to ensure calling s:notify_diag_to_ale after all
+    " subscribers handled the publishDiagnostics event.
+    " lsp_setup is hooked before vim-lsp sets various internal hooks. So this
+    " function is called before the response is not handled by vim-lsp yet.
+    call timer_start(0, {-> s:notify_diag_to_ale_for_buf(bufnr) })
+endfunction
+
+function! s:is_diagnostics_response(item) abort
+    if !has_key(a:item, 'server') || !has_key(a:item, 'response')
+        return v:false
+    endif
+    let res = a:item.response
+    if !has_key(res, 'method')
+        return v:false
+    endif
+    return res.method ==# 'textDocument/publishDiagnostics'
+endfunction
+
+function! lsp#ale#enable() abort
+    if s:Dispose isnot v:null
+        return
+    endif
+
+    let s:Dispose = lsp#callbag#pipe(
+            \   lsp#stream(),
+            \   lsp#callbag#filter(funcref('s:is_diagnostics_response')),
+            \   lsp#callbag#subscribe({ 'next': funcref('s:on_diagnostics') }),
+            \ )
+endfunction
+
+function! lsp#ale#disable() abort
+    if s:Dispose is v:null
+        return
+    endif
+    call s:Dispose()
+    let s:Dispose = v:null
+endfunction
+
+function! lsp#ale#enabled() abort
+    return s:Dispose isnot v:null
+endfunction