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.