From 87ad4dfbe78665029521667afb2f159f3865523b Mon Sep 17 00:00:00 2001 From: w0rp Date: Sun, 22 Apr 2018 15:53:01 +0100 Subject: [PATCH] Implement a preview window for selecting locations to open --- autoload/ale/definition.vim | 20 ++--------- autoload/ale/preview.vim | 54 ++++++++++++++++++++++++++++-- autoload/ale/util.vim | 21 ++++++++++-- ftplugin/ale-preview-selection.vim | 16 +++++++++ syntax/ale-preview-selection.vim | 11 ++++++ test/test_go_to_definition.vader | 7 ++-- 6 files changed, 104 insertions(+), 25 deletions(-) create mode 100644 ftplugin/ale-preview-selection.vim create mode 100644 syntax/ale-preview-selection.vim diff --git a/autoload/ale/definition.vim b/autoload/ale/definition.vim index 521cd0b1..a3bfcd17 100644 --- a/autoload/ale/definition.vim +++ b/autoload/ale/definition.vim @@ -13,26 +13,10 @@ function! ale#definition#SetMap(map) abort let s:go_to_definition_map = a:map endfunction -" This function is used so we can check the execution of commands without -" running them. -function! ale#definition#Execute(expr) abort - execute a:expr -endfunction - function! ale#definition#ClearLSPData() abort let s:go_to_definition_map = {} endfunction -function! ale#definition#Open(options, filename, line, column) abort - if a:options.open_in_tab - call ale#definition#Execute('tabedit ' . fnameescape(a:filename)) - else - call ale#definition#Execute('edit ' . fnameescape(a:filename)) - endif - - call cursor(a:line, a:column) -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) @@ -43,7 +27,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#Open(l:options, l:filename, l:line, l:column) + call ale#util#Open(l:filename, l:line, l:column, l:options) endif endif endfunction @@ -67,7 +51,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 - call ale#definition#Open(l:options, l:filename, l:line, l:column) + call ale#util#Open(l:filename, l:line, l:column, l:options) break endfor endif diff --git a/autoload/ale/preview.vim b/autoload/ale/preview.vim index 3b1c16a6..c03cfe51 100644 --- a/autoload/ale/preview.vim +++ b/autoload/ale/preview.vim @@ -2,13 +2,16 @@ " Description: Preview windows for showing whatever information in. " Open a preview window and show some lines in it. -function! ale#preview#Show(lines) abort +" An optional second argument can set an alternative filetype for the window. +function! ale#preview#Show(lines, ...) abort + let l:filetype = get(a:000, 0, 'ale-preview') + silent pedit ALEPreviewWindow wincmd P setlocal modifiable setlocal noreadonly setlocal nobuflisted - setlocal filetype=ale-preview + let &l:filetype = l:filetype setlocal buftype=nofile setlocal bufhidden=wipe :%d @@ -16,3 +19,50 @@ function! ale#preview#Show(lines) abort setlocal nomodifiable setlocal readonly endfunction + +" Show a location selection preview window, given some items. +" Each item should have 'filename', 'line', and 'column' keys. +function! ale#preview#ShowSelection(item_list) abort + let l:lines = [] + + " Create lines to display to users. + for l:item in a:item_list + call add( + \ l:lines, + \ l:item.filename + \ . ':' . l:item.line + \ . ':' . l:item.column, + \) + endfor + + call ale#preview#Show(l:lines, 'ale-preview-selection') + let b:ale_preview_item_list = a:item_list +endfunction + +function! s:Open(open_in_tab) abort + let l:item_list = get(b:, 'ale_preview_item_list', []) + let l:item = get(l:item_list, getcurpos()[1] - 1, {}) + + if empty(l:item) + return + endif + + if !a:open_in_tab + :q! + endif + + call ale#util#Open( + \ l:item.filename, + \ l:item.line, + \ l:item.column, + \ {'open_in_tab': a:open_in_tab}, + \) +endfunction + +function! ale#preview#OpenSelectionInBuffer() abort + call s:Open(0) +endfunction + +function! ale#preview#OpenSelectionInTab() abort + call s:Open(1) +endfunction diff --git a/autoload/ale/util.vim b/autoload/ale/util.vim index d160b34c..55d9d743 100644 --- a/autoload/ale/util.vim +++ b/autoload/ale/util.vim @@ -11,6 +11,11 @@ function! ale#util#FeedKeys(...) abort return call('feedkeys', a:000) endfunction +" A wrapper function for execute, so we can test executing some commands. +function! ale#util#Execute(expr) abort + execute a:expr +endfunction + if !exists('g:ale#util#nul_file') " A null file for sending output to nothing. let g:ale#util#nul_file = '/dev/null' @@ -33,6 +38,16 @@ function! ale#util#GetFunction(string_or_ref) abort return a:string_or_ref endfunction +function! ale#util#Open(filename, line, column, options) abort + if get(a:options, 'open_in_tab', 0) + call ale#util#Execute('tabedit ' . fnameescape(a:filename)) + else + call ale#util#Execute('edit ' . fnameescape(a:filename)) + endif + + call cursor(a:line, a:column) +endfunction + let g:ale#util#error_priority = 5 let g:ale#util#warning_priority = 4 let g:ale#util#info_priority = 3 @@ -341,8 +356,10 @@ if !exists('s:patial_timers') endif function! s:ApplyPartialTimer(timer_id) abort - let [l:Callback, l:args] = remove(s:partial_timers, a:timer_id) - call call(l:Callback, [a:timer_id] + l:args) + if has_key(s:partial_timers, a:timer_id) + let [l:Callback, l:args] = remove(s:partial_timers, a:timer_id) + call call(l:Callback, [a:timer_id] + l:args) + endif endfunction " Given a delay, a callback, a List of arguments, start a timer with diff --git a/ftplugin/ale-preview-selection.vim b/ftplugin/ale-preview-selection.vim new file mode 100644 index 00000000..d77b4f98 --- /dev/null +++ b/ftplugin/ale-preview-selection.vim @@ -0,0 +1,16 @@ +" Close the ALEPreviewWindow window with the q key. +noremap q :q! +" Disable some keybinds for the selection window. +noremap v +noremap i +noremap I +noremap +noremap +noremap +noremap a +noremap A +noremap o +noremap O +" Keybinds for opening selection items. +noremap :call ale#preview#OpenSelectionInBuffer() +noremap t :call ale#preview#OpenSelectionInTab() diff --git a/syntax/ale-preview-selection.vim b/syntax/ale-preview-selection.vim new file mode 100644 index 00000000..879ba096 --- /dev/null +++ b/syntax/ale-preview-selection.vim @@ -0,0 +1,11 @@ +if exists('b:current_syntax') + finish +endif + +syn match alePreviewSelectionFilename /\v^([a-zA-Z]?:?[^:]+)/ +syn match alPreviewNumber /\v:\d+:\d+$/ + +hi def link alePreviewSelectionFilename String +hi def link alePreviewNumber Number + +let b:current_syntax = 'ale-preview-selection' diff --git a/test/test_go_to_definition.vader b/test/test_go_to_definition.vader index b77a75ac..5bd75675 100644 --- a/test/test_go_to_definition.vader +++ b/test/test_go_to_definition.vader @@ -7,9 +7,9 @@ Before: let g:message_list = [] let g:expr_list = [] - runtime autoload/ale/definition.vim runtime autoload/ale/linter.vim runtime autoload/ale/lsp.vim + runtime autoload/ale/util.vim function! ale#linter#StartLSP(buffer, linter, callback) abort let g:Callback = a:callback @@ -26,11 +26,12 @@ Before: return 42 endfunction - function! ale#definition#Execute(expr) abort + function! ale#util#Execute(expr) abort call add(g:expr_list, a:expr) endfunction After: + call ale#definition#SetMap({}) call ale#test#RestoreDirectory() call ale#linter#Reset() @@ -40,9 +41,9 @@ After: unlet! g:expr_list unlet! b:ale_linters - runtime autoload/ale/definition.vim runtime autoload/ale/linter.vim runtime autoload/ale/lsp.vim + runtime autoload/ale/util.vim Execute(Other messages for the tsserver handler should be ignored): call ale#definition#HandleTSServerResponse(1, {'command': 'foo'})