Todo
highlight group currently highlights TODO
and FIXME
keywords. What do I do to add NOTE
, and possibley more keywords, to this existing highlight group, for all file types?
2 Answers
Add the following to your .vimrc:
fun! SetMyTodos()
syn match myTodos /\%(HABA:\)\|\%(NOTE:\)/
hi link myTodos Todo
endfu
autocmd bufenter * :call SetMyTodos()
autocmd filetype * :call SetMyTodos()
Restart. Then everytime you will set filetype (usually when you edit a file) or when you enter a buffer (:e newfile) it will add a myTodos
syntax that is highlighted as a Todo
.
It is just an example, though :)
-
-
-
You can also use syn keyword of course if you need just a words to be highlighted:
syn keyword myTodos MYXXX OTHERXXX ANOTHER
Commented Feb 28, 2019 at 15:40 -
1Does this highlight the keywords inside comments? I don't think so.– RalfCommented Feb 28, 2019 at 22:51
-
The highlight group Todo
just defines how a "todo" should be highlighted. What is actually highlighted by Todo
is defined by the syntax. For the C language, the expression is:
syn keyword cTodo contained TODO FIXME XXX
This defines the syntax group cTodo
, that contains the named keywords. This syntax group is later linked to highlight group Todo
with the following:
hi def link cTodo Todo
If you want to add an additional keyword to the cTodo
syntax group, you should create the file ~/.vim/after/syntax/c.vim
(~/vimfiles/after/syntax/c.vim
on Windows) with the following content:
" Add NOTE as todo keyword
syntax keyword cTodo contained NOTE
So this definition is syntax-specific. For python it would be pythonTodo
and the file would be ~.vim/after/syntax/python.vim
.
See :help :syn-keyword
and :help :syn-contained
.
Add-on: How do I delete a keyword from am syntax keyword group?
AFAIK, there is no way to do that directly. You have to clear the entire group and rebuild it. Like:
syntax clear cTodo
syntax keyword cTodo contained TODO FIXME NOTE
Add-on: How do I know how the "todo" syntax group is named for a given language?
Most likely it is <file-type>Todo
. To be sure, create a file of this language and add a "todo" comment. Move the cursor to the highlighted word and execute:
echo synIDattr(synID(line("."), col("."), 1), "name")
If you need to do that more than once, you might want to define a new command in Vim by adding the following to your vimrc
:
" Show name of syntax element below cursor
command! SynName echo synIDattr(synID(line("."), col("."), 1), "name")
Update: How to add "todo" keywords for all file types?
This is more complicated. Now you need a autocmd and a function to find the correct syntax groups and extend them.
Why is it important to add the new keywords to the existing definitions? Well, Vim syntax knows contained
and contains=...
. The "todo" syntax group is defined as contained
, that means, that it is only highlighted, when is is contained in another syntax group. On the other hand the syntax group(s) for comments is defined with contains=xxxTodo
, so "todos" are highlighted within comments.
Here you go:
function! UpdateTodoKeywords(...)
let newKeywords = join(a:000, " ")
let synTodo = map(filter(split(execute("syntax list"), '\n') , { i,v -> match(v, '^\w*Todo\>') == 0}), {i,v -> substitute(v, ' .*$', '', '')})
for synGrp in synTodo
execute "syntax keyword " . synGrp . " contained " . newKeywords
endfor
endfunction
augroup now
autocmd!
autocmd Syntax * call UpdateTodoKeywords("NOTE", "NOTES")
augroup END
The function UpdateTodoKeywords
is called whenever a syntax is loaded and adds the given keywords to all
"todo" syntax groups. You can add multiple names to the call to UpdateTodoKeywords
, as mutch as you want (but at least one).
Note that there are syntax definitions, that contain multiple definitions for "todo". E.g.
for Vim script files also python syntax is loaded, so it has vimTodo
and pythonTodo
.
The function is strait forward, except for the line let synTodo = map(...
. Here is what that line does:
- It lists all syntax items (
execute("syntax list")
) - Splits it into a list of lines (
split(..., '\n')
) - Filters it to only contain lines with syntax group name that ends with
Todo
(filter(..., { i,v -> match(v, '^\w*Todo\>') == 0})
) - Removes everything after syntax group name (
map(..., {i,v -> substitute(v, ' .*$', '', '')})
)
So the result of this is a list of syntax group names that end with Todo
.
Then for every syntax group name it adds the given keywords.
PS: This even works, if the "todo" syntax group is initially defined as syn-match
.
Finally: The "brute force attempt":
You could use the following:
autocmd Syntax * syntax keyword myTodo NOTE NOTES containedin=ALL | highlight def link myTodo TODO
This defines a new syntax group myTodo
that will be contained in every existing syntax group. So it will highlight "NOTE" and "NOTES" everywhere. In comments, in strings or if you use it as a variable name.
-
What if I want to add
NOTE
to all of the <filetype>Todo? I mean do I have to add all the filetypes by myself? And if so, then I think it would be simpler to define my ownsyn keyword
, how do I do that (also mention location of the file in this case)?– 3N4NCommented Feb 28, 2019 at 8:22 -
match, matchadd() wouldn't highlight the pattern for all windows, would it? Then I guess,
match
is not the answer.– 3N4NCommented Feb 28, 2019 at 8:51 -
-
Thanks. Your answer is really definitive, I learnt a lot. Sadly I've already selected the correct answer. Gave an upvote though.– 3N4NCommented Mar 1, 2019 at 18:12