6

I have the habit of leaving comments in my C source files like // @TODO or // @CHECK to quickly be able to get back to where I may have things to do. I can already match those in pretty much any language with vimgrep and get them in the quickfix list.

However, they're all a bit different and/or anywhere in a particular line: some are TODOs, some are CHECKs, and others may anything else. The quickfix list unfortunately lists them in no useful order, and to get the "type" (the few capital letters after the @) I sometimes have to look at all the line if the pattern is near the end.

What I'd like to do is "add a column" to the quickfix list that displays that "type" (so, for @CHECK it would be CHECK, and so on), and to be able to filter this to keep only one "type" (so maybe keep only FIXME or only TODO). If possible, I'd also like to sort this list alphabetically according to the type.

I have dug a bit, and it seems it may not be possible with the quickfix list, but I don't really know that many plugins. It also seems to be a use case for tags, but likewise, I don't really know how I could generate and update a list of those particular tags and add a column to the quickfix to show the "tag name".

Would I need a plugin to do this ? Could you point me to a particular one, maybe with a few configuration tips ?

Many thanks in advance !

3
  • I am not sure the quicklist can be changed, but would a command allowing you to search to a specific pattern (or by default to all of them) fit your need?
    – padawin
    May 13, 2019 at 14:16
  • In fact, I already have that. The current command I use is vimgrep #@\u\+#j **, which seems to do the trick for now. I guess I can write a function that searches for only one type is easy enough to do, too. The main problem here is just convenience ^^ I'd really like to find out how to get more customizable lists. May 13, 2019 at 14:20
  • I understand. I would have had a function and handful of mappings to help, but it would be solving the part you know how to do, not to actually change the list (or its format) :-/
    – padawin
    May 13, 2019 at 14:48

1 Answer 1

5

What I'd like to do is "add a column" to the quickfix list that displays that "type" (so, for @CHECK it would be CHECK, and so on)

An input file and the desired quickfix window would have helped, but try to source this code:

com -bar QfTodo call s:qf_todo()

fu s:qf_todo() abort
    sil vim /@\u\+/gj %
    let curfile = expand('%:p')
    call setqflist([], 'r', #{
        \ lines : getqflist()->map('curfile .. "|" .. v:val.lnum .. " " .. v:val.col .. "|" .. v:val.text'),
        \ efm : '%f|%l %c|%m',
        \ quickfixtextfunc : 's:quickfixtextfunc',
        \ })
    copen
endfu

fu s:quickfixtextfunc(info) abort
    if a:info.quickfix
        let qfl = getqflist(#{id: a:info.id, items: 1}).items
    else
        let qfl = getloclist(a:info.winid, #{id: a:info.id, items: 1}).items
    endif
    let l = []
    for idx in range(a:info.start_idx - 1, a:info.end_idx - 1)
        let e = qfl[idx]
        let fname = bufname(e.bufnr)->fnamemodify(':t')
        let displayed = printf('%s|%d col %d|%s| %s',
            \ fname,
            \ e.lnum,
            \ e.col,
            \ matchstr(e.text, '@\zs\u\+'),
            \ e.text
            \ )
        call add(l, displayed)
    endfor
    call sort(l, function('s:MySort'))
    return l
endfu

fu s:MySort(i, j) abort
    let s1 = split(a:i, '|')[2]
    let s2 = split(a:j, '|')[2]
    return s1 ==# s2 ? 0 : s1 ># s2 ? 1 : -1
endfu

It requires the patches 8.2.0869 and 8.2.0959, which provide the global option 'quickfixtextfunc', as well as a quickfix list attribute with the same name.

Now assuming your file is displayed in the current window, run this command to populate the quickfix list with all the lines containing an @ character followed by a sequence of uppercase alphabetic characters (like CHECK, FIXME, or TODO):

:QfTodo

and to be able to filter this to keep only one "type" (so maybe keep only FIXME or only TODO).

Load the default cfilter plugin:

:packadd cfilter

Then, run this command to only keep the TODOs:

:Cfilter TODO

Or this command to only keep the FIXMEs:

:Cfilter FIXME

Or this command to only keep the CHECKs:

:Cfilter CHECK

If possible, I'd also like to sort this list alphabetically according to the type.

This should be done by the call to sort() in the previous s:quickfixtextfunc() function.

call sort(l, function('s:MySort'))

If you care about speed, here is the same code rewritten in Vim9 script:

vim9script

com -bar QfTodo QfTodo()

def QfTodo()
    sil! vim /@\u\+/gj %
    var curfile: string = expand('%:p')
    setqflist([], 'r', {
        lines: getqflist()
            ->mapnew((_, v: dict<any>): string =>
                curfile .. '|' .. v.lnum .. ' ' .. v.col .. '|' .. v.text),
        efm: '%f|%l %c|%m',
        quickfixtextfunc: 'QuickfixTextFunc',
        })
    copen
enddef

def QuickfixTextFunc(info: dict<number>): list<string>
    var qfl: list<any>
    if info.quickfix
        qfl = getqflist({id: info.id, items: 1}).items
    else
        qfl = getloclist(info.winid, {id: info.id, items: 1}).items
    endif
    var l: list<string> = []
    for idx in range(info.start_idx - 1, info.end_idx - 1)
        var e: dict<any> = qfl[idx]
        var fname: string = bufname(e.bufnr)->fnamemodify(':t')
        var displayed: string = printf('%s|%d col %d|%s| %s',
            fname,
            e.lnum,
            e.col,
            matchstr(e.text, '@\zs\u\+'),
            e.text
            )
        add(l, displayed)
    endfor
    sort(l, MySort)
    return l
enddef

def MySort(i: string, j: string): number
    var s1: string = split(i, '|')[2]
    var s2: string = split(j, '|')[2]
    return s1 == s2 ? 0 : s1 > s2 ? 1 : -1
enddef

On my machine, it seems to be about twice as fast. This requires a recent Vim version. It works on 8.2.2332.


For more info, see:

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.