diff --git a/autoload/ale/code_action.vim b/autoload/ale/code_action.vim index fe6b175f..506107f4 100644 --- a/autoload/ale/code_action.vim +++ b/autoload/ale/code_action.vim @@ -263,3 +263,105 @@ function! ale#code_action#BuildChangesList(changes_map) abort return l:changes endfunction + +function! s:EscapeMenuName(text) abort + return substitute(a:text, '\\\| \|\.\|&', '\\\0', 'g') +endfunction + +function! s:UpdateMenu(data, menu_items) abort + silent! aunmenu PopUp.Refactor\.\.\. + + if empty(a:data) + return + endif + + for [l:type, l:item] in a:menu_items + let l:name = l:type is# 'tsserver' ? l:item.name : l:item.title + let l:func_name = l:type is# 'tsserver' + \ ? 'ale#codefix#ApplyTSServerCodeAction' + \ : 'ale#codefix#ApplyLSPCodeAction' + + execute printf( + \ 'anoremenu PopUp.&Refactor\.\.\..%s' + \ . ' :call %s(%s, %s)', + \ s:EscapeMenuName(l:name), + \ l:func_name, + \ string(a:data), + \ string(l:item), + \) + endfor + + if empty(a:menu_items) + silent! anoremenu PopUp.Refactor\.\.\..(None) :silent + endif +endfunction + +function! s:GetCodeActions(linter, options) abort + let l:buffer = bufnr('') + let [l:line, l:column] = getpos('.')[1:2] + let l:column = min([l:column, len(getline(l:line))]) + + let l:location = { + \ 'buffer': l:buffer, + \ 'line': l:line, + \ 'column': l:column, + \ 'end_line': l:line, + \ 'end_column': l:column, + \} + let l:Callback = function('s:OnReady', [l:location, a:options]) + call ale#lsp_linter#StartLSP(l:buffer, a:linter, l:Callback) +endfunction + +function! ale#code_action#GetCodeActions(options) abort + silent! aunmenu PopUp.Rename + silent! aunmenu PopUp.Refactor\.\.\. + + " Only display the menu items if there's an LSP server. + let l:has_lsp = 0 + + for l:linter in ale#linter#Get(&filetype) + if !empty(l:linter.lsp) + let l:has_lsp = 1 + + break + endif + endfor + + if l:has_lsp + if !empty(expand('')) + silent! anoremenu PopUp.Rename :ALERename + endif + + silent! anoremenu PopUp.Refactor\.\.\..(None) :silent + + call ale#codefix#Execute( + \ mode() is# 'v' || mode() is# "\", + \ function('s:UpdateMenu') + \) + endif +endfunction + +function! s:Setup(enabled) abort + augroup ALECodeActionsGroup + autocmd! + + if a:enabled + autocmd MenuPopup * :call ale#code_action#GetCodeActions({}) + endif + augroup END + + if !a:enabled + silent! augroup! ALECodeActionsGroup + + silent! aunmenu PopUp.Rename + silent! aunmenu PopUp.Refactor\.\.\. + endif +endfunction + +function! ale#code_action#EnablePopUpMenu() abort + call s:Setup(1) +endfunction + +function! ale#code_action#DisablePopUpMenu() abort + call s:Setup(0) +endfunction diff --git a/autoload/ale/codefix.vim b/autoload/ale/codefix.vim index b58f5e4b..3120e7cb 100644 --- a/autoload/ale/codefix.vim +++ b/autoload/ale/codefix.vim @@ -1,5 +1,5 @@ " Author: Dalius Dobravolskas -" Description: Code Fix support for tsserver +" Description: Code Fix support for tsserver and LSP servers let s:codefix_map = {} @@ -21,23 +21,65 @@ function! s:message(message) abort call ale#util#Execute('echom ' . string(a:message)) endfunction +function! ale#codefix#ApplyTSServerCodeAction(data, item) abort + if has_key(a:item, 'changes') + let l:changes = a:item.changes + + call ale#code_action#HandleCodeAction( + \ { + \ 'description': 'codefix', + \ 'changes': l:changes, + \ }, + \ {}, + \) + else + let l:message = ale#lsp#tsserver_message#GetEditsForRefactor( + \ a:data.buffer, + \ a:data.line, + \ a:data.column, + \ a:data.end_line, + \ a:data.end_column, + \ a:item.id[0], + \ a:item.id[1], + \) + + let l:request_id = ale#lsp#Send(a:data.connection_id, l:message) + + let s:codefix_map[l:request_id] = a:data + endif +endfunction + function! ale#codefix#HandleTSServerResponse(conn_id, response) abort if !has_key(a:response, 'request_seq') \ || !has_key(s:codefix_map, a:response.request_seq) return endif - let l:location = remove(s:codefix_map, a:response.request_seq) + let l:data = remove(s:codefix_map, a:response.request_seq) + let l:MenuCallback = get(l:data, 'menu_callback', v:null) if get(a:response, 'command', '') is# 'getCodeFixes' if get(a:response, 'success', v:false) is v:false + \&& l:MenuCallback is v:null let l:message = get(a:response, 'message', 'unknown') call s:message('Error while getting code fixes. Reason: ' . l:message) return endif - if len(a:response.body) == 0 + let l:result = get(a:response, 'body', []) + call filter(l:result, 'has_key(v:val, ''changes'')') + + if l:MenuCallback isnot v:null + call l:MenuCallback( + \ l:data, + \ map(copy(l:result), '[''tsserver'', v:val]') + \) + + return + endif + + if len(l:result) == 0 call s:message('No code fixes available.') return @@ -45,14 +87,15 @@ function! ale#codefix#HandleTSServerResponse(conn_id, response) abort let l:code_fix_to_apply = 0 - if len(a:response.body) == 1 + if len(l:result) == 1 let l:code_fix_to_apply = 1 else let l:codefix_no = 1 let l:codefixstring = "Code Fixes:\n" - for l:codefix in a:response.body - let l:codefixstring .= l:codefix_no . ') ' . l:codefix.description . "\n" + for l:codefix in l:result + let l:codefixstring .= l:codefix_no . ') ' + \ . l:codefix.description . "\n" let l:codefix_no += 1 endfor @@ -66,21 +109,22 @@ function! ale#codefix#HandleTSServerResponse(conn_id, response) abort endif endif - let l:changes = a:response.body[l:code_fix_to_apply - 1].changes - - call ale#code_action#HandleCodeAction({ - \ 'description': 'codefix', - \ 'changes': l:changes, - \}, {}) + call ale#codefix#ApplyTSServerCodeAction( + \ l:data, + \ l:result[l:code_fix_to_apply - 1], + \) elseif get(a:response, 'command', '') is# 'getApplicableRefactors' if get(a:response, 'success', v:false) is v:false + \&& l:MenuCallback is v:null let l:message = get(a:response, 'message', 'unknown') call s:message('Error while getting applicable refactors. Reason: ' . l:message) return endif - if len(a:response.body) == 0 + let l:result = get(a:response, 'body', []) + + if len(l:result) == 0 call s:message('No applicable refactors available.') return @@ -88,7 +132,7 @@ function! ale#codefix#HandleTSServerResponse(conn_id, response) abort let l:refactors = [] - for l:item in a:response.body + for l:item in l:result for l:action in l:item.actions call add(l:refactors, { \ 'name': l:action.description, @@ -97,11 +141,21 @@ function! ale#codefix#HandleTSServerResponse(conn_id, response) abort endfor endfor + if l:MenuCallback isnot v:null + call l:MenuCallback( + \ l:data, + \ map(copy(l:refactors), '[''tsserver'', v:val]') + \) + + return + endif + let l:refactor_no = 1 let l:refactorstring = "Applicable refactors:\n" for l:refactor in l:refactors - let l:refactorstring .= l:refactor_no . ') ' . l:refactor.name . "\n" + let l:refactorstring .= l:refactor_no . ') ' + \ . l:refactor.name . "\n" let l:refactor_no += 1 endfor @@ -116,19 +170,10 @@ function! ale#codefix#HandleTSServerResponse(conn_id, response) abort let l:id = l:refactors[l:refactor_to_apply - 1].id - let l:message = ale#lsp#tsserver_message#GetEditsForRefactor( - \ l:location.buffer, - \ l:location.line, - \ l:location.column, - \ l:location.end_line, - \ l:location.end_column, - \ l:id[0], - \ l:id[1], + call ale#codefix#ApplyTSServerCodeAction( + \ l:data, + \ l:refactors[l:refactor_to_apply - 1], \) - - let l:request_id = ale#lsp#Send(l:location.connection_id, l:message) - - let s:codefix_map[l:request_id] = l:location elseif get(a:response, 'command', '') is# 'getEditsForRefactor' if get(a:response, 'success', v:false) is v:false let l:message = get(a:response, 'message', 'unknown') @@ -137,10 +182,48 @@ function! ale#codefix#HandleTSServerResponse(conn_id, response) abort return endif - call ale#code_action#HandleCodeAction({ - \ 'description': 'editsForRefactor', - \ 'changes': a:response.body.edits, - \}, {}) + call ale#code_action#HandleCodeAction( + \ { + \ 'description': 'editsForRefactor', + \ 'changes': a:response.body.edits, + \ }, + \ {}, + \) + endif +endfunction + +function! ale#codefix#ApplyLSPCodeAction(data, item) abort + if has_key(a:item, 'command') + \&& type(a:item.command) == v:t_dict + let l:command = a:item.command + let l:message = ale#lsp#message#ExecuteCommand( + \ l:command.command, + \ l:command.arguments, + \) + + let l:request_id = ale#lsp#Send(a:data.connection_id, l:message) + elseif has_key(a:item, 'edit') || has_key(a:item, 'arguments') + if has_key(a:item, 'edit') + let l:topass = a:item.edit + else + let l:topass = a:item.arguments[0] + endif + + let l:changes_map = ale#code_action#GetChanges(l:topass) + + if empty(l:changes_map) + return + endif + + let l:changes = ale#code_action#BuildChangesList(l:changes_map) + + call ale#code_action#HandleCodeAction( + \ { + \ 'description': 'codeaction', + \ 'changes': l:changes, + \ }, + \ {}, + \) endif endfunction @@ -158,17 +241,32 @@ function! ale#codefix#HandleLSPResponse(conn_id, response) abort let l:changes = ale#code_action#BuildChangesList(l:changes_map) - call ale#code_action#HandleCodeAction({ - \ 'description': 'applyEdit', - \ 'changes': l:changes, - \}, {}) + call ale#code_action#HandleCodeAction( + \ { + \ 'description': 'applyEdit', + \ 'changes': l:changes, + \ }, + \ {} + \) elseif has_key(a:response, 'id') \&& has_key(s:codefix_map, a:response.id) - let l:location = remove(s:codefix_map, a:response.id) + let l:data = remove(s:codefix_map, a:response.id) + let l:MenuCallback = get(l:data, 'menu_callback', v:null) - if !has_key(a:response, 'result') - \ || type(a:response.result) != v:t_list - \ || len(a:response.result) == 0 + let l:result = get(a:response, 'result') + + if type(l:result) != v:t_list + let l:result = [] + endif + + " Send the results to the menu callback, if set. + if l:MenuCallback isnot v:null + call l:MenuCallback(map(copy(l:result), '[''lsp'', v:val]')) + + return + endif + + if len(l:result) == 0 call s:message('No code actions received from server') return @@ -177,8 +275,9 @@ function! ale#codefix#HandleLSPResponse(conn_id, response) abort let l:codeaction_no = 1 let l:codeactionstring = "Code Fixes:\n" - for l:codeaction in a:response.result - let l:codeactionstring .= l:codeaction_no . ') ' . l:codeaction.title . "\n" + for l:codeaction in l:result + let l:codeactionstring .= l:codeaction_no . ') ' + \ . l:codeaction.title . "\n" let l:codeaction_no += 1 endfor @@ -191,42 +290,44 @@ function! ale#codefix#HandleLSPResponse(conn_id, response) abort return endif - let l:item = a:response.result[l:codeaction_to_apply - 1] + let l:item = l:result[l:codeaction_to_apply - 1] - if has_key(l:item, 'command') - \ && type(l:item.command) == v:t_dict - let l:command = l:item.command - let l:message = ale#lsp#message#ExecuteCommand( - \ l:command.command, - \ l:command.arguments, - \) - - let l:request_id = ale#lsp#Send(l:location.connection_id, l:message) - elseif has_key(l:item, 'edit') || has_key(l:item, 'arguments') - if has_key(l:item, 'edit') - let l:topass = l:item.edit - else - let l:topass = l:item.arguments[0] - endif - - let l:changes_map = ale#code_action#GetChanges(l:topass) - - if empty(l:changes_map) - return - endif - - let l:changes = ale#code_action#BuildChangesList(l:changes_map) - - call ale#code_action#HandleCodeAction({ - \ 'description': 'codeaction', - \ 'changes': l:changes, - \}, {}) - endif + call ale#codefix#ApplyLSPCodeAction(l:data, l:item) endif endfunction +function! s:FindError(buffer, line, column, end_line, end_column) abort + let l:nearest_error = v:null -function! s:OnReady(line, column, end_line, end_column, linter, lsp_details) abort + if a:line == a:end_line + \&& a:column == a:end_column + \&& has_key(g:ale_buffer_info, a:buffer) + let l:nearest_error_diff = -1 + + for l:error in get(g:ale_buffer_info[a:buffer], 'loclist', []) + if has_key(l:error, 'code') && l:error.lnum == a:line + let l:diff = abs(l:error.col - a:column) + + if l:nearest_error_diff == -1 || l:diff < l:nearest_error_diff + let l:nearest_error_diff = l:diff + let l:nearest_error = l:error + endif + endif + endfor + endif + + return l:nearest_error +endfunction + +function! s:OnReady( +\ line, +\ column, +\ end_line, +\ end_column, +\ MenuCallback, +\ linter, +\ lsp_details, +\) abort let l:id = a:lsp_details.connection_id if !ale#lsp#HasCapability(l:id, 'code_actions') @@ -236,32 +337,17 @@ function! s:OnReady(line, column, end_line, end_column, linter, lsp_details) abo let l:buffer = a:lsp_details.buffer if a:linter.lsp is# 'tsserver' - if a:line == a:end_line && a:column == a:end_column - if !has_key(g:ale_buffer_info, l:buffer) - return - endif - - let l:nearest_error = v:null - let l:nearest_error_diff = -1 - - for l:error in get(g:ale_buffer_info[l:buffer], 'loclist', []) - if has_key(l:error, 'code') && l:error.lnum == a:line - let l:diff = abs(l:error.col - a:column) - - if l:nearest_error_diff == -1 || l:diff < l:nearest_error_diff - let l:nearest_error_diff = l:diff - let l:nearest_error = l:error.code - endif - endif - endfor + let l:nearest_error = + \ s:FindError(l:buffer, a:line, a:column, a:end_line, a:end_column) + if l:nearest_error isnot v:null let l:message = ale#lsp#tsserver_message#GetCodeFixes( \ l:buffer, \ a:line, \ a:column, \ a:line, \ a:column, - \ [l:nearest_error], + \ [l:nearest_error.code], \) else let l:message = ale#lsp#tsserver_message#GetApplicableRefactors( @@ -277,56 +363,37 @@ function! s:OnReady(line, column, end_line, end_column, linter, lsp_details) abo " completions won't know what text is nearby. call ale#lsp#NotifyForChanges(l:id, l:buffer) - if a:line == a:end_line && a:column == a:end_column - if !has_key(g:ale_buffer_info, l:buffer) - return - endif + let l:diagnostics = [] + let l:nearest_error = + \ s:FindError(l:buffer, a:line, a:column, a:end_line, a:end_column) - let l:nearest_error = v:null - let l:nearest_error_diff = -1 - - for l:error in get(g:ale_buffer_info[l:buffer], 'loclist', []) - if has_key(l:error, 'code') && l:error.lnum == a:line - let l:diff = abs(l:error.col - a:column) - - if l:nearest_error_diff == -1 || l:diff < l:nearest_error_diff - let l:nearest_error_diff = l:diff - let l:nearest_error = l:error - endif - endif - endfor - - let l:diagnostics = [] - - if l:nearest_error isnot v:null - let l:diagnostics = [{ - \ 'code': l:nearest_error.code, - \ 'message': l:nearest_error.text, - \ 'range': { - \ 'start': { 'line': l:nearest_error.lnum - 1, 'character': l:nearest_error.col - 1 }, - \ 'end': { 'line': l:nearest_error.end_lnum - 1, 'character': l:nearest_error.end_col - 1 } - \} - \}] - endif - - let l:message = ale#lsp#message#CodeAction( - \ l:buffer, - \ a:line, - \ a:column, - \ a:end_line, - \ a:end_column, - \ l:diagnostics, - \) - else - let l:message = ale#lsp#message#CodeAction( - \ l:buffer, - \ a:line, - \ a:column, - \ a:end_line, - \ a:end_column, - \ [], - \) + if l:nearest_error isnot v:null + let l:diagnostics = [ + \ { + \ 'code': l:nearest_error.code, + \ 'message': l:nearest_error.text, + \ 'range': { + \ 'start': { + \ 'line': l:nearest_error.lnum - 1, + \ 'character': l:nearest_error.col - 1, + \ }, + \ 'end': { + \ 'line': l:nearest_error.end_lnum - 1, + \ 'character': l:nearest_error.end_col - 1, + \ }, + \ }, + \ }, + \] endif + + let l:message = ale#lsp#message#CodeAction( + \ l:buffer, + \ a:line, + \ a:column, + \ a:end_line, + \ a:end_column, + \ l:diagnostics, + \) endif let l:Callback = a:linter.lsp is# 'tsserver' @@ -338,22 +405,40 @@ function! s:OnReady(line, column, end_line, end_column, linter, lsp_details) abo let l:request_id = ale#lsp#Send(l:id, l:message) let s:codefix_map[l:request_id] = { - \ 'connection_id': l:id, - \ 'buffer': l:buffer, - \ 'line': a:line, - \ 'column': a:column, - \ 'end_line': a:end_line, - \ 'end_column': a:end_column, + \ 'connection_id': l:id, + \ 'buffer': l:buffer, + \ 'line': a:line, + \ 'column': a:column, + \ 'end_line': a:end_line, + \ 'end_column': a:end_column, + \ 'menu_callback': a:MenuCallback, \} endfunction -function! s:ExecuteGetCodeFix(linter, range) abort +function! s:ExecuteGetCodeFix(linter, range, MenuCallback) abort let l:buffer = bufnr('') if a:range == 0 let [l:line, l:column] = getpos('.')[1:2] let l:end_line = l:line let l:end_column = l:column + + " Expand the range to cover the current word, if there is one. + let l:cword = expand('') + + if !empty(l:cword) + let l:search_pos = searchpos('\V' . l:cword, 'bn', l:line) + + if l:search_pos != [0, 0] + let l:column = l:search_pos[1] + let l:end_column = l:column + len(l:cword) - 1 + endif + endif + elseif mode() is# 'v' || mode() is# "\" + " You need to get the start and end in a different way when you're in + " visual mode. + let [l:line, l:column] = getpos('v')[1:2] + let [l:end_line, l:end_column] = getpos('.')[1:2] else let [l:line, l:column] = getpos("'<")[1:2] let [l:end_line, l:end_column] = getpos("'>")[1:2] @@ -363,11 +448,18 @@ function! s:ExecuteGetCodeFix(linter, range) abort let l:end_column = min([l:end_column, len(getline(l:end_line))]) let l:Callback = function( - \ 's:OnReady', [l:line, l:column, l:end_line, l:end_column]) + \ 's:OnReady', [l:line, l:column, l:end_line, l:end_column, a:MenuCallback] + \) + call ale#lsp_linter#StartLSP(l:buffer, a:linter, l:Callback) endfunction -function! ale#codefix#Execute(range) abort +function! ale#codefix#Execute(range, ...) abort + if a:0 > 1 + throw 'Too many arguments' + endif + + let l:MenuCallback = get(a:000, 0, v:null) let l:lsp_linters = [] for l:linter in ale#linter#Get(&filetype) @@ -377,12 +469,16 @@ function! ale#codefix#Execute(range) abort endfor if empty(l:lsp_linters) - call s:message('No active LSPs') + if l:MenuCallback is v:null + call s:message('No active LSPs') + else + call l:MenuCallback({}, []) + endif return endif for l:lsp_linter in l:lsp_linters - call s:ExecuteGetCodeFix(l:lsp_linter, a:range) + call s:ExecuteGetCodeFix(l:lsp_linter, a:range, l:MenuCallback) endfor endfunction diff --git a/doc/ale.txt b/doc/ale.txt index 013b39f9..20baf355 100644 --- a/doc/ale.txt +++ b/doc/ale.txt @@ -673,13 +673,31 @@ for a full list of options. ------------------------------------------------------------------------------- 5.7 Refactoring: Rename, Actions *ale-refactor* -ALE supports renaming symbols in symbols in code such as variables or class -names with the |ALERename| command. +ALE supports renaming symbols in code such as variables or class names with +the |ALERename| command. |ALECodeAction| will execute actions on the cursor or applied to a visual range selection, such as automatically fixing errors. +Actions will appear in the right click mouse menu by default for GUI versions +of Vim, unless disabled by setting |g:ale_popup_menu_enabled| to `0`. +Make sure to set your Vim to move the cursor position whenever you right +click, and enable the mouse menu: > + + set mouse=a + set mousemodel=popup_setpos +< +You may wish to remove some other menu items you don't want to see: > + + silent! aunmenu PopUp.Select\ Word + silent! aunmenu PopUp.Select\ Sentence + silent! aunmenu PopUp.Select\ Paragraph + silent! aunmenu PopUp.Select\ Line + silent! aunmenu PopUp.Select\ Block + silent! aunmenu PopUp.Select\ Blockwise + silent! aunmenu PopUp.Select\ All +< =============================================================================== 6. Global Options *ale-options* @@ -1784,6 +1802,19 @@ g:ale_pattern_options_enabled *g:ale_pattern_options_enabled* will not set buffer variables per |g:ale_pattern_options|. +g:ale_popup_menu_enabled *g:ale_popup_menu_enabled* + + Type: |Number| + Default: `has('gui')` + + When this option is set to `1`, ALE will show code actions and rename + capabilities in the right click mouse menu when there's a LSP server or + tsserver available. See |ale-refactor|. + + This setting must be set to `1` before ALE is loaded for this behavior + to be enabled. See |ale-lint-settings-on-startup|. + + g:ale_rename_tsserver_find_in_comments *g:ale_rename_tsserver_find_in_comments* Type: |Number| diff --git a/plugin/ale.vim b/plugin/ale.vim index c5c1d3d3..2398956e 100644 --- a/plugin/ale.vim +++ b/plugin/ale.vim @@ -158,6 +158,9 @@ let g:ale_python_auto_pipenv = get(g:, 'ale_python_auto_pipenv', 0) " This variable can be overridden to set the GO111MODULE environment variable. let g:ale_go_go111module = get(g:, 'ale_go_go111module', '') +" If 1, enable a popup menu for commands. +let g:ale_popup_menu_enabled = get(g:, 'ale_popup_menu_enabled', has('gui')) + if g:ale_set_balloons call ale#balloon#Enable() endif @@ -166,6 +169,10 @@ if g:ale_completion_enabled call ale#completion#Enable() endif +if g:ale_popup_menu_enabled + call ale#code_action#EnablePopUpMenu() +endif + " Define commands for moving through warnings and errors. command! -bar -nargs=* ALEPrevious \ :call ale#loclist_jumping#WrapJump('before', ) diff --git a/test/test_codefix.vader b/test/test_codefix.vader index 63275d7f..deb97256 100644 --- a/test/test_codefix.vader +++ b/test/test_codefix.vader @@ -105,11 +105,9 @@ Execute(Failed codefix responses should be handled correctly): \) AssertEqual g:handle_code_action_called, 0 - - Given typescript(Some typescript file): foo - somelongerline + somelongerline () bazxyzxyzxyz Execute(getCodeFixes from tsserver should be handled): @@ -283,7 +281,7 @@ Execute(tsserver codefix requests should be sent): runtime ale_linters/typescript/tsserver.vim let g:ale_buffer_info = {bufnr(''): {'loclist': [{'lnum': 2, 'col': 5, 'code': 2304}]}} - call setpos('.', [bufnr(''), 2, 5, 0]) + call setpos('.', [bufnr(''), 2, 16, 0]) " ALECodeAction call ale#codefix#Execute(0) @@ -303,9 +301,9 @@ Execute(tsserver codefix requests should be sent): \ ale#lsp#tsserver_message#Change(bufnr('')), \ [0, 'ts@getCodeFixes', { \ 'startLine': 2, - \ 'startOffset': 5, + \ 'startOffset': 16, \ 'endLine': 2, - \ 'endOffset': 6, + \ 'endOffset': 17, \ 'file': expand('%:p'), \ 'errorCodes': [2304], \ }] @@ -316,8 +314,8 @@ Execute(tsserver codefix requests should be sent only for error with code): call ale#linter#Reset() runtime ale_linters/typescript/tsserver.vim - let g:ale_buffer_info = {bufnr(''): {'loclist': [{'lnum': 2, 'col': 5}, {'lnum': 2, 'col': 5, 'code': 2304}]}} - call setpos('.', [bufnr(''), 2, 5, 0]) + let g:ale_buffer_info = {bufnr(''): {'loclist': [{'lnum': 2, 'col': 16}, {'lnum': 2, 'col': 16, 'code': 2304}]}} + call setpos('.', [bufnr(''), 2, 16, 0]) " ALECodeAction call ale#codefix#Execute(0) @@ -337,9 +335,9 @@ Execute(tsserver codefix requests should be sent only for error with code): \ ale#lsp#tsserver_message#Change(bufnr('')), \ [0, 'ts@getCodeFixes', { \ 'startLine': 2, - \ 'startOffset': 5, + \ 'startOffset': 16, \ 'endLine': 2, - \ 'endOffset': 6, + \ 'endOffset': 17, \ 'file': expand('%:p'), \ 'errorCodes': [2304], \ }] @@ -424,43 +422,6 @@ Execute(getEditsForRefactor should print error on failure): AssertEqual ['echom ''Error while getting edits for refactor. Reason: oops'''], g:expr_list -" TODO: I can't figure out how to run ALECodeAction on range -" in test function. Therefore I can't write properly working -" test. If somebody knows how to do that help is appreciated. -" -" Execute(tsserver getApplicableRefactors requests should be sent): -" call ale#linter#Reset() -" -" runtime ale_linters/typescript/tsserver.vim -" let g:ale_buffer_info = {bufnr(''): {'loclist': []}} -" call setpos('.', [bufnr(''), 2, 5, 0]) -" normal "v$" -" -" execute "ALECodeAction" -" -" " We shouldn't register the callback yet. -" AssertEqual '''''', string(g:Callback) -" -" AssertEqual type(function('type')), type(g:InitCallback) -" call g:InitCallback() -" -" AssertEqual 'code_actions', g:capability_checked -" AssertEqual -" \ 'function(''ale#codefix#HandleTSServerResponse'')', -" \ string(g:Callback) -" AssertEqual -" \ [ -" \ ale#lsp#tsserver_message#Change(bufnr('')), -" \ [0, 'ts@getApplicableRefactors', { -" \ 'startLine': 2, -" \ 'startOffset': 5, -" \ 'endLine': 2, -" \ 'endOffset': 15, -" \ 'file': expand('%:p'), -" \ }] -" \ ], -" \ g:message_list - Execute(Failed LSP responses should be handled correctly): call ale#codefix#HandleLSPResponse( \ 1, @@ -545,14 +506,6 @@ Execute(LSP code action requests should be sent): \ string(g:Callback) AssertEqual \ [ - \ [1, 'workspace/didChangeConfiguration', {'settings': {'python': {}}}], - \ [1, 'textDocument/didChange', { - \ 'contentChanges': [{'text': "def main():\n a = 1\n b = a + 2\n"}], - \ 'textDocument': { - \ 'uri': ale#path#ToURI(expand('%:p')), - \ 'version': g:ale_lsp_next_version_id - 1, - \ }, - \ }], \ [0, 'textDocument/codeAction', { \ 'context': { \ 'diagnostics': [{'range': {'end': {'character': 5, 'line': 1}, 'start': {'character': 4, 'line': 1}}, 'code': 2304, 'message': 'oops'}] @@ -561,7 +514,7 @@ Execute(LSP code action requests should be sent): \ 'textDocument': {'uri': ale#path#ToURI(expand('%:p'))} \ }] \ ], - \ g:message_list + \ g:message_list[-1:] Execute(LSP code action requests should be sent only for error with code): call ale#linter#Reset() @@ -585,14 +538,6 @@ Execute(LSP code action requests should be sent only for error with code): \ string(g:Callback) AssertEqual \ [ - \ [1, 'workspace/didChangeConfiguration', {'settings': {'python': {}}}], - \ [1, 'textDocument/didChange', { - \ 'contentChanges': [{'text': "def main():\n a = 1\n b = a + 2\n"}], - \ 'textDocument': { - \ 'uri': ale#path#ToURI(expand('%:p')), - \ 'version': g:ale_lsp_next_version_id - 1, - \ }, - \ }], \ [0, 'textDocument/codeAction', { \ 'context': { \ 'diagnostics': [{'range': {'end': {'character': 5, 'line': 1}, 'start': {'character': 4, 'line': 1}}, 'code': 2304, 'message': 'oops'}] @@ -601,4 +546,4 @@ Execute(LSP code action requests should be sent only for error with code): \ 'textDocument': {'uri': ale#path#ToURI(expand('%:p'))} \ }] \ ], - \ g:message_list + \ g:message_list[-1:]