<commit_before>" Author: w0rp <<EMAIL>>
" 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

" A Dictionary to track one-shot handlers for custom LSP requests
let s:custom_handlers_map = get(s:, 'custom_handlers_map', {})

" Check if diagnostics for a particular linter should be ignored.
function! s:ShouldIgnore(buffer, linter_name) abort
    " Ignore all diagnostics if LSP integration is disabled.
    if ale#Var(a:buffer, 'disable_lsp')
        return 1
    endif

    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:escaped_name = escape(
    \   fnameescape(l:filename),
    \   has('win32') ? '^' : '^,}]'
    \)
    let l:buffer = bufnr('^' . l:escaped_name . '$')
    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:loclist = ale#lsp#response#ReadDiagnostics(a:response)

    call ale#engine#HandleLoclist(l:linter_name, l:buffer, l:loclist, 0)
endfunction

function! s:HandleTSServerDiagnostics(response, error_type) abort
    let l:linter_name = 'tsserver'
    let l:escaped_name = escape(
    \   fnameescape(a:response.body.file),
    \   has('win32') ? '^' : '^,}]'
    \)
    let l:buffer = bufnr('^' . l:escaped_name . '$')
    let l:info = get(g:ale_buffer_info, l:buffer, {})

    if empty(l:info)
        return
    endif

    call ale#engine#MarkLinterInactive(l:info, l:linter_name)

    if s:ShouldIgnore(l:buffer, l:linter_name)
        return
    endif

    let l:thislist = ale#lsp#response#ReadTSServerDiagnostics(a:response)
    let l:no_changes = 0

    " 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'
        if len(l:thislist) is 0 && len(get(l:info, 'syntax_loclist', [])) is 0
            let l:no_changes = 1
        endif

        let l:info.syntax_loclist = l:thislist
    else
        if len(l:thislist) is 0 && len(get(l:info, 'semantic_loclist', [])) is 0
            let l:no_changes = 1
        endif

        let l:info.semantic_loclist = l:thislist
    endif

    if l:no_changes
        return
    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, 0)
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', '')

    if get(a:response, 'jsonrpc', '') is# '2.0' && has_key(a:response, 'error')
        let l:linter_name = get(s:lsp_linter_map, a:conn_id, '')

        call s:HandleLSPErrorMessage(l:linter_name, a:response)
    elseif l:method is# 'textDocument/publishDiagnostics'
        call s:HandleLSPDiagnostics(a:conn_id, a:response)
    elseif l:method is# 'window/showMessage'
        call ale#lsp_window#HandleShowMessage(
        \   s:lsp_linter_map[a:conn_id],
        \   g:ale_lsp_show_message_format,
        \   a:response.params
        \)
    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#lsp_linter#GetOptions(buffer, linter) abort
    if has_key(a:linter, 'initialization_options_callback')
        return ale#util#GetFunction(a:linter.initialization_options_callback)(a:buffer)
    endif

    if has_key(a:linter, 'initialization_options')
        let l:Options = a:linter.initialization_options

        if type(l:Options) is v:t_func
            let l:Options = l:Options(a:buffer)<commit_msg>Show tsserver hints/suggestions in Ale.<commit_after>" Author: w0rp <<EMAIL>>
" 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

" A Dictionary to track one-shot handlers for custom LSP requests
let s:custom_handlers_map = get(s:, 'custom_handlers_map', {})

" Check if diagnostics for a particular linter should be ignored.
function! s:ShouldIgnore(buffer, linter_name) abort
    " Ignore all diagnostics if LSP integration is disabled.
    if ale#Var(a:buffer, 'disable_lsp')
        return 1
    endif

    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:escaped_name = escape(
    \   fnameescape(l:filename),
    \   has('win32') ? '^' : '^,}]'
    \)
    let l:buffer = bufnr('^' . l:escaped_name . '$')
    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:loclist = ale#lsp#response#ReadDiagnostics(a:response)

    call ale#engine#HandleLoclist(l:linter_name, l:buffer, l:loclist, 0)
endfunction

function! s:HandleTSServerDiagnostics(response, error_type) abort
    let l:linter_name = 'tsserver'
    let l:escaped_name = escape(
    \   fnameescape(a:response.body.file),
    \   has('win32') ? '^' : '^,}]'
    \)
    let l:buffer = bufnr('^' . l:escaped_name . '$')
    let l:info = get(g:ale_buffer_info, l:buffer, {})

    if empty(l:info)
        return
    endif

    call ale#engine#MarkLinterInactive(l:info, l:linter_name)

    if s:ShouldIgnore(l:buffer, l:linter_name)
        return
    endif

    let l:thislist = ale#lsp#response#ReadTSServerDiagnostics(a:response)
    let l:no_changes = 0

    " 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'
        if len(l:thislist) is 0 && len(get(l:info, 'syntax_loclist', [])) is 0
            let l:no_changes = 1
        endif

        let l:info.syntax_loclist = l:thislist
    elseif a:error_type is# 'semantic'
        if len(l:thislist) is 0 && len(get(l:info, 'semantic_loclist', [])) is 0
            let l:no_changes = 1
        endif

        let l:info.semantic_loclist = l:thislist
    else
        if len(l:thislist) is 0 && len(get(l:info, 'suggestion_loclist', [])) is 0
            let l:no_changes = 1
        endif

        let l:info.suggestion_loclist = l:thislist
    endif

    if l:no_changes
        return
    endif

    let l:loclist = get(l:info, 'semantic_loclist', [])
    \   + get(l:info, 'suggestion_loclist', [])
    \   + get(l:info, 'syntax_loclist', [])

    call ale#engine#HandleLoclist(l:linter_name, l:buffer, l:loclist, 0)
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', '')

    if get(a:response, 'jsonrpc', '') is# '2.0' && has_key(a:response, 'error')
        let l:linter_name = get(s:lsp_linter_map, a:conn_id, '')

        call s:HandleLSPErrorMessage(l:linter_name, a:response)
    elseif l:method is# 'textDocument/publishDiagnostics'
        call s:HandleLSPDiagnostics(a:conn_id, a:response)
    elseif l:method is# 'window/showMessage'
        call ale#lsp_window#HandleShowMessage(
        \   s:lsp_linter_map[a:conn_id],
        \   g:ale_lsp_show_message_format,
        \   a:response.params
        \)
    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')
    elseif get(a:response, 'type', '') is# 'event'
    \&& get(a:response, 'event', '') is# 'suggestionDiag'
        call s:HandleTSServerDiagnostics(a:response, 'suggestion')
    endif
endfunction

function! ale#lsp_linter#GetOptions(buffer, linter) abort
    if has_key(a:linter, 'initialization_options_callback')
        return ale#util#GetFunction(a:linter.initialization_options_callback)(a:buffer)
    endif

    if has_key(a:linter, 'initialization_options')
        let l:Options = a:linter.initialization_options

        if type(l:Options) is v:t_func
            let l:Options = l:Options(a:buffer)
{'fraction_non_alphanumeric': 0.11997106952355122, 'fraction_numerical': 0.003706717295000452, 'mean_word_length': 3.5224856909239577, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6930211', 'n_tokens_mistral': 3989, 'n_tokens_neox': 3834, 'n_words': 848}