diff options
Diffstat (limited to 'autoload')
-rw-r--r-- | autoload/ale/c.vim | 25 | ||||
-rw-r--r-- | autoload/ale/completion.vim | 101 | ||||
-rw-r--r-- | autoload/ale/definition.vim | 19 | ||||
-rw-r--r-- | autoload/ale/engine.vim | 6 | ||||
-rw-r--r-- | autoload/ale/fix.vim | 28 | ||||
-rw-r--r-- | autoload/ale/fix/registry.vim | 5 | ||||
-rw-r--r-- | autoload/ale/fixers/styler.vim | 16 | ||||
-rw-r--r-- | autoload/ale/highlight.vim | 140 | ||||
-rw-r--r-- | autoload/ale/lsp/response.vim | 2 | ||||
-rw-r--r-- | autoload/ale/lsp_linter.vim | 15 | ||||
-rw-r--r-- | autoload/ale/sign.vim | 2 | ||||
-rw-r--r-- | autoload/ale/util.vim | 2 | ||||
-rw-r--r-- | autoload/ale/virtualtext.vim | 2 |
13 files changed, 295 insertions, 68 deletions
diff --git a/autoload/ale/c.vim b/autoload/ale/c.vim index eeb512ba..a9289e22 100644 --- a/autoload/ale/c.vim +++ b/autoload/ale/c.vim @@ -219,9 +219,32 @@ function! ale#c#ParseCompileCommandsFlags(buffer, file_lookup, dir_lookup) abort " Search for an exact file match first. let l:basename = tolower(expand('#' . a:buffer . ':t')) let l:file_list = get(a:file_lookup, l:basename, []) + " A source file matching the header filename. + let l:source_file = '' + + if empty(l:file_list) && l:basename =~? '\.h$\|\.hpp$' + for l:suffix in ['.c', '.cpp'] + let l:key = fnamemodify(l:basename, ':r') . l:suffix + let l:file_list = get(a:file_lookup, l:key, []) + + if !empty(l:file_list) + let l:source_file = l:key + break + endif + endfor + endif for l:item in l:file_list - if bufnr(l:item.file) is a:buffer && has_key(l:item, 'command') + " Load the flags for this file, or for a source file matching the + " header file. + if has_key(l:item, 'command') + \&& ( + \ bufnr(l:item.file) is a:buffer + \ || ( + \ !empty(l:source_file) + \ && l:item.file[-len(l:source_file):] is? l:source_file + \ ) + \) return ale#c#ParseCFlags(l:item.directory, l:item.command) endif endfor diff --git a/autoload/ale/completion.vim b/autoload/ale/completion.vim index 682f4c43..1d42c489 100644 --- a/autoload/ale/completion.vim +++ b/autoload/ale/completion.vim @@ -159,18 +159,20 @@ function! ale#completion#Filter(buffer, filetype, suggestions, prefix) abort endfunction function! s:ReplaceCompletionOptions() abort - " Remember the old omnifunc value, if there is one. - " If we don't store an old one, we'll just never reset the option. - " This will stop some random exceptions from appearing. - if !exists('b:ale_old_omnifunc') && !empty(&l:omnifunc) - let b:ale_old_omnifunc = &l:omnifunc - endif - - let &l:omnifunc = 'ale#completion#OmniFunc' + let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '') + + if l:source is# 'ale-automatic' || l:source is# 'ale-manual' + " Remember the old omnifunc value, if there is one. + " If we don't store an old one, we'll just never reset the option. + " This will stop some random exceptions from appearing. + if !exists('b:ale_old_omnifunc') && !empty(&l:omnifunc) + let b:ale_old_omnifunc = &l:omnifunc + endif - let l:info = get(b:, 'ale_completion_info', {}) + let &l:omnifunc = 'ale#completion#OmniFunc' + endif - if !get(l:info, 'manual') + if l:source is# 'ale-automatic' if !exists('b:ale_old_completeopt') let b:ale_old_completeopt = &l:completeopt endif @@ -199,31 +201,49 @@ function! ale#completion#RestoreCompletionOptions() abort endif endfunction -function! ale#completion#OmniFunc(findstart, base) abort - if a:findstart - let l:line = b:ale_completion_info.line - let l:column = b:ale_completion_info.column - let l:regex = s:GetFiletypeValue(s:omni_start_map, &filetype) - let l:up_to_column = getline(l:line)[: l:column - 2] - let l:match = matchstr(l:up_to_column, l:regex) +function! ale#completion#GetCompletionPosition() abort + if !exists('b:ale_completion_info') + return 0 + endif - return l:column - len(l:match) - 1 - else - " Parse a new response if there is one. - if exists('b:ale_completion_response') - \&& exists('b:ale_completion_parser') - let l:response = b:ale_completion_response - let l:parser = b:ale_completion_parser + let l:line = b:ale_completion_info.line + let l:column = b:ale_completion_info.column + let l:regex = s:GetFiletypeValue(s:omni_start_map, &filetype) + let l:up_to_column = getline(l:line)[: l:column - 2] + let l:match = matchstr(l:up_to_column, l:regex) + + return l:column - len(l:match) - 1 +endfunction - unlet b:ale_completion_response - unlet b:ale_completion_parser +function! ale#completion#GetCompletionResult() abort + " Parse a new response if there is one. + if exists('b:ale_completion_response') + \&& exists('b:ale_completion_parser') + let l:response = b:ale_completion_response + let l:parser = b:ale_completion_parser - let b:ale_completion_result = function(l:parser)(l:response) - endif + unlet b:ale_completion_response + unlet b:ale_completion_parser + + let b:ale_completion_result = function(l:parser)(l:response) + endif + + if exists('b:ale_completion_result') + return b:ale_completion_result + endif + + return v:null +endfunction + +function! ale#completion#OmniFunc(findstart, base) abort + if a:findstart + return ale#completion#GetCompletionPosition() + else + let l:result = ale#completion#GetCompletionResult() call s:ReplaceCompletionOptions() - return get(b:, 'ale_completion_result', []) + return l:result isnot v:null ? l:result : [] endif endfunction @@ -239,7 +259,14 @@ function! ale#completion#Show(response, completion_parser) abort " Replace completion options shortly before opening the menu. call s:ReplaceCompletionOptions() - call timer_start(0, {-> ale#util#FeedKeys("\<Plug>(ale_show_completion_menu)")}) + let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '') + + if l:source is# 'ale-automatic' || l:source is# 'ale-manual' + call timer_start( + \ 0, + \ {-> ale#util#FeedKeys("\<Plug>(ale_show_completion_menu)")} + \) + endif endfunction function! s:CompletionStillValid(request_id) abort @@ -249,7 +276,10 @@ function! s:CompletionStillValid(request_id) abort \&& has_key(b:, 'ale_completion_info') \&& b:ale_completion_info.request_id == a:request_id \&& b:ale_completion_info.line == l:line - \&& b:ale_completion_info.column == l:column + \&& ( + \ b:ale_completion_info.column == l:column + \ || b:ale_completion_info.source is# 'deoplete' + \) endfunction function! ale#completion#ParseTSServerCompletions(response) abort @@ -519,12 +549,12 @@ endfunction " This function can be used to manually trigger autocomplete, even when " g:ale_completion_enabled is set to false -function! ale#completion#GetCompletions(manual) abort +function! ale#completion#GetCompletions(source) abort let [l:line, l:column] = getpos('.')[1:2] let l:prefix = ale#completion#GetPrefix(&filetype, l:line, l:column) - if !a:manual && empty(l:prefix) + if a:source is# 'ale-automatic' && empty(l:prefix) return endif @@ -537,8 +567,9 @@ function! ale#completion#GetCompletions(manual) abort \ 'prefix': l:prefix, \ 'conn_id': 0, \ 'request_id': 0, - \ 'manual': a:manual, + \ 'source': a:source, \} + unlet! b:ale_completion_result let l:buffer = bufnr('') let l:Callback = function('s:OnReady') @@ -562,7 +593,7 @@ function! s:TimerHandler(...) abort " When running the timer callback, we have to be sure that the cursor " hasn't moved from where it was when we requested completions by typing. if s:timer_pos == [l:line, l:column] && ale#util#Mode() is# 'i' - call ale#completion#GetCompletions(0) + call ale#completion#GetCompletions('ale-automatic') endif endfunction diff --git a/autoload/ale/definition.vim b/autoload/ale/definition.vim index 521f0b45..3915cac1 100644 --- a/autoload/ale/definition.vim +++ b/autoload/ale/definition.vim @@ -3,6 +3,9 @@ let s:go_to_definition_map = {} +" Enable automatic updates of the tagstack +let g:ale_update_tagstack = get(g:, 'ale_update_tagstack', 1) + " Used to get the definition map in tests. function! ale#definition#GetMap() abort return deepcopy(s:go_to_definition_map) @@ -17,6 +20,20 @@ function! ale#definition#ClearLSPData() abort let s:go_to_definition_map = {} endfunction +function! ale#definition#UpdateTagStack() abort + let l:should_update_tagstack = exists('*gettagstack') && exists('*settagstack') && g:ale_update_tagstack + + if l:should_update_tagstack + " Grab the old location (to jump back to) and the word under the + " cursor (as a label for the tagstack) + let l:old_location = [bufnr('%'), line('.'), col('.'), 0] + let l:tagname = expand('<cword>') + let l:winid = win_getid() + call settagstack(l:winid, {'items': [{'from': l:old_location, 'tagname': l:tagname}]}, 'a') + call settagstack(l:winid, {'curidx': len(gettagstack(l:winid)['items']) + 1}) + endif +endfunction + function! ale#definition#HandleTSServerResponse(conn_id, response) abort if get(a:response, 'command', '') is# 'definition' \&& has_key(s:go_to_definition_map, a:response.request_seq) @@ -27,6 +44,7 @@ function! ale#definition#HandleTSServerResponse(conn_id, response) abort let l:line = a:response.body[0].start.line let l:column = a:response.body[0].start.offset + call ale#definition#UpdateTagStack() call ale#util#Open(l:filename, l:line, l:column, l:options) endif endif @@ -51,6 +69,7 @@ function! ale#definition#HandleLSPResponse(conn_id, response) abort let l:line = l:item.range.start.line + 1 let l:column = l:item.range.start.character + 1 + call ale#definition#UpdateTagStack() call ale#util#Open(l:filename, l:line, l:column, l:options) break endfor diff --git a/autoload/ale/engine.vim b/autoload/ale/engine.vim index 6b312b4f..7db808d6 100644 --- a/autoload/ale/engine.vim +++ b/autoload/ale/engine.vim @@ -39,8 +39,8 @@ function! ale#engine#MarkLinterActive(info, linter) abort endif endfunction -function! ale#engine#MarkLinterInactive(info, linter) abort - call filter(a:info.active_linter_list, 'v:val.name isnot# a:linter.name') +function! ale#engine#MarkLinterInactive(info, linter_name) abort + call filter(a:info.active_linter_list, 'v:val.name isnot# a:linter_name') endfunction function! ale#engine#ResetExecutableCache() abort @@ -195,7 +195,7 @@ function! s:HandleExit(job_info, buffer, output, data) abort let l:next_chain_index = a:job_info.next_chain_index " Remove this job from the list. - call ale#engine#MarkLinterInactive(l:buffer_info, l:linter) + call ale#engine#MarkLinterInactive(l:buffer_info, l:linter.name) " Stop here if we land in the handle for a job completing if we're in " a sandbox. diff --git a/autoload/ale/fix.vim b/autoload/ale/fix.vim index c0f05611..92ae3e14 100644 --- a/autoload/ale/fix.vim +++ b/autoload/ale/fix.vim @@ -1,3 +1,5 @@ +call ale#Set('fix_on_save_ignore', {}) + " Apply fixes queued up for buffers which may be hidden. " Vim doesn't let you modify hidden buffers. function! ale#fix#ApplyQueuedFixes() abort @@ -265,7 +267,21 @@ function! s:AddSubCallbacks(full_list, callbacks) abort return 1 endfunction -function! s:GetCallbacks(buffer, fixers) abort +function! s:IgnoreFixers(callback_list, filetype, config) abort + if type(a:config) is v:t_list + let l:ignore_list = a:config + else + let l:ignore_list = [] + + for l:part in split(a:filetype , '\.') + call extend(l:ignore_list, get(a:config, l:part, [])) + endfor + endif + + call filter(a:callback_list, 'index(l:ignore_list, v:val) < 0') +endfunction + +function! s:GetCallbacks(buffer, fixing_flag, fixers) abort if len(a:fixers) let l:callback_list = a:fixers elseif type(get(b:, 'ale_fixers')) is v:t_list @@ -290,8 +306,12 @@ function! s:GetCallbacks(buffer, fixers) abort endif endif - if empty(l:callback_list) - return [] + if a:fixing_flag is# 'save_file' + let l:config = ale#Var(a:buffer, 'fix_on_save_ignore') + + if !empty(l:config) + call s:IgnoreFixers(l:callback_list, &filetype, l:config) + endif endif let l:corrected_list = [] @@ -339,7 +359,7 @@ function! ale#fix#Fix(buffer, fixing_flag, ...) abort endif try - let l:callback_list = s:GetCallbacks(a:buffer, a:000) + let l:callback_list = s:GetCallbacks(a:buffer, a:fixing_flag, a:000) catch /E700\|BADNAME/ let l:function_name = join(split(split(v:exception, ':')[3])) let l:echo_message = printf( diff --git a/autoload/ale/fix/registry.vim b/autoload/ale/fix/registry.vim index 430dc7db..4d28272a 100644 --- a/autoload/ale/fix/registry.vim +++ b/autoload/ale/fix/registry.vim @@ -290,6 +290,11 @@ let s:default_registry = { \ 'suggested_filetypes': ['kt'], \ 'description': 'Fix Kotlin files with ktlint.', \ }, +\ 'styler': { +\ 'function': 'ale#fixers#styler#Fix', +\ 'suggested_filetypes': ['r'], +\ 'description': 'Fix R files with styler.', +\ }, \ 'latexindent': { \ 'function': 'ale#fixers#latexindent#Fix', \ 'suggested_filetypes': ['tex'], diff --git a/autoload/ale/fixers/styler.vim b/autoload/ale/fixers/styler.vim new file mode 100644 index 00000000..7ff3275c --- /dev/null +++ b/autoload/ale/fixers/styler.vim @@ -0,0 +1,16 @@ +" Author: tvatter <thibault.vatter@gmail.com> +" Description: Fixing R files with styler. + +call ale#Set('r_styler_executable', 'Rscript') +call ale#Set('r_styler_options', 'tidyverse_style') + +function! ale#fixers#styler#Fix(buffer) abort + return { + \ 'command': 'Rscript --vanilla -e ' + \ . '"suppressPackageStartupMessages(library(styler));' + \ . 'style_file(commandArgs(TRUE), style = ' + \ . ale#Var(a:buffer, 'r_styler_options') . ')"' + \ . ' %t', + \ 'read_temporary_file': 1, + \} +endfunction diff --git a/autoload/ale/highlight.vim b/autoload/ale/highlight.vim index ae1f3e7d..3e09f26d 100644 --- a/autoload/ale/highlight.vim +++ b/autoload/ale/highlight.vim @@ -26,6 +26,41 @@ endif let s:MAX_POS_VALUES = 8 let s:MAX_COL_SIZE = 1073741824 " pow(2, 30) +" Check if we have neovim's buffer highlight API +" +" Below we define some functions' implementation conditionally if this API +" exists or not. +" +" The API itself is more ergonomic and neovim performs highlights positions +" rebases during edits so we see less stalled highlights. +let s:nvim_api = exists('*nvim_buf_add_highlight') && exists('*nvim_buf_clear_namespace') + +function! ale#highlight#HasNeovimApi() abort + return s:nvim_api +endfunction + +function! ale#highlight#nvim_buf_clear_namespace(...) abort + return call('nvim_buf_clear_namespace', a:000) +endfunction + +function! ale#highlight#nvim_buf_add_highlight(...) abort + return call('nvim_buf_add_highlight', a:000) +endfunction + +function! s:ale_nvim_highlight_id(bufnr) abort + let l:id = getbufvar(a:bufnr, 'ale_nvim_highlight_id', -1) + + if l:id is -1 + " NOTE: This will highlight nothing but will allocate new id + let l:id = ale#highlight#nvim_buf_add_highlight( + \ a:bufnr, 0, '', 0, 0, -1 + \) + call setbufvar(a:bufnr, 'ale_nvim_highlight_id', l:id) + endif + + return l:id +endfunction + function! ale#highlight#CreatePositions(line, col, end_line, end_col) abort if a:line >= a:end_line " For single lines, just return the one position. @@ -49,12 +84,90 @@ endfunction " Given a loclist for current items to highlight, remove all highlights " except these which have matching loclist item entries. + function! ale#highlight#RemoveHighlights() abort - for l:match in getmatches() - if l:match.group =~# '^ALE' - call matchdelete(l:match.id) + if ale#highlight#HasNeovimApi() + if get(b:, 'ale_nvim_highlight_id', 0) + let l:bufnr = bufnr('%') + " NOTE: 0, -1 means from 0 line till the end of buffer + call ale#highlight#nvim_buf_clear_namespace( + \ l:bufnr, + \ b:ale_nvim_highlight_id, + \ 0, -1 + \) endif - endfor + else + for l:match in getmatches() + if l:match.group =~# '^ALE' + call matchdelete(l:match.id) + endif + endfor + endif +endfunction + +function! s:highlight_line(bufnr, lnum, group) abort + if ale#highlight#HasNeovimApi() + let l:highlight_id = s:ale_nvim_highlight_id(a:bufnr) + call ale#highlight#nvim_buf_add_highlight( + \ a:bufnr, l:highlight_id, a:group, + \ a:lnum, 0, -1 + \) + else + call matchaddpos(a:group, [a:lnum]) + endif +endfunction + +function! s:highlight_range(bufnr, range, group) abort + if ale#highlight#HasNeovimApi() + let l:highlight_id = s:ale_nvim_highlight_id(a:bufnr) + " NOTE: lines and columns indicies are 0-based in nvim_buf_* API. + let l:lnum = a:range.lnum - 1 + let l:end_lnum = a:range.end_lnum - 1 + let l:col = a:range.col - 1 + let l:end_col = a:range.end_col + + if l:lnum >= l:end_lnum + " For single lines, just return the one position. + call ale#highlight#nvim_buf_add_highlight( + \ a:bufnr, l:highlight_id, a:group, + \ l:lnum, l:col, l:end_col + \) + else + " highlight first line from start till the line end + call ale#highlight#nvim_buf_add_highlight( + \ a:bufnr, l:highlight_id, a:group, + \ l:lnum, l:col, -1 + \) + + " highlight all lines between the first and last entirely + let l:cur = l:lnum + 1 + + while l:cur < l:end_lnum + call ale#highlight#nvim_buf_add_highlight( + \ a:bufnr, l:highlight_id, a:group, + \ l:cur, 0, -1 + \ ) + let l:cur += 1 + endwhile + + call ale#highlight#nvim_buf_add_highlight( + \ a:bufnr, l:highlight_id, a:group, + \ l:end_lnum, 0, l:end_col + \) + endif + else + " Set all of the positions, which are chunked into Lists which + " are as large as will be accepted by matchaddpos. + call map( + \ ale#highlight#CreatePositions( + \ a:range.lnum, + \ a:range.col, + \ a:range.end_lnum, + \ a:range.end_col + \ ), + \ 'matchaddpos(a:group, v:val)' + \) + endif endfunction function! ale#highlight#UpdateHighlights() abort @@ -79,17 +192,14 @@ function! ale#highlight#UpdateHighlights() abort let l:group = 'ALEError' endif - let l:line = l:item.lnum - let l:col = l:item.col - let l:end_line = get(l:item, 'end_lnum', l:line) - let l:end_col = get(l:item, 'end_col', l:col) + let l:range = { + \ 'lnum': l:item.lnum, + \ 'col': l:item.col, + \ 'end_lnum': get(l:item, 'end_lnum', l:item.lnum), + \ 'end_col': get(l:item, 'end_col', l:item.col) + \} - " Set all of the positions, which are chunked into Lists which - " are as large as will be accepted by matchaddpos. - call map( - \ ale#highlight#CreatePositions(l:line, l:col, l:end_line, l:end_col), - \ 'matchaddpos(l:group, v:val)' - \) + call s:highlight_range(l:item.bufnr, l:range, l:group) endfor " If highlights are enabled and signs are not enabled, we should still @@ -111,7 +221,7 @@ function! ale#highlight#UpdateHighlights() abort endif if l:available_groups[l:group] - call matchaddpos(l:group, [l:item.lnum]) + call s:highlight_line(l:item.bufnr, l:item.lnum, l:group) endif endfor endif diff --git a/autoload/ale/lsp/response.vim b/autoload/ale/lsp/response.vim index b91d875b..9ce05260 100644 --- a/autoload/ale/lsp/response.vim +++ b/autoload/ale/lsp/response.vim @@ -28,7 +28,7 @@ function! ale#lsp#response#ReadDiagnostics(response) abort for l:diagnostic in a:response.params.diagnostics let l:severity = get(l:diagnostic, 'severity', 0) let l:loclist_item = { - \ 'text': l:diagnostic.message, + \ 'text': substitute(l:diagnostic.message, '\(\r\n\|\n\|\r\)', ' ', 'g'), \ 'type': 'E', \ 'lnum': l:diagnostic.range.start.line + 1, \ 'col': l:diagnostic.range.start.character + 1, diff --git a/autoload/ale/lsp_linter.vim b/autoload/ale/lsp_linter.vim index d544916a..3a596d62 100644 --- a/autoload/ale/lsp_linter.vim +++ b/autoload/ale/lsp_linter.vim @@ -27,12 +27,13 @@ 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) + let l:info = get(g:ale_buffer_info, l:buffer, {}) - if s:ShouldIgnore(l:buffer, l:linter_name) + if empty(l:info) return endif - if l:buffer <= 0 + if s:ShouldIgnore(l:buffer, l:linter_name) return endif @@ -50,6 +51,8 @@ function! s:HandleTSServerDiagnostics(response, error_type) abort return endif + call ale#engine#MarkLinterInactive(l:info, l:linter_name) + if s:ShouldIgnore(l:buffer, l:linter_name) return endif @@ -376,6 +379,10 @@ function! s:CheckWithLSP(linter, details) abort if a:linter.lsp is# 'tsserver' let l:message = ale#lsp#tsserver_message#Geterr(l:buffer) let l:notified = ale#lsp#Send(l:id, l:message) != 0 + + if l:notified + call ale#engine#MarkLinterActive(l:info, a:linter) + endif else let l:notified = ale#lsp#NotifyForChanges(l:id, l:buffer) endif @@ -386,10 +393,6 @@ function! s:CheckWithLSP(linter, details) abort let l:save_message = ale#lsp#message#DidSave(l:buffer) let l:notified = ale#lsp#Send(l:id, l:save_message) != 0 endif - - if l:notified - call ale#engine#MarkLinterActive(l:info, a:linter) - endif endfunction function! ale#lsp_linter#CheckWithLSP(buffer, linter) abort diff --git a/autoload/ale/sign.vim b/autoload/ale/sign.vim index 933fc055..7395b0e2 100644 --- a/autoload/ale/sign.vim +++ b/autoload/ale/sign.vim @@ -66,7 +66,7 @@ endif " Spaces and backslashes need to be escaped for signs. function! s:EscapeSignText(sign_text) abort - return substitute(a:sign_text, '\\\| ', '\\\0', 'g') + return substitute(substitute(a:sign_text, ' *$', '', ''), '\\\| ', '\\\0', 'g') endfunction " Signs show up on the left for error markers. diff --git a/autoload/ale/util.vim b/autoload/ale/util.vim index e57307e4..e7563608 100644 --- a/autoload/ale/util.vim +++ b/autoload/ale/util.vim @@ -422,7 +422,7 @@ function! ale#util#Writefile(buffer, lines, filename) abort \ ? map(copy(a:lines), 'substitute(v:val, ''\r*$'', ''\r'', '''')') \ : a:lines - call writefile(l:corrected_lines, a:filename) " no-custom-checks + call writefile(l:corrected_lines, a:filename, 'S') " no-custom-checks endfunction if !exists('s:patial_timers') diff --git a/autoload/ale/virtualtext.vim b/autoload/ale/virtualtext.vim index 532427fb..d7c5360e 100644 --- a/autoload/ale/virtualtext.vim +++ b/autoload/ale/virtualtext.vim @@ -81,7 +81,7 @@ function! ale#virtualtext#ShowCursorWarning(...) abort call ale#virtualtext#Clear() if !empty(l:loc) - let l:msg = get(l:loc, 'detail', l:loc.text) + let l:msg = l:loc.text let l:hl_group = 'ALEVirtualTextInfo' let l:type = get(l:loc, 'type', 'E') |