diff --git a/README.md b/README.md index fdbc821..896a1d3 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ ### Anti-features -Many plugins interact with the quickfix/location list/window in ways that are more or less incompatible with vim-qf. I have put considerable effort in making most vim-qf features optional so it should be possible to disable individual features in case of conflict but well… you never know. +Many plugins interact with the quickfix/location list/window in ways that are more or less incompatible with vim-qf. I have put considerable effort into making most vim-qf features optional so it should be possible to disable individual features in case of conflict but well… you never know. **If one of your plugins somehow already manages the quickfix/location list/window, then you should probably look elsewhere.** @@ -26,7 +26,7 @@ Many plugins interact with the quickfix/location list/window in ways that are mo - (optional) open the location/quickfix window automatically after `:make`, `:grep`, `:lvimgrep` and friends if there are valid locations/errors -- (optional) automatically set the height of location/quickfix windows to the number of list items if less than Vim's default height (10) or the user's prefered height +- (optional) automatically set the height of location/quickfix windows to the number of list items if less than Vim's default height (10) or the user's preferred height ### Local features (available only in location/quickfix windows) @@ -36,10 +36,6 @@ Many plugins interact with the quickfix/location list/window in ways that are mo ![filter][1] -- perform commands on each line in the current list - -- perform commands on each file in the current list - - jump to next group of entries belonging to same file ("file grouping"): ![group][2] @@ -72,27 +68,9 @@ If you are using Vim 8.0 or above, move this directory to: See `:help package`. -### Method 3 - -If you are using Vim 7.4 or below, move the files in this directory to their standard location: - - # Unix-like systems - ~/.vim/after/ftplugin/qf.vim - ~/.vim/autoload/qf.vim - ~/.vim/autoload/qf/*.vim - ~/.vim/doc/qf.txt - ~/.vim/plugin/qf.vim - - # Windows - %userprofile%\vimfiles\after\ftplugin\qf.vim - %userprofile%\vimfiles\autoload\qf.vim - %userprofile%\vimfiles\autoload\qf\*.vim - %userprofile%\vimfiles\doc\qf.txt - %userprofile%\vimfiles\plugin\qf.vim - ## Documentation -You can use this command to get help on vim-qf: +The full documentation is available through this command: :help vim-qf diff --git a/after/ftplugin/qf.vim b/after/ftplugin/qf.vim index 90e81a7..99f983e 100644 --- a/after/ftplugin/qf.vim +++ b/after/ftplugin/qf.vim @@ -4,31 +4,20 @@ " License: MIT " Location: after/ftplugin/qf.vim " Website: https://github.com/romainl/vim-qf -" -" Use this command to get help on vim-qf: -" -" :help qf -" -" If this doesn't work and you installed vim-qf manually, use the following -" command to index vim-qf's documentation: -" -" :helptags ~/.vim/doc -" -" or read your runtimepath/plugin manager documentation. let s:save_cpo = &cpo set cpo&vim -" text wrapping is pretty much useless in the quickfix window +" Text wrapping is pretty much useless in the quickfix window " but some users may still want it execute get(g:, "qf_nowrap", 1) ? "setlocal nowrap" : "setlocal wrap" -" relative line numbers don't make much sense either +" Relative line numbers don't make much sense either " but absolute numbers definitely do setlocal norelativenumber setlocal number -" we don't want quickfix buffers to pop up when doing :bn or :bp +" We don't want quickfix buffers to pop up when doing :bn or :bp set nobuflisted if exists("b:undo_ftplugin") @@ -37,54 +26,59 @@ else let b:undo_ftplugin = "setl wrap< rnu< nu< bl<" endif -" are we in a location list or a quickfix list? -let b:qf_isLoc = get(get(getwininfo(win_getid()), 0, {}), 'loclist', 0) +" Are we in a location window or a quickfix window? +" 0 -> quickfix window +" 1 -> location window +let b:qf_isLoc = win_getid() + \ ->getwininfo() + \ ->get(0, {}) + \ ->get("loclist", 0) -" customize the statusline +" Customize the statusline if exists("g:qf_statusline") execute "setlocal statusline=" . g:qf_statusline.before . "%{qf#statusline#SetStatusline()}" . g:qf_statusline.after endif -" inspired by Ack.vim -if exists("g:qf_mapping_ack_style") - let qf_at_bottom = (b:qf_isLoc == 1 && get(g:, 'qf_loclist_window_bottom', 1)) - \ || (b:qf_isLoc == 0 && get(g:, 'qf_window_bottom', 1)) +" Mappings inspired by Ack.vim +if get(g:, "qf_mapping_ack_style", 0) + let qf_at_bottom = (get(b:, "qf_isLoc", 0) && get(g:, "qf_loclist_window_bottom", 1)) + \ || (!get(b:, "qf_isLoc", 0) && get(g:, "qf_window_bottom", 1)) - " open entry in a new vertical window. + " Open entry in a new vertical window if qf_at_bottom nnoremap v &splitright ? "\\\L\p\J\p" : "\\\H\p\J\p" else - " don't move quickfix to bottom if qf_loclist_window_bottom is 0 + " Don't move quickfix to bottom if qf_loclist_window_bottom is 0 nnoremap v &splitright ? "\\\L" : "\\\H" endif if qf_at_bottom && &splitbelow - " open entry in a new horizontal window and move quickfix to bottom + " Open entry in a new horizontal window and move quickfix to bottom nnoremap s pJp - " preview entry under the cursor and move quickfix to bottom + " Preview entry under the cursor and move quickfix to bottom nnoremap p :call qf#preview#PreviewFileUnderCursor()J else - " open entry in a new horizontal window + " Open entry in a new horizontal window nnoremap s - " preview entry under the cursor + " Preview entry under the cursor nnoremap p :call qf#preview#PreviewFileUnderCursor() endif - " open entry in a new tab. - nnoremap t T - - " open entry and come back - nnoremap o p - - " open entry and close the location/quickfix window. - if b:qf_isLoc == 1 + " Open entry and close the location/quickfix window + if get(b:, "qf_isLoc", 0) nnoremap O :lclose else nnoremap O :cclose endif + " Open entry in a new tab + nnoremap t T + + " Open entry and come back + nnoremap o p + let b:undo_ftplugin .= "| execute 'nunmap s'" \ . "| execute 'nunmap v'" \ . "| execute 'nunmap t'" @@ -93,76 +87,75 @@ if exists("g:qf_mapping_ack_style") \ . "| execute 'nunmap p'" endif -" filter the location/quickfix list -" (kept for backward compatibility, use :Keep and :Reject instead) -" usage: -" :Filter foo <-- same as :Keep foo -" :Filter! foo <-- same as :Reject foo -" :10,15Filter <-- same as :10,15Keep -" :10,15Filter! <-- same as :10,15Reject -command! -buffer -range -nargs=1 -bang Filter call qf#filter#FilterList(, expand("") == "!" ? 1 : 0, , , ) - -" keep entries matching the argument or range -" usage: +" Keep entries matching the argument or range +" Usage: " :Keep foo " :10,15Keep command! -buffer -range -nargs=? Keep call qf#filter#FilterList(, 0, , , ) -" reject entries matching the argument or range -" usage: +" Reject entries matching the argument or range +" Usage: " :Reject foo " :10,15Reject command! -buffer -range -nargs=? Reject call qf#filter#FilterList(, 1, , , ) -" restore the location/quickfix list -" usage: +" Restore the location/quickfix list +" Usage: " :Restore command! -buffer -bar Restore call qf#filter#RestoreList() -" do something on each line in the location/quickfix list -" usage: -" :Doline s/^/--- -command! -buffer -nargs=1 Doline call qf#do#DoList(1, ) - -" do something on each file in the location/quickfix list -" usage: -" :Dofile %s/^/--- -command! -buffer -nargs=1 Dofile call qf#do#DoList(0, ) - -" save current location/quickfix list and associate it with a given name or the +" Save current location/quickfix list and associate it with a given name or the " last used name +" Usage: +" :SaveList foobar +" :SaveList command! -buffer -nargs=? -complete=customlist,qf#namedlist#CompleteList SaveList call qf#namedlist#SaveList(0, ) -" like SaveList, but add to a potentially existing named list +" Like SaveList, but add to a potentially existing named list +" Usage: +" :SaveListAdd foobar +" :SaveListAdd command! -buffer -nargs=? -complete=customlist,qf#namedlist#CompleteList SaveListAdd call qf#namedlist#SaveList(1, ) -" replace location/quickfix list with named lists +" Replace location/quickfix list with named lists +" Usage: +" :LoadList foobar command! -buffer -nargs=+ -complete=customlist,qf#namedlist#CompleteList LoadList call qf#namedlist#LoadList(0, ) -" like LoadList but append instead of replace +" Like LoadList but append instead of replace +" Usage: +" :LoadListAdd foobar command! -buffer -nargs=+ -complete=customlist,qf#namedlist#CompleteList LoadListAdd call qf#namedlist#LoadList(1, ) -" list currently saved lists +" List currently saved lists +" Usage: +" :ListLists command! -buffer ListLists call qf#namedlist#ListLists() -" remove given lists or all +" Remove given lists or all +" Usage: +" :RemoveList foobar +" :RemoveList! command! -buffer -nargs=* -bang -complete=customlist,qf#namedlist#CompleteList RemoveList call qf#namedlist#RemoveList(expand("") == "!" ? 1 : 0, ) -" quit Vim if the last window is a quickfix window -autocmd qf BufEnter nested if get(g:, 'qf_auto_quit', 1) | if winnr('$') < 2 | q | endif | endif -autocmd qf BufWinEnter nested if get(g:, 'qf_auto_quit', 1) | call qf#filter#ReuseTitle() | endif +" Quit Vim if the last window is a quickfix window +autocmd qf BufEnter nested if get(g:, "qf_auto_quit", 1) | if winnr('$') < 2 | q | endif | endif +autocmd qf BufWinEnter nested if get(g:, "qf_auto_quit", 1) | call qf#filter#ReuseTitle() | endif -" Move forward and backward in list history (in a quickfix or location window) +" Move forward and backward in list history (in a location/quickfix window) nnoremap (qf_older) :call qf#history#Older() nnoremap (qf_newer) :call qf#history#Newer() -" Jump to previous and next file grouping (in a quickfix or location window) +" Jump to previous and next file grouping (in a location/quickfix window) nnoremap (qf_previous_file) :call qf#filegroup#PreviousFile() nnoremap (qf_next_file) :call qf#filegroup#NextFile() -let b:undo_ftplugin .= "| delcommand Filter" - \ . "| delcommand Keep" +" Decide where to open the location/quickfix window +if (get(b:, "qf_isLoc", 0) && get(g:, "qf_loclist_window_bottom", 1)) + \ || (!get(b:, "qf_isLoc", 0) && get(g:, "qf_window_bottom", 1)) + wincmd J +endif + +let b:undo_ftplugin .= "| delcommand Keep" \ . "| delcommand Reject" \ . "| delcommand Restore" - \ . "| delcommand Doline" - \ . "| delcommand Dofile" \ . "| delcommand SaveList" \ . "| delcommand SaveListAdd" \ . "| delcommand LoadList" @@ -175,10 +168,4 @@ let b:undo_ftplugin .= "| delcommand Filter" \ . "| execute 'nunmap (qf_next_file)'" \ . "| unlet! b:qf_isLoc" -" decide where to open the location/quickfix window -if (b:qf_isLoc == 1 && get(g:, 'qf_loclist_window_bottom', 1)) - \ || (b:qf_isLoc == 0 && get(g:, 'qf_window_bottom', 1)) - wincmd J -endif - let &cpo = s:save_cpo diff --git a/autoload/qf.vim b/autoload/qf.vim index 91a1539..572ccce 100644 --- a/autoload/qf.vim +++ b/autoload/qf.vim @@ -4,171 +4,150 @@ " License: MIT " Location: autoload/qf.vim " Website: https://github.com/romainl/vim-qf -" -" Use this command to get help on vim-qf: -" -" :help qf -" -" If this doesn't work and you installed vim-qf manually, use the following -" command to index vim-qf's documentation: -" -" :helptags ~/.vim/doc -" -" or read your runtimepath/plugin manager documentation. let s:save_cpo = &cpo set cpo&vim -" open the current entry in th preview window -function qf#PreviewFileUnderCursor() - let cur_list = b:qf_isLoc == 1 ? getloclist('.') : getqflist() - let cur_line = getline(line('.')) - let cur_file = fnameescape(substitute(cur_line, '|.*$', '', '')) - if cur_line =~ '|\d\+' - let cur_pos = substitute(cur_line, '^\(.\{-}|\)\(\d\+\)\(.*\)', '\2', '') - execute "pedit +" . cur_pos . " " . cur_file - else - execute "pedit " . cur_file - endif +function! s:GetWinInfo(nr) + let win_id = a:nr != 0 ? win_getid(a:nr) : win_getid() + + return win_id->getwininfo()->get(0, {}) endfunction -" helper function -" returns 1 if the window with the given number is a quickfix window +" Returns 1 if the window with the given number is a quickfix window " 0 if the window with the given number is not a quickfix window -" TODO (Nelo-T. Wallus): make a:nbmr optional and return current window -" by default -function! qf#IsQfWindow(nmbr) - if getwinvar(a:nmbr, "&filetype") == "qf" - return qf#IsLocWindow(a:nmbr) ? 0 : 1 - endif +" Uses current window if no number is given +function! qf#IsQfWindow(...) + let info = get(a:, 1, 0)->GetWinInfo() - return 0 + return info->get("quickfix", 0) == 1 && info->get("loclist", 0) == 0 endfunction -" helper function -" returns 1 if the window with the given number is a location window +" Returns 1 if the window with the given number is a location window " 0 if the window with the given number is not a location window -function! qf#IsLocWindow(nmbr) - return getbufvar(winbufnr(a:nmbr), "qf_isLoc") == 1 +" Uses current window if no number is given +function! qf#IsLocWindow(...) + let info = get(a:, 1, 0)->GetWinInfo() + + return info->get("loclist", 0) == 1 endfunction -" returns bool: Is quickfix window open? +" Returns bool: Is quickfix window open? function! qf#IsQfWindowOpen() abort - for winnum in range(1, winnr('$')) + for winnum in range(1, winnr("$")) if qf#IsQfWindow(winnum) return 1 endif endfor + return 0 endfunction -" returns bool: Is location window for window with given number open? +" Returns bool: Is location window for window with given number open? function! qf#IsLocWindowOpen(nmbr) abort let loclist = getloclist(a:nmbr) - for winnum in range(1, winnr('$')) - if qf#IsLocWindow(winnum) && loclist ==# getloclist(winnum) - return 1 - endif - endfor + + if !loclist->empty() + for winnum in range(1, winnr("$")) + if qf#IsLocWindow(winnum) && loclist ==# getloclist(winnum) + return 1 + endif + endfor + endif + return 0 endfunction -" returns location list of the current loclist if isLoc is set -" qf list otherwise -function! qf#GetList() - if get(b:, 'qf_isLoc', 0) - return getloclist(0) +" Returns items of the current location/quickfix list +" qf#GetListItems(0, 0) .... all items of the quickfix list +" qf#GetListItems(0, 5) .... item 5 of the quickfix list +" qf#GetListItems(1, 0) .... all items of the location list +" qf#GetListItems(1, 5) .... item 5 of the location list +function! qf#GetListItems(loc = 0, idx = 0) + if a:loc == 1 + return getloclist(0, { "idx": a:idx, "items": 1 })["items"] + else + return getqflist({ "idx": a:idx, "items": 1 })["items"] + endif +endfunction + +" Returns the number of items in a location/quickfix list +" qf#GetListSize(0) .... size of the quickfix list +" qf#GetListSize(1) .... size of the location list +function! qf#GetListSize(loc = 0) + if a:loc == 1 + return getloclist(0, { "size": 1 })->get("size", 99999) + else + return getqflist({ "size": 1 })->get("size", 99999) + endif +endfunction + +" Returns the title of a location/quickfix list +" qf#GetListTitle(0) .... title of the quickfix list +" qf#GetListTitle(1) .... title of the location list +function! qf#GetListTitle(loc = 0) + if a:loc == 1 + return getloclist(0, { "title": 1 })->get("title", "") else - return getqflist() + return getqflist({ "title": 1 })->get("title", "") endif endfunction -" sets location or qf list based in b:qf_isLoc to passed newlist +" Returns the maximum height of the location/quickfix window +function! qf#GetMaxHeight() + return get(g:, "qf_max_height", 10) < 1 ? 10 : get(g:, "qf_max_height", 10) +endfunction + +" Sets location or quickfix list based in b:qf_isLoc to passed newlist function! qf#SetList(newlist, ...) - " generate partial + " Generate partial let Func = get(b:, 'qf_isLoc', 0) \ ? function('setloclist', [0, a:newlist]) \ : function('setqflist', [a:newlist]) - " get user-defined maximum height - let max_height = get(g:, 'qf_max_height', 10) < 1 ? 10 : get(g:, 'qf_max_height', 10) - - " call partial with optional arguments + " Call partial with optional arguments call call(Func, a:000) if a:newlist == [] return endif - if get(b:, 'qf_isLoc', 0) - execute get(g:, "qf_auto_resize", 1) ? 'lclose|' . min([ max_height, len(getloclist(0)) ]) . 'lwindow' : 'lclose|lwindow' - else - execute get(g:, "qf_auto_resize", 1) ? 'cclose|' . min([ max_height, len(getqflist()) ]) . 'cwindow' : 'cclose|cwindow' - endif + call get(b:, "qf_isLoc", 0)->qf#OpenWindow() endfunction -function! qf#GetEntryPath(line) abort - " +- match from the first pipe to the end of line - " | declaring EOL explicitly is faster than implicitly - " | +- replace match with nothing - " | | +- no flags - return substitute(a:line, '|.*$', '', '') +" Open the quickfix window if there are valid errors +function! qf#OpenQuickfixWindow() + if get(g:, "qf_auto_open_quickfix", 1) + call qf#OpenWindow(0) + endif endfunction -" open the quickfix window if there are valid errors -function! qf#OpenQuickfix() - if get(g:, 'qf_auto_open_quickfix', 1) - " get user-defined maximum height - let max_height = get(g:, 'qf_max_height', 10) < 1 ? 10 : get(g:, 'qf_max_height', 10) - - let qf_list = getqflist() - - " shorten paths if applicable - if get(g:, 'qf_shorten_path', 0) > 0 - call setqflist(qf#ShortenPathsInList(qf_list)) - endif - - execute get(g:, "qf_auto_resize", 1) ? 'cclose|' . min([ max_height, len(qf_list) ]) . 'cwindow' : 'cclose|cwindow' +" Open a location window if there are valid locations +function! qf#OpenLocationWindow() + if get(g:, "qf_auto_open_loclist", 1) + call qf#OpenWindow(1) endif endfunction -" open a location window if there are valid locations -function! qf#OpenLoclist() - if get(g:, 'qf_auto_open_loclist', 1) - " get user-defined maximum height - let max_height = get(g:, 'qf_max_height', 10) < 1 ? 10 : get(g:, 'qf_max_height', 10) - - let loc_list = getloclist(0) +" Refresh the location/quickfix window +function! qf#OpenWindow(loc) + let prefix = get(a:, "loc", 0) ? "l" : "c" + let list_size = qf#GetListSize(a:loc) - " shorten paths if applicable - if get(g:, 'qf_shorten_path', 0) > 0 - call setloclist(0, qf#ShortenPathsInList(loc_list)) - endif - - execute get(g:, "qf_auto_resize", 1) ? 'lclose|' . min([ max_height, len(loc_list) ]) . 'lwindow' : 'lclose|lwindow' + if list_size > 0 + execute get(g:, "qf_auto_resize", 1) + \ ? prefix .. "close|" .. min([ qf#GetMaxHeight(), list_size ]) .. prefix .. "window" + \ : prefix .. "close|" .. prefix .. "window" + else + execute prefix .. "close" endif endfunction -" shorten file paths in given qf/loc list -function! qf#ShortenPathsInList(list) - let index = 0 - while index < len(a:list) - " item is a dict, sample: { lnum: 14, text: 'foo bar', bufnr: 3, ... } - let item = a:list[index] - - let filepath = bufname(item["bufnr"]) - let trim_len = get(g:, "qf_shorten_path", 1) - - " set the 'module' field to customise the visual filename in the qf/loc list (available since 8.0.1782) - if has('patch-8.2.1741') - let item["module"] = pathshorten(filepath, trim_len) - else - let item["module"] = pathshorten(filepath) - endif +" Handles formatting of the text in the buffer +function! qf#QuickfixTextFunc(options) + let items = qf#GetListItems(!a:options["quickfix"], 0) - let index = index + 1 - endwhile - return a:list + return items->map({ key, val -> qf#format#FormatItem(val) }) endfunction let &cpo = s:save_cpo diff --git a/autoload/qf/do.vim b/autoload/qf/do.vim deleted file mode 100644 index 641e17d..0000000 --- a/autoload/qf/do.vim +++ /dev/null @@ -1,58 +0,0 @@ -" vim-qf - Tame the quickfix window -" Maintainer: romainl -" Version: 0.2.0 -" License: MIT -" Location: autoload/do.vim -" Website: https://github.com/romainl/vim-qf -" -" Use this command to get help on vim-qf: -" -" :help qf -" -" If this doesn't work and you installed vim-qf manually, use the following -" command to index vim-qf's documentation: -" -" :helptags ~/.vim/doc -" -" or read your runtimepath/plugin manager documentation. - -let s:save_cpo = &cpo -set cpo&vim - -" do something with each entry -" a single function for :Doline and :Dofile both in a quickfix list and -" a location list -" falls back to :cdo, :cfdo, :ldo, :lfdo when possible -function! qf#do#DoList(line, cmd) - if exists("b:qf_isLoc") - let prefix = b:qf_isLoc == 1 ? "l" : "c" - else - let prefix = "c" - endif - - if v:version >= 705 - \ || v:version == 704 && has("patch858") - if a:line == 1 - let modifier = "" - else - let modifier = "f" - endif - - try - execute prefix . modifier . "do " . a:cmd - catch /^Vim\%((\a\+)\)\=:E\%(553\|42\):/ - endtry - else - try - silent execute prefix . "first" - while 1 - execute a:cmd - - silent execute a:line == 1 ? prefix . "next" : prefix . "nfile" - endwhile - catch /^Vim\%((\a\+)\)\=:E\%(553\|42\):/ - endtry - endif -endfunction - -let &cpo = s:save_cpo diff --git a/autoload/qf/filegroup.vim b/autoload/qf/filegroup.vim index 9bf2900..61b6771 100644 --- a/autoload/qf/filegroup.vim +++ b/autoload/qf/filegroup.vim @@ -19,40 +19,54 @@ let s:save_cpo = &cpo set cpo&vim -function! s:JumpToFirstItemOfFileChunk() abort - let l:chunk_file_path = qf#GetEntryPath(getline('.')) +function! qf#filegroup#NextFile() abort + if exists("b:qf_isLoc") + let items = qf#GetListItems(b:->get("qf_isLoc", 0), 0) + let current_index = line('.') - 1 + let current_bufnr = items[current_index]["bufnr"] + let limit = items->len() - while line('.') - 1 != 0 - \ && l:chunk_file_path == qf#GetEntryPath(getline(line('.') - 1)) - normal! k - endwhile + while current_index < limit && items[current_index]["bufnr"] == current_bufnr + let current_index += 1 + endwhile - normal! zz + if current_index == limit + 1 + else + execute current_index + 1 + endif + endif endfunction -function! s:JumpFileChunk(down) abort - let l:start_file_path = qf#GetEntryPath(getline('.')) - let l:direction = a:down ? 'j' : 'k' - let l:end = a:down ? '$' : 1 +function! qf#filegroup#PreviousFile() abort + if exists("b:qf_isLoc") + let items = qf#GetListItems(b:->get("qf_isLoc", 0), 0) + let current_index = line('.') - 1 + let current_bufnr = items[current_index]["bufnr"] + let limit = 0 - while l:start_file_path - \ == qf#GetEntryPath(getline('.')) - \ && getline('.') != getline(l:end) - execute 'normal! ' . l:direction - endwhile + while current_index > limit && items[current_index]["bufnr"] == current_bufnr + let current_index -= 1 + endwhile - call s:JumpToFirstItemOfFileChunk() -endfunction + if current_index == limit + normal! G + else + execute current_index + 1 + endif -function! qf#filegroup#PreviousFile() abort - if exists("b:qf_isLoc") - call s:JumpFileChunk(0) - endif -endfunction + let current_index = line('.') - 1 + let current_bufnr = items[current_index]["bufnr"] -function! qf#filegroup#NextFile() abort - if exists("b:qf_isLoc") - call s:JumpFileChunk(1) + while current_index > limit && items[current_index]["bufnr"] == current_bufnr + let current_index -= 1 + endwhile + + if current_index == limit + 1 + else + execute current_index + 2 + endif endif endfunction diff --git a/autoload/qf/filter.vim b/autoload/qf/filter.vim index 31eff1e..ecdb891 100644 --- a/autoload/qf/filter.vim +++ b/autoload/qf/filter.vim @@ -4,122 +4,81 @@ " License: MIT " Location: autoload/filter.vim " Website: https://github.com/romainl/vim-qf -" -" Use this command to get help on vim-qf: -" -" :help qf -" -" If this doesn't work and you installed vim-qf manually, use the following -" command to index vim-qf's documentation: -" -" :helptags ~/.vim/doc -" -" or read your runtimepath/plugin manager documentation. let s:save_cpo = &cpo set cpo&vim " deletes every original list function! s:ResetLists() - if exists("b:qf_isLoc") - if b:qf_isLoc == 1 - call setwinvar(winnr("#"), "qf_location_lists", []) - call setwinvar(winnr("#"), "qf_location_titles", []) - else - let g:qf_quickfix_lists = [] - let g:qf_quickfix_titles = [] - endif + if qf#IsLocWindow() + call winnr("#")->setwinvar("qf_location_lists", []) + call winnr("#")->setwinvar("qf_location_titles", []) + endif + + if qf#IsQfWindow() + let g:qf_quickfix_lists = [] + let g:qf_quickfix_titles = [] endif endfunction -function! s:SetList(pat, range, reject, strategy) +function! s:FilteredList(list, pat, range, reject, strategy) " decide what regexp operator to use - let operator = a:reject == 0 ? '=~' : '!~' - " get user-defined maximum height - let max_height = get(g:, 'qf_max_height', 10) < 1 ? 10 : get(g:, 'qf_max_height', 10) - - if exists("b:qf_isLoc") - if b:qf_isLoc == 1 - " bufname && text - if a:strategy == 0 - call setloclist(0, filter(getloclist(0), "(bufname(v:val['bufnr']) . v:val['text'] " . operator . " a:pat)"), "r") - endif + let operator = a:reject == 0 ? '=~' : '!~' - " only bufname - if a:strategy == 1 - call setloclist(0, filter(getloclist(0), "bufname(v:val['bufnr']) " . operator . " a:pat"), "r") - endif - - " only text - if a:strategy == 2 - call setloclist(0, filter(getloclist(0), "v:val['text'] " . operator . " a:pat"), "r") - endif + " create an empty list + let new_list = [] - " range - if a:strategy == 3 - let current_list = getloclist(0) - if a:reject - " remove range from list - call remove(current_list, a:range[0], a:range[1]) - call setloclist(0, current_list, "r") - else - " take range from list - call setloclist(0, remove(current_list, a:range[0], a:range[1]), "r") - endif - endif + " bufname && text + if a:strategy == 0 + let new_list = a:list->filter("(bufname(v:val['bufnr']) .. v:val['text'] " .. operator .. " a:pat)") + endif - execute get(g:, "qf_auto_resize", 1) ? 'lclose|' . min([ max_height, len(getloclist(0)) ]) . 'lwindow' : 'lclose|lwindow' - else - " bufname && text - if a:strategy == 0 - call setqflist(filter(getqflist(), "(bufname(v:val['bufnr']) . v:val['text'] " . operator . " a:pat)"), "r") - endif + " only bufname + if a:strategy == 1 + let new_list = a:list->filter("bufname(v:val['bufnr']) " .. operator .. " a:pat") + endif - " only bufname - if a:strategy == 1 - call setqflist(filter(getqflist(), "bufname(v:val['bufnr']) " . operator . " a:pat"), "r") - endif + " only text + if a:strategy == 2 + let new_list = a:list->filter("v:val['text'] " .. operator .. " a:pat") + endif - " only text - if a:strategy == 2 - call setqflist(filter(getqflist(), "v:val['text'] " . operator . " a:pat"), "r") - endif + " range + if a:strategy == 3 + if a:reject + let current_list = a:list - " range - if a:strategy == 3 - let current_list = getqflist() - if a:reject - " remove range from list - call remove(current_list, a:range[0], a:range[1]) - call setqflist(current_list, "r") - else - " take range from list - call setqflist(remove(current_list, a:range[0], a:range[1]), "r") - endif - endif + " remove range from list + call current_list->remove(a:range[0], a:range[1]) - execute get(g:, "qf_auto_resize", 1) ? 'cclose|' . min([ max_height, len(getqflist()) ]) . 'cwindow' : 'cclose|cwindow' + let new_list = current_list + else + " take range from list + let new_list = a:list->remove(a:range[0], a:range[1]) endif endif + + return new_list endfunction function! s:AddList() - if exists("b:qf_isLoc") - if b:qf_isLoc == 1 - let locations = getwinvar(winnr("#"), "qf_location_lists") + if qf#IsLocWindow() + let locations = winnr("#")->getwinvar("qf_location_lists") - if len(locations) > 0 - call add(locations, getloclist(0)) - call setwinvar(winnr("#"), "qf_location_lists", locations) - else - call setwinvar(winnr("#"), "qf_location_lists", [getloclist(0)]) - endif + if !locations->empty() + call locations->add(qf#GetListItems(1)) + + call winnr("#")->setwinvar("qf_location_lists", locations) else - if exists("g:qf_quickfix_lists") - let g:qf_quickfix_lists = add(g:qf_quickfix_lists, getqflist()) - else - let g:qf_quickfix_lists = [getqflist()] - endif + call winnr("#")->setwinvar("qf_location_lists", [qf#GetListItems(1)]) + endif + endif + + if qf#IsQfWindow() + if exists("g:qf_quickfix_lists") + let g:qf_quickfix_lists = add(g:qf_quickfix_lists, qf#GetListItems()) + else + let g:qf_quickfix_lists = [qf#GetListItems()] endif endif endfunction @@ -137,34 +96,34 @@ endfunction " :grep foo sample.txt [reject: entry 13] function! s:SetTitle(pat, range, reject) " did we use :Keep or :Reject? - let action = a:reject == 0 ? 'keep' : 'reject' + let action = a:reject == 0 ? "keep" : "reject" " describe the filter that was applied if a:pat != '' - let filter = "'" . a:pat . "'" + let filter = "'" .. a:pat .. "'" else if a:range[0] == a:range[1] - let filter = 'entry ' . (a:range[0] + 1) + let filter = "entry " .. (a:range[0] + 1) else - let filter = 'entries ' . (a:range[0] + 1) . '..' . (a:range[1] + 1) + let filter = "entries " .. (a:range[0] + 1) .. ".." .. (a:range[1] + 1) endif endif - let str = " [" . action . ": " . filter . "]" + let str = " [" .. action .. ": " .. filter .. "]" - if exists("b:qf_isLoc") - if b:qf_isLoc == 1 - call s:SetTitleValue(getwinvar(winnr("#"), "qf_location_titles")[0] . str) - else - if exists("g:qf_quickfix_titles") - if len(g:qf_quickfix_titles) > 0 - call s:SetTitleValue(g:qf_quickfix_titles[0] . str) - else - call s:SetTitleValue(w:quickfix_title . str) - endif + if qf#IsLocWindow() + call s:SetTitleValue(winnr("#")->getwinvar("qf_location_titles")[0] .. str) + endif + + if qf#IsQfWindow() + if exists("g:qf_quickfix_titles") + if !g:qf_quickfix_titles->empty() + call s:SetTitleValue(g:qf_quickfix_titles[0] .. str) else - call s:SetTitleValue(w:quickfix_title . str) + call s:SetTitleValue(w:quickfix_title .. str) endif + else + call s:SetTitleValue(w:quickfix_title .. str) endif endif endfunction @@ -175,35 +134,32 @@ endfunction function! s:SetTitleValue(title) let w:quickfix_title = a:title " Update the quickfix/location list title if this Vim supports it - if has('patch-7.4.2200') - if b:qf_isLoc == 1 - noautocmd call setloclist(0, [], 'a', {'title': a:title}) - else - noautocmd call setqflist([], 'a', {'title': a:title}) - endif + if qf#IsLocWindow() + noautocmd call setloclist(0, [], "a", {"title": a:title}) + endif + + if qf#IsQfWindow() + noautocmd call setqflist([], "a", {"title": a:title}) endif endfunction " store the current title function! s:AddTitle(title) - if exists("b:qf_isLoc") - if b:qf_isLoc == 1 - let titles = getwinvar(winnr("#"), "qf_location_titles") + if qf#IsLocWindow() + let titles = winnr("#")->getwinvar("qf_location_titles") - if len(titles) > 0 - call add(titles, a:title) - call setwinvar(winnr("#"), "qf_location_titles", titles) - else - call setwinvar(winnr("#"), "qf_location_titles", [a:title]) - endif + if !titles->empty() + call titles->add(a:title) + + call winnr("#")->setwinvar("qf_location_titles", titles) else - if exists("g:qf_quickfix_titles") - let g:qf_quickfix_titles = add(g:qf_quickfix_titles, a:title) - else - let g:qf_quickfix_titles = [a:title] - endif + call winnr("#")->setwinvar("qf_location_titles", [a:title]) endif endif + + if qf#IsQfWindow() + let g:qf_quickfix_titles = get(g:, "qf_quickfix_titles", [])->add(a:title) + endif endfunction function! s:GetSelection() @@ -211,30 +167,32 @@ function! s:GetSelection() normal! gv"vy let raw_search = getreg("v") call setreg("v", old_reg) - return substitute(escape(raw_search, '\/.*$^~[]'), "\n", '\\n', "g") + return raw_search + \ ->escape('\/.*$^~[]') + \ ->substitute("\n", '\\n', "g") endfunction " filter the current list function! qf#filter#FilterList(pat, reject, lnum1, lnum2, cnt) - let strategy = get(g:, 'qf_bufname_or_text', 0) - let pat = '' + let strategy = get(g:, "qf_bufname_or_text", 0) + let pat = "" let range = [] - if a:pat != '' + if a:pat != "" let pat = a:pat else if a:cnt == -1 " no range was given " :Reject - if col('.') == 1 - if get(g:, 'qf_shorten_path', 1) - let pat = split(split(getline('.'), '|')[0], '/')[-1] + if col(".") == 1 + if get(g:, "qf_shorten_path", 1) + let pat = split(split(getline("."), "|")[0], "/")[-1] else - let pat = split(getline('.'), '|')[0] + let pat = split(getline("."), "|")[0] endif let strategy = 1 else - let pat = expand('') + let pat = expand("") let strategy = 2 endif else @@ -247,44 +205,55 @@ function! qf#filter#FilterList(pat, reject, lnum1, lnum2, cnt) endif endif - if exists("b:qf_isLoc") + if qf#IsLocWindow() || qf#IsQfWindow() call s:AddList() - call s:AddTitle(get(w:, 'quickfix_title', ' ')) + call s:AddTitle(get(w:, "quickfix_title", " ")) - call s:SetList(pat, range, a:reject, strategy) + call qf#GetListItems(qf#IsLocWindow(), 0) + \ ->s:FilteredList(pat, range, a:reject, strategy) + \ ->s:ReplaceList(qf#IsLocWindow()) call s:SetTitle(pat, range, a:reject) - call s:AddTitle(get(w:, 'quickfix_title', ' ')) + call s:AddTitle(get(w:, "quickfix_title", " ")) endif endfunction +function! s:ReplaceList(new_list, loc) + if a:loc == 1 + call setloclist(0, a:new_list, "r") + else + call setqflist(a:new_list, "r") + endif + + call qf#OpenWindow(a:loc) +endfunction + " restore the original list function! qf#filter#RestoreList() - " get user-defined maximum height - let max_height = get(g:, 'qf_max_height', 10) < 1 ? 10 : get(g:, 'qf_max_height', 10) + if qf#IsLocWindow() + let lists = winnr("#")->getwinvar("qf_location_lists") - if exists("b:qf_isLoc") - if b:qf_isLoc == 1 - let lists = getwinvar(winnr("#"), "qf_location_lists") + if !lists->empty() + call setloclist(0, winnr("#")->getwinvar("qf_location_lists")[0], "r") - if len(lists) > 0 - call setloclist(0, getwinvar(winnr("#"), "qf_location_lists")[0], "r") - execute get(g:, "qf_auto_resize", 1) ? 'lclose|' . min([ max_height, len(getloclist(0)) ]) . 'lwindow' : 'lwindow' + call qf#OpenWindow(1) - call s:SetTitleValue(getwinvar(winnr("#"), "qf_location_titles")[0]) - else - echo "No filter applied. Nothing to restore." - endif + call s:SetTitleValue(winnr("#")->getwinvar("qf_location_titles")[0]) else - if exists("g:qf_quickfix_lists") - if len(g:qf_quickfix_lists) > 0 - call setqflist(g:qf_quickfix_lists[0], "r") - execute get(g:, "qf_auto_resize", 1) ? 'cclose|' . min([ max_height, len(getqflist()) ]) . 'cwindow' : 'cwindow' + echo "No filter applied. Nothing to restore." + endif + endif - call s:SetTitleValue(g:qf_quickfix_titles[0]) - else - echo "No filter applied. Nothing to restore." - endif + if qf#IsQfWindow() + if exists("g:qf_quickfix_lists") + if !g:qf_quickfix_lists->empty() + call setqflist(g:qf_quickfix_lists[0], "r") + + call qf#OpenWindow(0) + + call s:SetTitleValue(g:qf_quickfix_titles[0]) + else + echo "No filter applied. Nothing to restore." endif endif endif @@ -294,28 +263,12 @@ endfunction " replace the current title function! qf#filter#ReuseTitle() - if exists("b:qf_isLoc") - if b:qf_isLoc == 1 - if has('patch-7.4.2200') - let w:quickfix_title = getloclist(0, {'title': 0}).title - else - let titles = getwinvar(winnr("#"), "qf_location_titles") + if qf#IsLocWindow() + let w:quickfix_title = qf#GetListTitle(1) + endif - if len(titles) > 0 - let w:quickfix_title = getwinvar(winnr("#"), "qf_location_titles")[0] - endif - endif - else - if has('patch-7.4.2200') - let w:quickfix_title = getqflist({'title': 0}).title - else - if exists("g:qf_quickfix_titles") - if len(g:qf_quickfix_titles) > 0 - let w:quickfix_title = g:qf_quickfix_titles[0] - endif - endif - endif - endif + if qf#IsQfWindow() + let w:quickfix_title = qf#GetListTitle() endif endfunction diff --git a/autoload/qf/format.vim b/autoload/qf/format.vim new file mode 100644 index 0000000..20476e2 --- /dev/null +++ b/autoload/qf/format.vim @@ -0,0 +1,63 @@ +" vim-qf - Tame the quickfix window +" Maintainer: romainl +" Version: 0.2.0 +" License: MIT +" Location: autoload/qf/format.vim +" Website: https://github.com/romainl/vim-qf + +let s:save_cpo = &cpo +set cpo&vim + +function! qf#format#FormatItem(item) + return [ + \ a:item->FormatFilename(), + \ a:item->FormatPosition(), + \ a:item->FormatText(), + \ ]->join("|") +endfunction + +function! s:FormatFilename(item) + let filename = a:item["bufnr"]->bufname() + + if has("patch-8.2.1741") + return pathshorten(filename, g:->get("qf_shorten_path", 1)) + else + return pathshorten(filename) + endif +endfunction + +function! s:FormatPosition(item) + return [ + \ a:item->get("lnum", 0)->FormatLineNumber(), + \ a:item->get("col", 0)->FormatColumn(), + \ a:item->get("type", "")->FormatType(), + \ a:item->get("nr", 0)->FormatErrorNumber(), + \ ]->join("") +endfunction + +function! s:FormatText(item) + return " " .. a:item->get("text", "") +endfunction + +function! s:FormatLineNumber(lnum) + return a:lnum != 0 ? a:lnum : "" +endfunction + +function! s:FormatColumn(col) + return a:col > 0 ? " col " .. a:col : "" +endfunction + +function! s:FormatType(type) + return { + \ "e": " error", + \ "i": " info", + \ "n": " note", + \ "w": " warning" + \ }->get(a:type, "") +endfunction + +function! s:FormatErrorNumber(nr) + return a:nr > 0 ? " " .. printf("%3d", a:nr) : "" +endfunction + +let &cpo = s:save_cpo diff --git a/autoload/qf/preview.vim b/autoload/qf/preview.vim index 27ec033..e1b8d31 100644 --- a/autoload/qf/preview.vim +++ b/autoload/qf/preview.vim @@ -21,16 +21,22 @@ set cpo&vim " open the current entry in th preview window function! qf#preview#PreviewFileUnderCursor() - let cur_list = qf#GetList() - let cur_line = getline(line('.')) - let cur_file = fnameescape(qf#GetEntryPath(cur_line)) + let winview = winsaveview() - if cur_line =~ '|\d\+' - let cur_pos = substitute(cur_line, '^\(.\{-}|\)\(\d\+\)\(.*\)', '\2', '') - execute "pedit +" . cur_pos . " " . cur_file + let current_item = qf#GetListItems(b:->get("qf_isLoc", 0), line('.'))[0] + let current_file_name = current_item["bufnr"]->bufname() + let current_file_line = current_item->get('lnum', 0) + let current_file_column = current_item->get('col', 0) + + if current_file_line && current_file_column + execute "pedit +" .. current_file_line .. " " .. current_file_name .. "|normal! " .. current_file_column .. "G" + elseif current_file_line && !current_file_column + execute "pedit +" .. current_file_line .. " " .. current_file_name else - execute "pedit " . cur_file + execute "pedit " .. current_file_name endif + + call winrestview(winview) endfunction let &cpo = s:save_cpo diff --git a/autoload/qf/statusline.vim b/autoload/qf/statusline.vim index bd925f3..3caeba6 100644 --- a/autoload/qf/statusline.vim +++ b/autoload/qf/statusline.vim @@ -30,7 +30,7 @@ function! qf#statusline#SetStatusline() let titles = get(g:, 'qf_quickfix_titles', []) endif - if len(titles) > 0 + if !titles->empty() return titles[-1] endif diff --git a/autoload/qf/toggle.vim b/autoload/qf/toggle.vim index 263e02c..68ad618 100644 --- a/autoload/qf/toggle.vim +++ b/autoload/qf/toggle.vim @@ -4,22 +4,11 @@ " License: MIT " Location: autoload/toggle.vim " Website: https://github.com/romainl/vim-qf -" -" Use this command to get help on vim-qf: -" -" :help qf -" -" If this doesn't work and you installed vim-qf manually, use the following -" command to index vim-qf's documentation: -" -" :helptags ~/.vim/doc -" -" or read your runtimepath/plugin manager documentation. let s:save_cpo = &cpo set cpo&vim -" toggles the quickfix window +" Toggles the quickfix window. function! qf#toggle#ToggleQfWindow(stay) abort " save the view if the current window is not a quickfix window if get(g:, 'qf_save_win_view', 1) && !qf#IsQfWindow(winnr()) @@ -28,9 +17,6 @@ function! qf#toggle#ToggleQfWindow(stay) abort let winview = {} endif - " get user-defined maximum height - let max_height = get(g:, 'qf_max_height', 10) < 1 ? 10 : get(g:, 'qf_max_height', 10) - " if one of the windows is a quickfix window close it and return if qf#IsQfWindowOpen() cclose @@ -38,7 +24,7 @@ function! qf#toggle#ToggleQfWindow(stay) abort call winrestview(winview) endif else - execute get(g:, 'qf_auto_resize', 1) ? min([ max_height, len(getqflist()) ]) . 'cwindow' : max_height . 'cwindow' + call qf#OpenQuickfixWindow() if qf#IsQfWindowOpen() wincmd p if !empty(winview) @@ -51,26 +37,23 @@ function! qf#toggle#ToggleQfWindow(stay) abort endif endfunction -" toggles the location window associated with the current window -" or whatever location window has the focus +" Toggles the location window associated with the current window +" or whatever location window has the focus. function! qf#toggle#ToggleLocWindow(stay) abort " save the view if the current window is not a location window - if get(g:, 'qf_save_win_view', 1) && !qf#IsLocWindow(winnr()) + if get(g:, 'qf_save_win_view', 1) && qf#IsLocWindow(winnr()) let winview = winsaveview() else let winview = {} endif - " get user-defined maximum height - let max_height = get(g:, 'qf_max_height', 10) < 1 ? 10 : get(g:, 'qf_max_height', 10) - if qf#IsLocWindowOpen(0) lclose if !empty(winview) call winrestview(winview) endif else - execute get(g:, 'qf_auto_resize', 1) ? min([ max_height, len(getloclist(0)) ]) . 'lwindow' : max_height . 'lwindow' + call qf#OpenLocationWindow() if qf#IsLocWindowOpen(0) wincmd p if !empty(winview) diff --git a/autoload/qf/wrap.vim b/autoload/qf/wrap.vim index b543780..10dca64 100644 --- a/autoload/qf/wrap.vim +++ b/autoload/qf/wrap.vim @@ -19,11 +19,7 @@ let s:save_cpo = &cpo set cpo&vim -" wrap around -" TODO (Nelo-T. Wallus): I actually don't know what this does -" TODO (romainl): Built-in :cn/:cp/:ln/:lp stop at the beginning -" and end of the list. This allows us to wrap -" around. +" Wrap :cn/:cp/:ln/:lp around function! qf#wrap#WrapCommand(direction, prefix) if a:direction == "up" try @@ -41,7 +37,7 @@ function! qf#wrap#WrapCommand(direction, prefix) endtry endif - if &foldopen =~ 'quickfix' && foldclosed(line('.')) != -1 + if &foldopen =~ 'quickfix' && line('.')->foldclosed() != -1 normal! zv endif endfunction diff --git a/doc/qf.txt b/doc/qf.txt index 2649a09..7e6e3b7 100644 --- a/doc/qf.txt +++ b/doc/qf.txt @@ -35,14 +35,12 @@ These "global" features are available from any window: |:grep|, |:lvimgrep| and friends if there are valid locations/errors - (optional) automatically set the height of location/quickfix windows to the number of list items if less than Vim's default height (10) or - the user's prefered height + the user's preferred height These "local" features are only available in location/quickfix windows: - disable relative numbers - filter and restore the current list - - perform commands on each line in the current list - - perform commands on each file in the current list - mappings to navigate between older and newer lists - jump to next group of entries belonging to same file ("file grouping") - save and load named lists @@ -58,40 +56,18 @@ Method 1 Method 2 - If you are using Vim 8.0 or above, move this directory to its appropriate - location. - - On Unix-like systems: > + Move this directory to its appropriate location. + On Unix-like systems: +> ~/.vim/pack/{whatever name you want}/start/vim-qf < - On Windows: > - + On Windows: +> %userprofile%\vimfiles\pack\{whatever name you want}\start\vim-qf < - See `:help package`. - -Method 3 - - If you are using Vim 7.4 or below, move the files in this directory to their - standard location. - - On Unix-like systems: > - - ~/.vim/after/ftplugin/qf.vim - ~/.vim/autoload/qf.vim - ~/.vim/autoload/qf/*.vim - ~/.vim/doc/qf.txt - ~/.vim/plugin/qf.vim -< - On Windows: > + See |package|. - %userprofile%\vimfiles\after\ftplugin\qf.vim - %userprofile%\vimfiles\autoload\qf.vim - %userprofile%\vimfiles\autoload\qf\*.vim - %userprofile%\vimfiles\doc\qf.txt - %userprofile%\vimfiles\plugin\qf.vim -< ============================================================================== 3. CONFIGURATION *qf-configuration* @@ -138,8 +114,8 @@ Default: none ~ Go up and down the quickfix list and wrap around. -Example: > - +Example: +> nmap (qf_qf_previous) nmap (qf_qf_next) < @@ -151,8 +127,8 @@ Default: none ~ Go up and down the current location list and wrap around. -Example: > - +Example: +> nmap (qf_loc_previous) nmap (qf_loc_next) < @@ -163,8 +139,8 @@ Default: none ~ Jump to and from location/quickfix windows. -Example: > - +Example: +> nmap ç (qf_qf_switch) < ------------------------------------------------------------------------------ @@ -175,8 +151,8 @@ Default: none ~ Toggle the quickfix window. Uses |:cwindow| and |:cclose| under the hood. -Example: > - +Example: +> nmap (qf_qf_toggle) < ------------------------------------------------------------------------------ @@ -187,8 +163,8 @@ Default: none ~ Toggle the quickfix window and do not move if toggled open. Uses |:cwindow| and |:cclose| under the hood. -Example: > - +Example: +> nmap (qf_qf_toggle_stay) < ------------------------------------------------------------------------------ @@ -199,8 +175,8 @@ Default: none ~ Toggle the current window's location window or the current location window. Uses |:lwindow| and |:lclose| under the hood. -Example: > - +Example: +> nmap (qf_loc_toggle) < ------------------------------------------------------------------------------ @@ -212,8 +188,8 @@ Toggle the current window's location window or the current location window and do not move if toggled open. Uses |:lwindow| and |:lclose| under the hood. -Example: > - +Example: +> nmap (qf_loc_toggle_stay) < ------------------------------------------------------------------------------ @@ -224,8 +200,8 @@ Default: none ~ In a location/quickfix window, navigate to an older or newer list. -Example (in after/ftplugin/qf.vim): > - +Example (in `after/ftplugin/qf.vim`): +> nmap (qf_older) nmap (qf_newer) < @@ -238,8 +214,8 @@ Default: none ~ In a location/quickfix window, jump to the next group of lines corresponding to a file. -Example (in after/ftplugin/qf.vim): > - +Example (in `after/ftplugin/qf.vim`): +> nmap { (qf_previous_file) nmap } (qf_next_file) < @@ -250,15 +226,15 @@ Default: 0 ~ Ack.vim-inspired mappings available only in location/quickfix windows: - s - open entry in a new horizontal window - v - open entry in a new vertical window - t - open entry in a new tab - o - open entry and come back - O - open entry and close the location/quickfix window - p - open entry in a preview window - -Add the line below to your vimrc to enable this feature: > + `s` ........ open entry in a new horizontal window + `v` ........ open entry in a new vertical window + `t` ........ open entry in a new tab + `o` ........ open entry and come back + `O` ........ open entry and close the location/quickfix window + `p` ........ open entry in a preview window +Add the line below to your vimrc to enable this feature: +> let g:qf_mapping_ack_style = 1 < ------------------------------------------------------------------------------ @@ -268,8 +244,8 @@ Default: 1 ~ Open the quickfix window at the bottom of the screen. -Add the line below to your vimrc to disable this feature: > - +Add the line below to your vimrc to disable this feature: +> let g:qf_window_bottom = 0 < ------------------------------------------------------------------------------ @@ -279,8 +255,8 @@ Default: 1 ~ Open location list windows at the bottom of the screen. -Add the line below to your vimrc to disable this feature: > - +Add the line below to your vimrc to disable this feature: +> let g:qf_loclist_window_bottom = 0 < ------------------------------------------------------------------------------ @@ -291,8 +267,8 @@ Default: {} ~ It is possible to define what comes before and after the default information displayed in the |'statusline'|. -Example: > - +Example: +> let g:qf_statusline = {} let g:qf_statusline.before = '%<\ ' let g:qf_statusline.after = '\ %f%=%l\/%-6L\ \ \ \ \ ' @@ -304,8 +280,8 @@ Default: 1 ~ Open the quickfix window automatically if there are any errors. -Add the line below to your vimrc to disable this feature: > - +Add the line below to your vimrc to disable this feature: +> let g:qf_auto_open_quickfix = 0 < ------------------------------------------------------------------------------ @@ -315,8 +291,8 @@ Default: 1 ~ Open the location window automatically if there are any locations. -Add the line below to your vimrc to disable this feature: > - +Add the line below to your vimrc to disable this feature: +> let g:qf_auto_open_loclist = 0 < ------------------------------------------------------------------------------ @@ -328,8 +304,8 @@ Automatically adjust the height of location/quickfix windows to 10 lines (Vim's default) or to the number of items in the list if that number is inferior to 10. -Add the line below to your vimrc to disable this feature: > - +Add the line below to your vimrc to disable this feature: +> let g:qf_auto_resize = 0 < ------------------------------------------------------------------------------ @@ -376,7 +352,7 @@ Default: 1 ~ Save the view of the current window when toggling location/quickfix window. -Add the line below to your vimrc to change the default value: +Add the line below to your vimrc to disable this feature: > let g:qf_save_win_view = 0 < @@ -388,7 +364,7 @@ Default: 1 ~ Enables or disables soft-wrapping in the location/quickfix window. The default value disables soft-wrapping. -Add the line below to your vimrc to change the default value: +Add the line below to your vimrc to disable this feature: > let g:qf_nowrap = 0 < @@ -403,110 +379,156 @@ window. With the option set to `0` (vanilla Vim): > very/long/path/with/lots/of/subdirectories/filename.ext|87 col 22| … - +< With the option set to `1` (vim-qf default): > v/l/p/w/l/o/s/filename.ext|87 col 22| … - -With the option set to `3` (Vim v8.2.1741 or above): +< +With the option set to `3`: > ver/lon/pat/wit/lot/of/sub/filename.ext|87 col 22| … +< +Etc. Add the line below to your vimrc to change the default value: > let g:qf_shorten_path = 0 < ============================================================================== - 4. USAGE *qf-usage* + 4. Filtering *qf-usage* -The following commands are available when the location/quickfix window -is focused: +When working with a location/quickfix list, it might be useful to remove false +potives, for example, before further operation. vim-qf exposes three hopefully +intuitive commands to help in that scenario: |:Keep|, |:Reject|, and +|:Restore| when the location/quickfix window is focused: *:Keep* Keep some entries from the list. - Example: > + Example: + + `:Keep model` ...... Keep entries matching 'model' + `:Keep` ............ Keep entries with same filename as curent entry + `:.Keep` ........... Keep current entry + `:10,15Keep` ....... Keep entries 10..15 + `:'<,'>Keep` ....... Keep entries covered by visual selection - :Keep model Keep entries matching 'model' - :Keep Keep entries with same filename as curent entry - :.Keep Keep current entry - :10,15Keep Keep entries 10..15 - :'<,'>Keep Keep entries covered by visual selection -< With a pattern, filtering is done by default on the buffer name AND the text. This can be changed with the |g:qf_bufname_or_text| option. If a [range] was given, it is ignored. + With a [range], the lines covered by [range] are kept. If a pattern was + given, it is ignored. + With neither a pattern nor a [range], filtering is done: - on the buffer name if the cursor is on column 1, - on the word under the cursor if the cursor is on any other column. - With a [range], the lines covered by [range] are kept. If a pattern was - given, it is ignored. - *:Reject* Reject some entries from the list. - Example: > + Examples: + + `:Reject model` .... Reject entries matching 'model' + `:Reject` .......... Reject entries with same filename as curent entry + `:.Reject` ......... Reject current entry + `:10,15Reject` ..... Reject entries 10..15 + `:'<,'>Reject` ..... Reject entries covered by visual selection - :Reject model Reject entries matching 'model' - :Reject Reject entries with same filename as curent entry - :.Reject Reject current entry - :10,15Reject Reject entries 10..15 - :'<,'>Reject Reject entries covered by visual selection -< With a pattern, filtering is done by default on the buffer name AND the text. This can be changed with the |g:qf_bufname_or_text| option. If a [range] was given, it is ignored. + With a [range], the lines covered by [range] are rejected. If a pattern + was given, it is ignored. + With neither a pattern nor a [range], filtering is done: - on the buffer name if the cursor is on column 1, - on the word under the cursor if the cursor is on any other column. - With a [range], the lines covered by [range] are rejected. If a pattern - was given, it is ignored. - *:Restore* - Restore the list to its original state. + Restore the list to its original state, before any |:Keep| or |:Reject|. -*:Doline* + Example: +> + :helpgrep gd + :Keep usr_ + :Reject 26 + :Restore +< +NOTE: In most cases it is possible to only type a few characters to +disembiguate commands. Assuming you don't already have custom commands with +clashing names, you can shorten the commands above to: - Execute an Ex command on every line in the current list. - Aliased to the built-in `:cdo` and `:ldo` when applicable. + |:Keep| ....................................... :K + |:Reject| ..................................... :Rej + |:Restore| .................................... :Res - Example: > +============================================================================== + 5. NAMED LISTS *qf-named-lists* + +While vim remembers the last ten quickfix/location lists and provides commands +to switch between them (|:colder|, |:lolder|, |:cnewer|, |:lnewer|), this doesn't +necessarily suffice and doesn't include changes made with |:Reject| et al. - :Doline s/^/-- +So vim-qf provides commands to save quickfix and location lists for later reuse +and concatenation. This can be handy to compose a long list of matches to act +on with |:cdo|, |:ldo| and family. + +These named lists share the same space, so a location list can be converted to +a quickfix list: > + + :SaveList current_loclist + :cwindow + :LoadList current_loclist < -*:Dofile* +Concatenating multiple location lists to use as a quickfix list: > - Execute an Ex command on every file in the current list. - Aliased to the built-in `:cfdo` and `:lfdo` when applicable. + :SaveListAdd current_loclist - Example: > +< in each location list you want to use, then > - :Dofile norm @q + :cwindow + :LoadList current_loclist < +Composing a list of files to attach a license to: > + + :grep _GNU_SOURCE + :Reject false_positives + :SaveListAdd floss_files + :grep POSIX_ME_HARDER + :Reject false_positives + :SaveListAdd floss_files + +< and so on... > + + :cwindow + :LoadList floss_files + :cdo 0r /path/to/license + +The following commands are available when the location/quickfix window +is focused: + *:SaveList* Save the current quickfix/location under the given name. If no name is supplied the last saved list is used. - Example: > - + Example: +> :SaveList curlist < *:SaveListAdd* Like |:SaveList|, but adds to an existing named list. - Example: > - + Example: +> :SaveListAdd curlist < *:LoadList* @@ -514,24 +536,24 @@ is focused: Replace the current quickfix/location list with one or more saved named lists. If no name is supplied, the last saved list is used. - Example: > - + Example: +> :LoadList curlist < *:LoadListAdd* Like |:LoadList|, but adds to an existing quickfix/location list. - Example: > - + Example: +> :LoadListAdd curlist < *:ListLists* List all currently saved lists. - Example: > - + Example: +> :ListLists curlist another_list @@ -540,15 +562,19 @@ is focused: Remove given lists. With a bang all saved lists are removed. + Example: +> + :ListLists + curlist + another_list + :RemoveList another_list + :ListLists + curlist +< NOTE: In most cases it is possible to only type a few characters to disembiguate commands. Assuming you don't already have custom commands with clashing names, you can shorten the commands above to: - |:Keep| ....................................... :K - |:Reject| ..................................... :Rej - |:Restore| .................................... :Res - |:Doline| ..................................... :Dol - |:Dofile| ..................................... :Dof |:SaveList| ................................... :SaveList |:SaveListAdd| ................................ :SaveListA |:LoadList| ................................... :LoadList @@ -556,48 +582,6 @@ clashing names, you can shorten the commands above to: |:ListLists| .................................. :ListL |:RemoveList| ................................. :Rem -============================================================================== - 5. NAMED LISTS *qf-named-lists* - -While vim remembers the last ten quickfix/location lists and provides commands -to switch between them (|:colder|, |:lolder|, |:cnewer|, |:lnewer|), this doesn't -necessarily suffice and doesn't include changes made with |:Reject| et al. - -So vim-qf provides commands to save quickfix and location lists for later reuse -and concatenation. This can be handy to compose a long list of matches to act -on with |:cdo|, |:ldo| and family. - -These named lists share the same space, so a location list can be converted to -a quickfix list: > - - :SaveList current_loclist - :cwindow - :LoadList current_loclist -< -Concatenating multiple location lists to use as a quickfix list: > - - :SaveListAdd current_loclist - -< in each location list you want to use, then > - - :cwindow - :LoadList current_loclist -< -Composing a list of files to attach a license to: > - - :grep _GNU_SOURCE - :Reject false_positives - :SaveListAdd floss_files - :grep POSIX_ME_HARDER - :Reject false_positives - :SaveListAdd floss_files - -< and so on... > - - :cwindow - :LoadList floss_files - :cdo 0r /path/to/license -< ============================================================================== 6. ACKNOWLEGEMENTS *qf-acknowledgements* @@ -605,14 +589,6 @@ The "Ack.vim-inspired mappings" are adapted from Ack.vim: - https://github.com/mileszs/ack.vim -|:Doline| and |:Dofile| are inspired by these online resources: - - - http://vimcasts.org/episodes/project-wide-find-and-replace/ - - https://github.com/nelstrom/vim-qargs - - https://github.com/henrik/vim-qargs - - http://stackoverflow.com/a/4793316/546861 - - http://stackoverflow.com/a/5686810/546861 - |:Keep| and |:Reject| are adapted from the answers in this thread: - http://stackoverflow.com/q/15406138/546861 diff --git a/doc/tags b/doc/tags index ee5a502..521dce6 100644 --- a/doc/tags +++ b/doc/tags @@ -11,8 +11,6 @@ 'g:qf_shorten_path' qf.txt /*'g:qf_shorten_path'* 'g:qf_statusline' qf.txt /*'g:qf_statusline'* 'g:qf_window_bottom' qf.txt /*'g:qf_window_bottom'* -:Dofile qf.txt /*:Dofile* -:Doline qf.txt /*:Doline* :Keep qf.txt /*:Keep* :ListLists qf.txt /*:ListLists* :LoadList qf.txt /*:LoadList* @@ -35,10 +33,6 @@ (qf_qf_switch) qf.txt /*(qf_qf_switch)* (qf_qf_toggle) qf.txt /*(qf_qf_toggle)* (qf_qf_toggle_stay) qf.txt /*(qf_qf_toggle_stay)* -QfHistoryNewer qf.txt /*QfHistoryNewer* -QfHistoryOlder qf.txt /*QfHistoryOlder* -QfNextFile qf.txt /*QfNextFile* -QfPreviousFile qf.txt /*QfPreviousFile* qf qf.txt /*qf* qf-acknowledgements qf.txt /*qf-acknowledgements* qf-configuration qf.txt /*qf-configuration* diff --git a/plugin/qf.vim b/plugin/qf.vim index 87c488c..26c41cd 100644 --- a/plugin/qf.vim +++ b/plugin/qf.vim @@ -4,19 +4,8 @@ " License: MIT " Location: plugin/qf.vim " Website: https://github.com/romainl/vim-qf -" -" Use this command to get help on vim-qf: -" -" :help qf -" -" If this doesn't work and you installed vim-qf manually, use the following -" command to index vim-qf's documentation: -" -" :helptags ~/.vim/doc -" -" or read your runtimepath/plugin manager documentation. - -if exists("g:loaded_qf") || v:version < 703 || &compatible + +if exists("g:loaded_qf") || v:version < 802 || &compatible finish endif let g:loaded_qf = 1 @@ -24,89 +13,77 @@ let g:loaded_qf = 1 let s:save_cpo = &cpo set cpo&vim -" Kept for backward compatibility -nmap QfCprevious (qf_qf_previous) -nmap QfCnext (qf_qf_next) -nmap QfLprevious (qf_loc_previous) -nmap QfLnext (qf_loc_next) -nmap QfCtoggle (qf_qf_toggle) -nmap QfLtoggle (qf_loc_toggle) -nmap QfSwitch &filetype ==# 'qf' ? 'p' : 'b' - -" Go up and down quickfix list +" Go up and down the quickfix list nnoremap (qf_qf_previous) : call qf#wrap#WrapCommand('up', 'c') nnoremap (qf_qf_next) : call qf#wrap#WrapCommand('down', 'c') -" Go up and down location list +" Go up and down the location list nnoremap (qf_loc_previous) : call qf#wrap#WrapCommand('up', 'l') nnoremap (qf_loc_next) : call qf#wrap#WrapCommand('down', 'l') -" Toggle quickfix list +" Toggle the quickfix window nnoremap (qf_qf_toggle) : call qf#toggle#ToggleQfWindow(0) nnoremap (qf_qf_toggle_stay) : call qf#toggle#ToggleQfWindow(1) -" Toggle location list +" Toggle the location window nnoremap (qf_loc_toggle) : call qf#toggle#ToggleLocWindow(0) nnoremap (qf_loc_toggle_stay) : call qf#toggle#ToggleLocWindow(1) -" Jump to and from list +" Jump to and from a location/quickfix window nnoremap (qf_qf_switch) &filetype ==# 'qf' ? 'p' : 'b' " A list of commands used to trigger the QuickFixCmdPost event is documented in " `:help QuickFixCmdPre`. " NOTE: helgrep is excluded because it's a special case (see below). -let s:quickfix_autocmd_trigger_cmds = [ - \ 'make', 'grep', 'grepadd', 'vimgrep', 'vimgrepadd', 'cfile', 'cgetfile', - \ 'caddfile', 'cexpr', 'cgetexpr', 'caddexpr', 'cbuffer', - \ 'cgetbuffer', 'caddbuffer'] - -function! s:GetQuickFixCmdsPattern() abort - return join(s:quickfix_autocmd_trigger_cmds, ',') -endfunction - -function! s:GetLocListCmdsPattern() abort - let l:loclist_cmds = [] - - for l:qf_cmd in s:quickfix_autocmd_trigger_cmds - " If a commands starts with 'c', replace it with 'l'. Otherwise, prepend - " 'l'. - if l:qf_cmd[0] is# 'c' - let l:cmd = 'l' . l:qf_cmd[1:] - else - let l:cmd = 'l' . l:qf_cmd - endif - call add(l:loclist_cmds, l:cmd) - endfor - - return join(l:loclist_cmds, ',') -endfunction +let s:qf_autocmd_triggers = [ + \ "cbuffer", "cgetbuffer", "caddbuffer", + \ "cexpr", "cgetexpr", "caddexpr", + \ "cfile", "cgetfile", "caddfile", + \ "grep", "grepadd", + \ "make", + \ "vimgrep", "vimgrepadd", + \ ]->join(",") + +let s:loc_autocmd_triggers = [ + \ "lbuffer", "lgetbuffer", "laddbuffer", + \ "lexpr", "lgetexpr", "laddexpr", + \ "lfile", "lgetfile", "laddfile", + \ "lgrep", "grepadd", + \ "lmake", + \ "lvimgrep", "lvimgrepadd", + \ ]->join(",") augroup qf autocmd! - " automatically open the location/quickfix window after :make, :grep, + " Automatically open the location/quickfix window after :make, :grep, " :lvimgrep and friends if there are valid locations/errors - exec printf('autocmd QuickFixCmdPost %s nested call qf#OpenQuickfix()', s:GetQuickFixCmdsPattern()) - exec printf('autocmd QuickFixCmdPost %s nested call qf#OpenLoclist()', s:GetLocListCmdsPattern()) + execute "autocmd QuickFixCmdPost " .. s:qf_autocmd_triggers .. " nested call qf#OpenQuickfixWindow()" + execute "autocmd QuickFixCmdPost " .. s:loc_autocmd_triggers .. " nested call qf#OpenLocationWindow()" - " special case for :helpgrep and :lhelpgrep since the help window may not + " Special case for :helpgrep and :lhelpgrep since the help window may not " be opened yet when QuickFixCmdPost triggers if exists('*timer_start') - autocmd QuickFixCmdPost helpgrep nested call timer_start(10, { -> execute('call qf#OpenQuickfix()') }) - autocmd QuickFixCmdPost lhelpgrep nested call timer_start(10, { -> execute('call qf#OpenLoclist()') }) + autocmd QuickFixCmdPost helpgrep nested call timer_start(10, { -> execute('call qf#OpenQuickfixWindow()') }) + autocmd QuickFixCmdPost lhelpgrep nested call timer_start(10, { -> execute('call qf#OpenLocationWindow()') }) else - " the window qf is not positioned correctly but at least it's there - autocmd QuickFixCmdPost helpgrep nested call qf#OpenQuickfix() + " The window qf is not positioned correctly but at least it's there + autocmd QuickFixCmdPost helpgrep nested call qf#OpenQuickfixWindow() " I can't make it work for :lhelpgrep endif - " spacial case for $ vim -q - autocmd VimEnter * nested if count(get(v:, 'argv', []), '-q') | call qf#OpenQuickfix() | endif + " Special case for $ vim -q + autocmd VimEnter * nested if get(v:, 'argv', [])->count('-q') | call qf#OpenQuickfixWindow() | endif - " automatically close corresponding loclist when quitting a window + " Automatically close corresponding loclist when quitting a window if exists('##QuitPre') autocmd QuitPre * nested if &filetype != 'qf' | silent! lclose | endif endif augroup END +" Handle formatting if possible +if exists('+quickfixtextfunc') && get(g:, "qf_shorten_path", 1) + set quickfixtextfunc=qf#QuickfixTextFunc +endif + let &cpo = s:save_cpo