├── README.md ├── after ├── ftplugin │ └── qf.vim └── syntax │ └── qf.vim ├── autoload └── kickfix.vim ├── doc └── kickfix.txt ├── ftplugin └── qf.vim └── plugin └── kickfix.vim /README.md: -------------------------------------------------------------------------------- 1 | Vim-Kickfix 2 | ------------ 3 | 4 | > _Kick it till it's fixed._ 5 | 6 | Kickfix lets you filter, discard and save entries from the quickfix list. 7 | 8 | It's a simple but reasonably effective tool to shape the quickfix as you like, 9 | discarding unwanted matches and possibly saving it once you're done. 10 | 11 | [![asciicast](https://asciinema.org/a/iIfNKV7cK1UqdBnSAhoZksNLe.png)](https://asciinema.org/a/iIfNKV7cK1UqdBnSAhoZksNLe) 12 | 13 | It also provides "zebra-striped" syntax highlighting and folding, grouping 14 | lines by file. 15 | 16 | Usage 17 | ------ 18 | See [the documentation](doc/kickfix.txt). 19 | 20 | Installation 21 | ------------- 22 | Use your favorite method: 23 | * [Pathogen][1] - git clone https://github.com/fcpg/vim-kickfix ~/.vim/bundle/vim-kickfix 24 | * [NeoBundle][2] - NeoBundle 'fcpg/vim-kickfix' 25 | * [Vundle][3] - Plugin 'fcpg/vim-kickfix' 26 | * [Plug][4] - Plug 'fcpg/vim-kickfix' 27 | * manual - copy all files into your ~/.vim directory 28 | 29 | Pluginophobia 30 | -------------- 31 | If you don't like plugins, feel free to steal snippets into your vimrc. 32 | 33 | License 34 | -------- 35 | [Attribution-ShareAlike 4.0 Int.](https://creativecommons.org/licenses/by-sa/4.0/) 36 | 37 | [1]: https://github.com/tpope/vim-pathogen 38 | [2]: https://github.com/Shougo/neobundle.vim 39 | [3]: https://github.com/gmarik/vundle 40 | [4]: https://github.com/junegunn/vim-plug 41 | -------------------------------------------------------------------------------- /after/ftplugin/qf.vim: -------------------------------------------------------------------------------- 1 | " qf filetype - kickfix extensions 2 | 3 | let b:undo_ftplugin = "setl number< nowrap<" 4 | setl number nowrap 5 | -------------------------------------------------------------------------------- /after/syntax/qf.vim: -------------------------------------------------------------------------------- 1 | " Extra qf syntax 2 | 3 | if !get(g:, 'kickfix_zebra', 1) 4 | finish 5 | endif 6 | 7 | syn sync fromstart 8 | 9 | syn match qfFileName1 /^[^|]*/ nextgroup=qfSeparator contained 10 | syn match qfFileName2 /^[^|]*/ nextgroup=qfSeparator contained 11 | 12 | syn match qfZebraLineNr /|[^|]*|/ contains=qfSeparator,qfLineNr,qfError contained nextgroup=qfSkip 13 | syn match qfSkip /.*$/ excludenl contains=NONE transparent 14 | 15 | syn region qfZebra1 matchgroup=qfZebraStart1 start=/^\z([^|]\+\)/ end=/\n\(\z1|\)\@!/ nextgroup=qfZebra2 skipnl keepend fold contains=qfFileName1,qfZebraLineNr 16 | syn region qfZebra2 matchgroup=qfZebraStart2 start=/^\z([^|]\+\)/ end=/\n\(\z1|\)\@!/ nextgroup=qfZebra1 skipnl keepend fold contains=qfFileName2,qfZebraLineNr 17 | 18 | 19 | hi def qfZebra1 guibg=#222222 ctermbg=240 20 | hi def qfZebra2 guibg=#444444 ctermbg=244 21 | 22 | hi def link qfFileName1 qfZebra1 23 | hi def link qfFileName2 qfZebra2 24 | 25 | hi def link qfZebraStart1 qfFileName1 26 | hi def link qfZebraStart2 qfFileName2 27 | 28 | -------------------------------------------------------------------------------- /autoload/kickfix.vim: -------------------------------------------------------------------------------- 1 | " kickfix functions 2 | let s:save_cpo = &cpo 3 | set cpo&vim 4 | 5 | 6 | " Preview {{{1 7 | " open the current entry in the preview window 8 | function kickfix#Preview() abort 9 | let curline = getline(line('.')) 10 | let curfile = fnameescape(matchstr(curline, '^[^|]\+')) 11 | let curpos = curline =~ '|\d\+' 12 | \ ? "+".matchstr(curline, '|\zs\d\+') 13 | \ : "" 14 | exe "pedit" curpos curfile 15 | endfun 16 | 17 | " QFilterName {{{1 18 | " Filter in/out quickfix entries by filename 19 | function! s:FilterName(list, rx, filter_in) abort 20 | let newlist = [] 21 | let oldlist = a:list 22 | let [kept, removed, nobuf] = [0, 0, 0] 23 | for f in oldlist 24 | if !get(f, 'bufnr', 0) 25 | let nobuf += 1 26 | continue 27 | endif 28 | let bufname = bufname(f.bufnr) 29 | if (a:filter_in && match(bufname, a:rx) != -1) 30 | \ || (!a:filter_in && match(bufname, a:rx) == -1) 31 | call add(newlist, copy(f)) 32 | let kept += 1 33 | else 34 | let removed += 1 35 | endif 36 | endfor 37 | echom printf('Removed: %d, Kept: %d, Nobuf: %d', removed, kept, nobuf) 38 | return newlist 39 | endfunction 40 | 41 | function! kickfix#QFilterName(rx, filter_in) abort 42 | call setqflist(s:FilterName(getqflist(), a:rx, a:filter_in)) 43 | endfun 44 | 45 | function! kickfix#LocFilterName(rx, filter_in) abort 46 | call setloclist(0, s:FilterName(getloclist(0), a:rx, a:filter_in)) 47 | endfunction 48 | 49 | " QFilterContent {{{1 50 | " Filter in/out quickfix entries by content 51 | function! s:FilterContent(list, rx, filter_in) abort 52 | let newlist = [] 53 | let oldlist = a:list 54 | let [kept, removed, nobuf] = [0, 0, 0] 55 | let winid = win_getid() 56 | 1split 57 | for f in oldlist 58 | if !get(f, 'bufnr', 0) 59 | let nobuf += 1 60 | continue 61 | endif 62 | exe 'noauto b' f.bufnr 63 | if (a:filter_in && search(a:rx, 'wn')) 64 | \ || (!a:filter_in && !search(a:rx, 'wn')) 65 | call add(newlist, copy(f)) 66 | let kept += 1 67 | else 68 | let removed += 1 69 | endif 70 | endfor 71 | echom printf('Removed: %d, Kept: %d, Nobuf: %d', removed, kept, nobuf) 72 | close 73 | if win_id2win(winid) 74 | call win_gotoid(winid) 75 | endif 76 | return newlist 77 | endfunction 78 | 79 | function! kickfix#QFilterContent(rx, filter_in) abort 80 | call setqflist(s:FilterContent(getqflist(), a:rx, a:filter_in)) 81 | endfun 82 | 83 | function! kickfix#LocFilterContent(rx, filter_in) abort 84 | call setloclist(0, s:FilterContent(getloclist(0), a:rx, a:filter_in)) 85 | endfunction 86 | 87 | " QInfo {{{1 88 | " Print number of files and number of errors in the quickfix 89 | function! kickfix#QInfo() abort 90 | let curlist = !empty(getloclist(0)) ? getloclist(0) : getqflist() 91 | let files = empty(curlist) 92 | \ ? {} 93 | \ : eval('{'. 94 | \ join(uniq(map(copy(curlist),'v:val.bufnr'),'N'),':1,'). 95 | \ ':1}') 96 | 97 | echo printf("%d File(s), %d Line(s)", len(files), len(curlist)) 98 | endfunction 99 | 100 | " QDeleteLine {{{1 101 | " Remove line(s) from quickfix 102 | function! kickfix#QDeleteLine(...) abort 103 | let isloc = !empty(getloclist(0)) 104 | let curlist = isloc ? getloclist(0) : getqflist() 105 | if a:0 == 1 && type(a:1) == type("") 106 | " called from g@ 107 | let [l1, l2] = [line("'["), line("']")] 108 | elseif a:0 == 2 109 | " called from cmdline 110 | let [l1, l2] = [a:1, a:2] 111 | else 112 | echom "Argument error (kickfix#QDeleteLine)" 113 | return 114 | endif 115 | let curline = line('.') 116 | let newlist = copy(curlist) 117 | call remove(newlist, l1 - 1, l2 - 1) 118 | if isloc 119 | call setloclist(0, newlist) 120 | else 121 | call setqflist(newlist) 122 | endif 123 | call cursor(curline, 0) 124 | endfun 125 | 126 | " QLoad {{{1 127 | " Load saved quickfix buffer 128 | function! kickfix#QLoad(file, loc) abort 129 | let cmd = a:loc ? "lfile" : "cfile" 130 | let oldefm = &efm 131 | setlocal efm+=%f\|%l\ col\ %c\|%m 132 | exe cmd a:file 133 | let &efm = oldefm 134 | endfun 135 | 136 | " FoldText {{{1 137 | " Function for 'foldtext in quickfix 138 | function! kickfix#FoldText() abort 139 | let numlines = v:foldend - v:foldstart + 1 140 | let filename = matchstr(getline(v:foldstart), '[^|]*') 141 | let filelen = strchars(filename) 142 | 143 | if (&termencoding ==# 'utf-8' || &encoding ==# 'utf-8') && version >= 700 144 | let myfoldchar = '─' 145 | else 146 | let myfoldchar = '-' 147 | endif 148 | 149 | let spacer_left = repeat(myfoldchar, 4) 150 | let spacer_mid = repeat(myfoldchar, 5) 151 | let spacer_right = repeat(myfoldchar, 4) 152 | 153 | if filelen > 50 154 | " extract the last path components so that total length < 47 155 | let filename_end = strcharpart(filename, filelen - 47) 156 | let ssl = exists('+shellslash') ? &shellslash : '/' 157 | let filename_upto50 = "..." . matchstr(filename_end, ssl.'.*') 158 | else 159 | let filename_upto50 = filename 160 | endif 161 | 162 | let txt = printf("+%s %-50.50s %s (%4d lines) %s", 163 | \ spacer_left, filename_upto50, spacer_mid, numlines, spacer_right) 164 | return txt 165 | endfun 166 | 167 | let &cpo = s:save_cpo 168 | -------------------------------------------------------------------------------- /doc/kickfix.txt: -------------------------------------------------------------------------------- 1 | *kickfix.txt* Vim Quickfix Editing *kickfix* 2 | 3 | kickfix MANUAL 4 | 5 | 1. About kickfix |kickfix-about| 6 | 2. Quick Start |kickfix-quickstart| 7 | 3. Commands |kickfix-commands| 8 | 4. Plug Mappings |kickfix-plug-mappings| 9 | 5. Options |kickfix-options| 10 | 6. Highlight Groups |kickfix-hl| 11 | 7. Configuration Example |kickfix-example| 12 | 8. Changelog |kickfix-changelog| 13 | 9. Contribute |kickfix-contribute| 14 | A. License |kickfix-license| 15 | 16 | ============================================================================= 17 | ABOUT KICKFIX *kickfix-about* 18 | 19 | Kickfix lets you filter, discard and save entries from the quickfix list. 20 | 21 | Shape the quickfix as you like, discard unwanted matches and possibly 22 | save it for later use once you're done. 23 | 24 | Extra "zebra" highlighting and folding is provided for the quickfix buffer. 25 | 26 | ============================================================================= 27 | QUICK START *kickfix-quickstart* 28 | 29 | 1. Install the plugin Eg. with Pathogen: 30 | > 31 | cd ~/.vim/bundle && git clone https://github.com/fcpg/vim-kickfix 32 | < 33 | or using vim8 package management: 34 | > 35 | cd ~/.vim/pack/std/start && git clone https://github.com/fcpg/vim-kickfix 36 | < 37 | 2. Get a quickfix list, eg. with |:grep| or |:make| 38 | 39 | 3. Enable folding (`zi`) to fold lines from same files. 40 | 41 | 4. Delete lines with |d|{motion}, |dd| or |d| in visual mode. 42 | Filter in/out lines with |:QFilterName| or |:QFilterContent|. 43 | 44 | 5. Save the quickfix buffer content in a file; it can be loaded back with 45 | |:QLoad| 46 | 47 | ============================================================================= 48 | COMMANDS *kickfix-commands* 49 | 50 | :[range]QDeleteLine *:QDeleteLine* 51 | Delete lines from the quickfix buffer and the corresponding entries 52 | from the quickfix list. Also works for the location list. 53 | 54 | :QFilterName[!] {pattern} *:QFilterName* 55 | Keep only filenames matching {pattern} in the quickfix list. 56 | Discard them if [!]. 57 | 58 | :LocFilterName[!] {pattern} *:LocFilterName* 59 | Keep only filenames matching {pattern} in the location list. 60 | Discard them if [!]. 61 | 62 | :QFilterContent[!] {pattern} *:QFilterContent* 63 | Keep only files whose content matches {pattern} in the quickfix list. 64 | Discard them if [!]. 65 | 66 | :LocFilterContent[!] {pattern} *:LocFilterContent* 67 | Keep only files whose content matches {pattern} in the location list. 68 | Discard them if [!]. 69 | 70 | :QInfo *:QInfo* 71 | Show number of files and number of entries in the quickfix list. Also works 72 | for the location list. 73 | 74 | :QLoad {path} *:QLoad* 75 | Load quickfix from {path}. 76 | Quickfix content can be saved as is with `:w {path}`. Also works for the 77 | location list. 78 | 79 | ============================================================================= 80 | PLUG MAPPINGS *kickfix-plug-mappings* 81 | 82 | (KickfixPreview) 83 | Open quickfix entry in preview window. Buffer-local. 84 | Cf. |kickfix-example| 85 | 86 | ============================================================================= 87 | OPTIONS *kickfix-options* 88 | 89 | g:kickfix_zebra *g:kickfix_zebra* 90 | Set to zero to deactivate kickfix extra syntax highlighting. 91 | 92 | ============================================================================= 93 | HIGHLIGHT GROUPS *kickfix-hl* 94 | 95 | Kickfix provides extra highlighting for the quickfix buffer. 96 | Lines are "zebra-striped", grouped by file; thus there are two 97 | variants for each highlight group (dark/light, by default). 98 | 99 | qfZebra1 *hl-qfZebra1* 100 | qfZebra2 *hl-qfZebra2* 101 | All lines belonging to the same file. 102 | 103 | qfFileName1 *hl-qfFileName1* 104 | qfFileName2 *hl-qfFileName2* 105 | The filename, on each successive lines. 106 | 107 | qfqfZebraStart1 *hl-qfqfZebraStart1* 108 | qfqfZebraStart2 *hl-qfqfZebraStart2* 109 | The filename when it occurs for the first time. 110 | Default to qfFileName1 / qfFileName2. 111 | 112 | ============================================================================= 113 | CONFIGURATION EXAMPLE *kickfix-example* 114 | 115 | In .vim/after/ftplugin/qf.vim: 116 | > 117 | nmap p (KickfixPreview) 118 | nmap :QInfo 119 | < 120 | In .vim/vimrc: 121 | > 122 | hi link qfFileName1 Statement 123 | hi link qfFileName2 PreProc 124 | < 125 | ============================================================================= 126 | CHANGELOG *kickfix-changelog* 127 | 128 | [1.0] - 2018-06-29 129 | - Initial release 130 | 131 | ============================================================================= 132 | CONTRIBUTE *kickfix-contribute* 133 | 134 | Contribute on [Github](https://github.com/fcpg/vim-kickfix) 135 | 136 | ============================================================================= 137 | LICENSE *kickfix-license* 138 | 139 | [Attribution-ShareAlike 4.0 Int.](https://creativecommons.org/licenses/by-sa/4.0/) 140 | 141 | vim: set expandtab sts=2 ts=2 sw=2 tw=78 ft=help norl: 142 | -------------------------------------------------------------------------------- /ftplugin/qf.vim: -------------------------------------------------------------------------------- 1 | " qf filetype - kickfix extensions 2 | 3 | let b:undo_ftplugin = "setl number< nowrap< foldenable<" 4 | setl number nowrap 5 | setl foldtext=kickfix#FoldText() 6 | setl foldmethod=syntax nofoldenable 7 | 8 | nnoremap dd :QDeleteLine 9 | nnoremap d :set opfunc=kickfix#QDeleteLineg@ 10 | xnoremap d :QDeleteLine 11 | 12 | nnoremap (KickfixPreview) 13 | \ :call kickfix#Preview() 14 | -------------------------------------------------------------------------------- /plugin/kickfix.vim: -------------------------------------------------------------------------------- 1 | " kickfix.vim - quickfix editing 2 | 3 | command! -nargs=1 -bar -bang QFilterName 4 | \ call kickfix#QFilterName(, ''=='') 5 | command! -nargs=1 -bar -bang LocFilterName 6 | \ call kickfix#LocFilterName(, ''=='') 7 | 8 | command! -nargs=1 -bar -bang QFilterContent 9 | \ call kickfix#QFilterContent(, ''=='') 10 | command! -nargs=1 -bar -bang LocFilterContent 11 | \ call kickfix#LocFilterContent(, ''=='') 12 | 13 | command! -bar QInfo call kickfix#QInfo() 14 | 15 | command! -range -bar QDeleteLine 16 | \ call kickfix#QDeleteLine(, ) 17 | 18 | command! -bar -nargs=1 -complete=file QLoad 19 | \ call kickfix#QLoad(, 0) 20 | command! -bar -nargs=1 -complete=file LocLoad 21 | \ call kickfix#QLoad(, 1) 22 | 23 | --------------------------------------------------------------------------------