9

Is it possible to add a sign to be displayed in the signs column whenever the line has a ToDo group (ToDo,FIXME...).

Tweaking my colorscheme I changed the highlight of the Todo group, but would like to have an indicator in the signs column, like Syntastic errors and warnings.

9

Try this function :

function! SignKeyword()

    silent! sign undefine todo

    sign define todo text=>> texthl=Search

    g/\v\C(<TODO>|<FIXME>)/execute "sign place 9999 line=" . line('.')
    \ . " name=todo buffer=" . bufnr('')

    nohlsearch

endfunction

Now call the function on the command line :

:call SignKeyword()

Or add a mapping in your ~/.vimrc to call it :

nnoremap <your mapping> :call SignKeyword()<cr>

Or add an autocmd. For example if you want the function to be called automatically when opening a file whose filetype is markdown :

autocmd FileType markdown call SignKeyword()

The first line of the function silent! sign undefine todo deletes the sign todo if it already exists, so that if your signs are misplaced after deleting or adding a line, you can recall the function to fix them immediately.


The second line defines a sign whose name is todo, whose text is >> (you can change it to suit your preferences) and which uses the Search highlighting group (same thing).


The third line uses the global command :

:g/pattern/command

The global command executes a command on every line that matches a pattern.

Here the pattern is \v\C(<TODO>|<FIXME>), which means any line containing either the word TODO or FIXME.
The regex includes the atom \C so that the search respects the case (no matter what your 'ignorecase' option is). If you want the search to not respect the case, change it to \c.

Whenever such a line is found the following line is executed by the function :

execute "sign place 9999 line=" . line('.')
    \ . " name=todo buffer=" . bufnr('')

It executes (with the :execute command) the content of the following string :

"sign place 9999 line=" . line('.') . " name=todo buffer=" . bufnr('')

The string includes two vim built-in functions : line() and bufnr().
line('.') returns the number of the current line when a match is found by the global command, and bufnr('.') returns the number of the current buffer.

So for example, if the global command finds a match on line 10 in the buffer 5, it will give :

"sign place 9999 line=" . 10 . " name=todo buffer=" . 5

The dots concatenate the strings, and so it will finally evaluate to :

"sign place 9999 line=10 name=todo buffer=5"

Which is the :sign command placing a sign on line 10 in buffer 5.
9999 is a random id chosen for the sign (you can choose another one).


The fourth line of the function :nohlsearch disables the highlighting of the matched patterns.

Edit : I fixed the regex, the original was wrong. I wrote ^[TODO|FIXME] but instead I think it should be \v\C(<TODO>|<FIXME>). Sorry for the inconvenience, I'm still learning vimscript.

  • 1
    how to remove the sign once the TODO comment has been removed? – user5235 Nov 12 '15 at 16:39
  • 1
    that's not what I expected, because that remove all the todo signs, but however just noticed that removing the line the sign is removed, so that's ok – user5235 Nov 12 '15 at 17:06
  • 1
    Ok, I've added this line at the beginning of the function : silent! sign undefine todo. It deletes the sign todo if it already exists, so that if your signs are misplaced after deleting a line containing the keyword TODO or FIXME, you can recall the function to fix them immediately. – saginaw Nov 12 '15 at 17:15
  • 2
    The regex was wrong, I typed ^[TODO|FIXME] but instead it should have been \v(TODO|FIXME). The new regex will match a line containing one of the keywords but not the beginning of the line, since I suppose a line could contain some code before a comment for example like this some code # FIXME this line needs to be fixed. The previous regex was completely wrong, sorry for the inconvenience, I'm still learning vimscript... – saginaw Nov 12 '15 at 21:02
  • 1
    The problem with this approach is, it will get quikly out of sync, if you modify the buffer, e.g. add another line above a TODO line. – Christian Brabandt Nov 14 '15 at 10:20
6

You can use my DynamicSigns plugin. This allows for so called "SignExpression" which are similar to the fold expression.

So you can simply do :SignExpression getline(v:lnum)=~'TODO'?'Warning':0

Read the help for more exmples of what is possible.

The advantage of using my plugin is, that it tracks changes of the buffer and adjusts the signs accordingly.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy