From 249fbc63bf2f293c7511665ca600c5bfe25f1449 Mon Sep 17 00:00:00 2001 From: Matteo Landi Date: Mon, 5 Mar 2018 17:27:07 +0100 Subject: [PATCH 1/9] Check for :Dispatch and async inside init() --- autoload/ack.vim | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/autoload/ack.vim b/autoload/ack.vim index dbf84572..ebb8d103 100644 --- a/autoload/ack.vim +++ b/autoload/ack.vim @@ -2,14 +2,6 @@ if exists('g:autoloaded_ack') || &cp finish endif -if exists('g:ack_use_dispatch') - if g:ack_use_dispatch && !exists(':Dispatch') - call s:Warn('Dispatch not loaded! Falling back to g:ack_use_dispatch = 0.') - let g:ack_use_dispatch = 0 - endif -else - let g:ack_use_dispatch = 0 -endif "----------------------------------------------------------------------------- " Public API @@ -163,6 +155,15 @@ function! s:Init(cmd) "{{{ let s:searching_filepaths = (a:cmd =~# '-g$') ? 1 : 0 let s:using_loclist = (a:cmd =~# '^l') ? 1 : 0 + if exists('g:ack_use_dispatch') + if g:ack_use_dispatch && !exists(':Dispatch') + call s:Warn('Dispatch not loaded! Falling back to g:ack_use_dispatch = 0.') + let g:ack_use_dispatch = 0 + endif + else + let g:ack_use_dispatch = 0 + endif + if g:ack_use_dispatch && s:using_loclist call s:Warn('Dispatch does not support location lists! Proceeding with quickfix...') let s:using_loclist = 0 From 93bf705fb1659a8831049cda7a310aeee79d4543 Mon Sep 17 00:00:00 2001 From: Matteo Landi Date: Mon, 5 Mar 2018 17:28:51 +0100 Subject: [PATCH 2/9] Add support for async grepping (g:ack_use_async = 1) --- autoload/ack.vim | 83 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 79 insertions(+), 4 deletions(-) diff --git a/autoload/ack.vim b/autoload/ack.vim index ebb8d103..5f61b49a 100644 --- a/autoload/ack.vim +++ b/autoload/ack.vim @@ -43,18 +43,23 @@ function! ack#Ack(cmd, args) "{{{ " allow for passing arguments etc let l:escaped_args = escape(l:grepargs, '|#%') + let ShowResults = function('s:ShowResults', [l:grepargs]) + echo "Searching ..." if g:ack_use_dispatch call s:SearchWithDispatch(l:grepprg, l:escaped_args, l:grepformat) + elseif g:ack_use_async + call s:SearchWithAsync(l:grepprg, l:escaped_args, l:grepformat, ShowResults) else call s:SearchWithGrep(a:cmd, l:grepprg, l:escaped_args, l:grepformat) endif - " Dispatch has no callback mechanism currently, we just have to display the - " list window early and wait for it to populate :-/ - call ack#ShowResults() - call s:Highlight(l:grepargs) + if !g:ack_use_async + " Dispatch has no callback mechanism currently, we just have to display the + " list window early and wait for it to populate :-/ + call ShowResults() + endif endfunction "}}} function! ack#AckFromSearch(cmd, args) "{{{ @@ -141,6 +146,11 @@ function! s:GetDocLocations() "{{{ return dp endfunction "}}} +function! s:ShowResults(grepargs) "{{{ + call ack#ShowResults() + call s:Highlight(a:grepargs) +endfunction "}}} + function! s:Highlight(args) "{{{ if !g:ackhighlight return @@ -164,6 +174,15 @@ function! s:Init(cmd) "{{{ let g:ack_use_dispatch = 0 endif + if exists('g:ack_use_async') + if g:ack_use_async && !(&rtp =~ 'async.vim') + call s:Warn('async not loaded! Falling back to g:ack_use_async = 0.') + let g:ack_use_async = 0 + endif + else + let g:ack_use_async = 0 + endif + if g:ack_use_dispatch && s:using_loclist call s:Warn('Dispatch does not support location lists! Proceeding with quickfix...') let s:using_loclist = 0 @@ -205,6 +224,58 @@ function! s:SearchWithDispatch(grepprg, grepargs, grepformat) "{{{ endtry endfunction "}}} +function! s:SearchWithAsync(grepprg, grepargs, grepformat, success_cb) "{{{ + " We don't execute a :grep command for Dispatch, so add -g here instead + if s:SearchingFilepaths() + let l:grepprg = a:grepprg . ' -g' + else + let l:grepprg = a:grepprg + endif + + let cmd = l:grepprg . ' ' . a:grepargs + let job_cmd = split(&shell) + split(&shellcmdflag) + [cmd] + let ctx = { + \ 'data': [], + \ 'grepformat': a:grepformat, + \ 'title': ':' . cmd, + \ 'success_cb': a:success_cb, + \} + + function! ctx.append(job_id, data, event_type) "{{{ + let self.ctx.data = self.ctx.data + a:data + endfunction "}}} + + function! ctx.complete(job_id, data, event_type) " {{{ + let l:errorformat_bak = &l:errorformat + + try + let &l:errorformat = self.ctx.grepformat + let entries = filter(self.ctx.data, 'len(v:val)') + + if s:UsingLocList() + lgetexpr entries + call setloclist(0, [], 'a', { 'title': self.ctx.title }) + else + cgetexpr entries + call setqflist([], 'a', { 'title': self.ctx.title }) + endif + finally + let &l:errorformat = errorformat_bak + endtry + call self.ctx.success_cb() + endfunction "}}} + + let jobid = async#job#start(job_cmd, { + \ 'on_stdout': ctx.append, + \ 'on_exit': ctx.complete, + \ 'ctx': ctx, + \ }) + + if jobid <= 0 + call s:Error('Failed to run the following command: ' . string(job_cmd)) + endif +endfunction "}}} + function! s:SearchWithGrep(grepcmd, grepprg, grepargs, grepformat) "{{{ let l:grepprg_bak = &l:grepprg let l:grepformat_bak = &grepformat @@ -243,5 +314,9 @@ function! s:Warn(msg) "{{{ echohl WarningMsg | echomsg 'Ack: ' . a:msg | echohl None endf "}}} +function! s:Error(msg) "{{{ + echohl ErrorMsg | echomsg 'Ack: ' . a:msg | echohl None +endf "}}} + let g:autoloaded_ack = 1 " vim:set et sw=2 ts=2 tw=78 fdm=marker From e11d1f491da1f5d21da281524aa43ab11ee5fa20 Mon Sep 17 00:00:00 2001 From: Matteo Landi Date: Mon, 5 Mar 2018 17:38:49 +0100 Subject: [PATCH 3/9] Properly support grepadd/lgrepadd in async mode --- autoload/ack.vim | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/autoload/ack.vim b/autoload/ack.vim index 5f61b49a..d334345f 100644 --- a/autoload/ack.vim +++ b/autoload/ack.vim @@ -162,8 +162,9 @@ endfunction "}}} " Initialize state for an :Ack* or :LAck* search function! s:Init(cmd) "{{{ - let s:searching_filepaths = (a:cmd =~# '-g$') ? 1 : 0 - let s:using_loclist = (a:cmd =~# '^l') ? 1 : 0 + let s:searching_filepaths = (a:cmd =~# '-g$') ? 1 : 0 + let s:using_loclist = (a:cmd =~# '^l') ? 1 : 0 + let s:using_existing_qfloc_list = (a:cmd =~# '^l?grepadd') ? 1 : 0 if exists('g:ack_use_dispatch') if g:ack_use_dispatch && !exists(':Dispatch') @@ -253,10 +254,18 @@ function! s:SearchWithAsync(grepprg, grepargs, grepformat, success_cb) "{{{ let entries = filter(self.ctx.data, 'len(v:val)') if s:UsingLocList() - lgetexpr entries + if s:UsingExistingQFLocList() + laddexpr entries + else + lgetexpr entries + endif call setloclist(0, [], 'a', { 'title': self.ctx.title }) else - cgetexpr entries + if s:UsingExistingQFLocList() + caddexpr entries + else + cgetexpr entries + endif call setqflist([], 'a', { 'title': self.ctx.title }) endif finally @@ -310,6 +319,11 @@ function! s:UsingLocList() "{{{ return get(s:, 'using_loclist', 0) endfunction "}}} +" Were we invoked with a :AckAdd or :LackAdd command? +function! s:UsingExistingQFLocList() " {{{ + return get(s:, 'using_existing_qfloc_list', 0) +endfunction "}}} + function! s:Warn(msg) "{{{ echohl WarningMsg | echomsg 'Ack: ' . a:msg | echohl None endf "}}} From 4b625411790dd35fbf2473c59a7a0f778b501ac3 Mon Sep 17 00:00:00 2001 From: Matteo Landi Date: Mon, 5 Mar 2018 17:45:40 +0100 Subject: [PATCH 4/9] Update docs --- doc/ack.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/ack.txt b/doc/ack.txt index 22e884bc..95245b5d 100644 --- a/doc/ack.txt +++ b/doc/ack.txt @@ -219,6 +219,17 @@ acceptable tradeoffs for very large projects where searches are slow. Example: > let g:ack_use_dispatch = 1 +< + *g:ack_use_async* +g:ack_use_async +Default: 0 + +Use this option to use async.vim to run searches in the background, leveraging +async job support added to VIM 8. + +Example: +> + let g:ack_use_async = 1 < *g:ack_use_cword_for_empty_search* g:ack_use_cword_for_empty_search From 7e662ef274fd0f7e2af8b2af0db979333c0b6cb5 Mon Sep 17 00:00:00 2001 From: Matteo Landi Date: Thu, 8 Mar 2018 07:49:31 +0100 Subject: [PATCH 5/9] Update README to add reference to async.vim --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fca907fa..9ee96c4f 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,8 @@ Present maintainer, yours truly, [kind of wishes they never forked][sadface], contributes to both, and wouldn't mind seeing them merged again. ag.vim got a nice code clean-up (which ack.vim is now hopefully getting), and ack.vim picked up a few features that haven't made their way to ag.vim, like `:AckWindow`, -optional background search execution with [vim-dispatch], and auto-previewing. +optional background search execution with [vim-dispatch] or [async.vim], and +auto-previewing. #### I don't want to jump to the first result automatically. #### @@ -156,4 +157,5 @@ And of course, where would we be without [ack]. And, you know, Vim. [ack]: http://beyondgrep.com/ [vim-dispatch]: https://github.com/tpope/vim-dispatch +[async.vim]: https://github.com/prabirshrestha/async.vim [releases]: https://github.com/mileszs/ack.vim/releases From f25deeda023e91d293c634ce72406f4c404fe587 Mon Sep 17 00:00:00 2001 From: Matteo Landi Date: Sat, 24 Mar 2018 09:51:33 +0100 Subject: [PATCH 6/9] Do everything using setloclist/setqflist Use setloclist/setqflist not only to change the title, but also to append/replace entries in the quickfix/loclist. There was an issue earlier where entries in the quickfix/loclist windows sometimes ended up not being properly formatted (somehow errorformat was not properly picked up); this new solution should hopefully fix that. --- autoload/ack.vim | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/autoload/ack.vim b/autoload/ack.vim index 4bd0c85d..c25de1ec 100644 --- a/autoload/ack.vim +++ b/autoload/ack.vim @@ -253,20 +253,11 @@ function! s:SearchWithAsync(grepprg, grepargs, grepformat, success_cb) "{{{ let &l:errorformat = self.ctx.grepformat let entries = filter(self.ctx.data, 'len(v:val)') + let mode = s:UsingExistingQFLocList() ? 'a' : 'r' if s:UsingLocList() - if s:UsingExistingQFLocList() - laddexpr entries - else - lgetexpr entries - endif - call setloclist(0, [], 'a', { 'title': self.ctx.title }) + call setloclist(0, entries, mode, { 'title': self.ctx.title }) else - if s:UsingExistingQFLocList() - caddexpr entries - else - cgetexpr entries - endif - call setqflist([], 'a', { 'title': self.ctx.title }) + call setqflist(entries, mode, { 'title': self.ctx.title }) endif finally let &l:errorformat = errorformat_bak From 0f0676e21c2828b9e0760e28a6f3057fdff882df Mon Sep 17 00:00:00 2001 From: Matteo Landi Date: Wed, 28 Mar 2018 23:31:07 +0200 Subject: [PATCH 7/9] Fix bug with :AckAdd with async enabled --- autoload/ack.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autoload/ack.vim b/autoload/ack.vim index c25de1ec..9851befd 100644 --- a/autoload/ack.vim +++ b/autoload/ack.vim @@ -164,7 +164,7 @@ endfunction "}}} function! s:Init(cmd) "{{{ let s:searching_filepaths = (a:cmd =~# '-g$') ? 1 : 0 let s:using_loclist = (a:cmd =~# '^l') ? 1 : 0 - let s:using_existing_qfloc_list = (a:cmd =~# '^l?grepadd') ? 1 : 0 + let s:using_existing_qfloc_list = (a:cmd =~# '^l\?grepadd') ? 1 : 0 if exists('g:ack_use_dispatch') if g:ack_use_dispatch && !exists(':Dispatch') From 467ae0cefd215cab9bc31dfedbd50c51f2286e18 Mon Sep 17 00:00:00 2001 From: Matteo Landi Date: Wed, 28 Mar 2018 23:31:47 +0200 Subject: [PATCH 8/9] Revert "Do everything using setloclist/setqflist" This reverts commit f25deeda023e91d293c634ce72406f4c404fe587. --- autoload/ack.vim | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/autoload/ack.vim b/autoload/ack.vim index 9851befd..4ed32b28 100644 --- a/autoload/ack.vim +++ b/autoload/ack.vim @@ -253,11 +253,20 @@ function! s:SearchWithAsync(grepprg, grepargs, grepformat, success_cb) "{{{ let &l:errorformat = self.ctx.grepformat let entries = filter(self.ctx.data, 'len(v:val)') - let mode = s:UsingExistingQFLocList() ? 'a' : 'r' if s:UsingLocList() - call setloclist(0, entries, mode, { 'title': self.ctx.title }) + if s:UsingExistingQFLocList() + laddexpr entries + else + lgetexpr entries + endif + call setloclist(0, [], 'a', { 'title': self.ctx.title }) else - call setqflist(entries, mode, { 'title': self.ctx.title }) + if s:UsingExistingQFLocList() + caddexpr entries + else + cgetexpr entries + endif + call setqflist([], 'a', { 'title': self.ctx.title }) endif finally let &l:errorformat = errorformat_bak From 751043fd0e18907d5e645644f6ca647ea51d6f8b Mon Sep 17 00:00:00 2001 From: Matteo Landi Date: Fri, 25 May 2018 19:04:46 +0200 Subject: [PATCH 9/9] Change *global* errorformat when running async The async ack implementation uses {c,l}addexpr and {c,l}getexpr to populate the quickfix/location-list, which rely on global errorformat https://github.com/vim/vim/issues/569 --- autoload/ack.vim | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/autoload/ack.vim b/autoload/ack.vim index 4ed32b28..128a541e 100644 --- a/autoload/ack.vim +++ b/autoload/ack.vim @@ -247,10 +247,14 @@ function! s:SearchWithAsync(grepprg, grepargs, grepformat, success_cb) "{{{ endfunction "}}} function! ctx.complete(job_id, data, event_type) " {{{ - let l:errorformat_bak = &l:errorformat + " Later on we are using {c,l}addexpr and {c,l}getexpr to populate + " the quickfix/location-list, and these use the global errorformat so + " that's what needs to be temporarily changed. + " https://github.com/vim/vim/issues/569 + let l:errorformat_bak = &errorformat try - let &l:errorformat = self.ctx.grepformat + let &errorformat = self.ctx.grepformat let entries = filter(self.ctx.data, 'len(v:val)') if s:UsingLocList() @@ -269,7 +273,7 @@ function! s:SearchWithAsync(grepprg, grepargs, grepformat, success_cb) "{{{ call setqflist([], 'a', { 'title': self.ctx.title }) endif finally - let &l:errorformat = errorformat_bak + let &errorformat = errorformat_bak endtry call self.ctx.success_cb() endfunction "}}}