From 456378cb53dbf38ff0077b8f41894bbdc7c9671e Mon Sep 17 00:00:00 2001 From: w0rp Date: Sun, 20 Aug 2017 15:59:18 +0100 Subject: [PATCH] #653 - Jump to the position which Vim does not jump to for moving from quickfix/loclist items to other buffers --- autoload/ale/events.vim | 30 +++++++++++++ ftplugin/qf.vim | 4 ++ test/test_ale_init_au_groups.vader | 24 ++++++++++- ...t_list_modification_error_cancelling.vader | 42 +++++++++++++++++++ 4 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 ftplugin/qf.vim diff --git a/autoload/ale/events.vim b/autoload/ale/events.vim index c84954c..2ee7f86 100644 --- a/autoload/ale/events.vim +++ b/autoload/ale/events.vim @@ -60,10 +60,40 @@ function! s:HitReturn(...) abort if get(split(l:output, "\n"), -1, '') =~# '^E92[456]' call ale#util#FeedKeys("\", 'n') + + " If we hit one of the errors and cleared it, then Vim didn't + " move to the position we wanted. Change the position to the one + " the user selected. + if exists('g:ale_list_window_selection') + let l:pos = getcurpos() + let [l:pos[1], l:pos[2]] = g:ale_list_window_selection + call setpos('.', l:pos) + endif endif endif + + " Always clear the last selection when trying to cancel the errors above + " here. This prevents us from remembering invalid positions. + unlet! g:ale_list_window_selection endfunction function! ale#events#BufWinLeave() abort call timer_start(0, function('s:HitReturn')) endfunction + +" Grab the position for a problem from the loclist or quickfix windows +" when moving through selections. This selection will be remembered and +" set as the position when jumping to an error in another file. +function! ale#events#ParseLoclistWindowItemPosition() abort + " Parses lines like + " test.txt|72 col 5 error| ... + " test.txt|72| ... + let l:match = matchlist(getline('.'), '\v^[^|]+\|(\d+)( [^ ]+ )?(\d*)') + + if !empty(l:match) + let g:ale_list_window_selection = [ + \ l:match[1] + 0, + \ max([l:match[3] + 0, 1]), + \] + endif +endfunction diff --git a/ftplugin/qf.vim b/ftplugin/qf.vim new file mode 100644 index 0000000..18e2c81 --- /dev/null +++ b/ftplugin/qf.vim @@ -0,0 +1,4 @@ +augroup ALEQuickfixCursorMovedEvent + autocmd! * + autocmd CursorMoved call ale#events#ParseLoclistWindowItemPosition() +augroup END diff --git a/test/test_ale_init_au_groups.vader b/test/test_ale_init_au_groups.vader index 109f84a..3606402 100644 --- a/test/test_ale_init_au_groups.vader +++ b/test/test_ale_init_au_groups.vader @@ -21,8 +21,14 @@ Before: let l:header = split(l:line)[1] let l:header = get(l:event_name_corrections, l:header, l:header) elseif !empty(l:header) - call add(l:matches, join(split(l:header . l:line))) - let l:header = '' + " There's an extra line for buffer events, and we should only look + " for the one matching the current buffer. + if l:line =~# '' + let l:header .= ' ' + else + call add(l:matches, join(split(l:header . l:line))) + let l:header = '' + endif endif endfor @@ -54,6 +60,11 @@ After: call ALEInitAuGroups() + " Clean up the quickfix group. + augroup ALEQuickfixCursorMovedEvent + autocmd! * + augroup END + Execute (g:ale_lint_on_text_changed = 0 should bind no events): let g:ale_lint_on_text_changed = 0 @@ -211,3 +222,12 @@ Execute(Disabling completion should remove autocmd events correctly): AssertEqual [], CheckAutocmd('ALECompletionGroup') AssertEqual 0, g:ale_completion_enabled + +Execute(The cursor events should be set up for the quickfix list): + runtime! ftplugin/qf.vim + + AssertEqual + \ [ + \ 'CursorMoved call ale#events#ParseLoclistWindowItemPosition()', + \ ], + \ CheckAutocmd('ALEQuickfixCursorMovedEvent') diff --git a/test/test_list_modification_error_cancelling.vader b/test/test_list_modification_error_cancelling.vader index 0644962..e4aa3af 100644 --- a/test/test_list_modification_error_cancelling.vader +++ b/test/test_list_modification_error_cancelling.vader @@ -26,6 +26,7 @@ Before: After: unlet! b:fake_mode unlet! b:feedkeys_calls + unlet! g:ale_list_window_selection delfunction CheckError @@ -52,3 +53,44 @@ Execute(The BufWinLeave event function should ignore other errors): Execute(The BufWinLeave event function not send keys for other modes): call CheckError('n', 'E924', []) + +Execute(The last window selection should always be cleared by the timer): + let g:ale_list_window_selection = [347, 2] + + " The message and mode shouldn't matter, we should still clear the variable. + echom 'xyz' + let b:fake_mode = 'n' + call ale#events#BufWinLeave() + sleep 1ms + + Assert !has_key(g:, 'ale_list_window_selection') + +Given qf(A quickfix list with some errors): + test.txt|23 col 9 warning| Some warning + test.txt|72 col 25 error| Some column error + test.txt|93 error| Some line error + +Execute(Line and column numbers should be parsed by the quickfix event function): + call setpos('.', [bufnr(''), 2, 1, 0]) + call ale#events#ParseLoclistWindowItemPosition() + AssertEqual [72, 25], g:ale_list_window_selection + +Execute(Just Line numbers should be parsed by the quickfix event function): + call setpos('.', [bufnr(''), 3, 1, 0]) + call ale#events#ParseLoclistWindowItemPosition() + AssertEqual [93, 1], g:ale_list_window_selection + +Given python(Some example Python file): + class FooBar: + def whatever(self): + self.do_something() + +Execute(We should jump to the window selection after cancelling the errors): + call setpos('.', [bufnr(''), 1, 1, 0]) + let g:ale_list_window_selection = [3, 9] + + echom 'E925' + call ale#events#BufWinLeave() + sleep 1ms + + AssertEqual [3, 9], getcurpos()[1:2]