vimctagsuniversal-ctags

Ctags produces tags without parentheses after functions


Ctags produces a tags file without () after functions. As a result, Vim's Ctrl+] can't search for functions. How to fix this?

~/ $ cat example.hxx
bool function() {
    return true;
}
~/ $ ctags example.hxx
~/ $ cat tags | grep function
!_TAG_KIND_DESCRIPTION!C++      f,function      /function definitions/
function        example.hxx       /^bool function() {$/;" f       typeref:typename:bool
~/ $ vim -t "function()"
E426: Tag not found: function()
~/ $ ctags --fields=+l --extras=+q example.hxx
~/ $ cat tags | grep function
!_TAG_KIND_DESCRIPTION!C++      f,function      /function definitions/
function        example.hxx       /^bool function() {$/;" f       language:C++    typeref:typename:bool
~/ $ vim -t "function()"
E426: Tag not found: function()

All searches (+ Assistant) found were the options to add to ctags, which do not fix Vim use.

A possible solution is:

~/ $ sed "s/^\(\w\+\)\t/\1()\t/" -i"" tags
~/SubStack/tmp $ cat tags | grep function
!_TAG_KIND_DESCRIPTION!C++      f,function      /function definitions/
function()      example.hxx       /^bool function() {$/;" f       typeref:typename:bool
~/SubStack/tmp $ vim -t "function()"
example.hxx                                                                                                   4,0-1          All
"example.hxx" 4L, 35B

but this prevents such simple README.md instructions such as "Execute ctags -R . in the project root if you want Vim to jump to tags", as does:

~/ $ echo "\"nnoremap <C-]> :let stripped = expand(\"<cword>\")<CR>:execute \"tag \" . substitute(stripped, '()', '', 'g')<CR> \"`Tag not found: function()` fix" >> ~/.vimrc

It appears that if you use ~/.vimrc:setlocal iskeyword you cannot use ./tags. What to do?


Solution

  • The root cause of the problem is adding parentheses to Vim's 'iskeyword' option. This will not only cause the (intended) change of commands like w but will also make <C-]> pick up trailing parentheses for tag lookup.

    Changing the behavior of ctags or post-processing the tags file serves only to work around the original problem. Continue down this road and you'll have to compile your own ctags, only the compiler won't work so you need to change it as well, only it will not work on your OS so you need to change the kernel, only it doesn't run on your hardware so you need to build your own CPU ...

    Jokes aside, just don't change 'iskeyword'. There are some Vim options which I personally consider are "don't touch" options and 'iskeyword' is one of them.

    In your comment, you mention that you want to make w go by token. This has no meaning in Vim. Vim is a text editor, and words are a very convenient and natural unit in text; both of natural language and programming language.

    I'd strongly suggest to leave the w command as it is. It's just too useful.

    A token is something a compiler's parser would concern itself with. There may be some kind of plugin which might have access to a source code's syntax tree and thus enable movement by token. I wouldn't know such a plugin.

    If you want to, you can create a buffer-local mapping. I don't completely understand what you want to achieve but the following simple mapping may be a starting point:

    :noremap <buffer> <leader>w /[)}]<CR>
    

    Read :help mapping for the complete tour of mappings.

    For consistency, you might also want to create mappings for the complete zoo of W, e, E, b, B, etc.

    Although Vim does not care about tokens, chances are that it already offers a motion command that works for you. I'm thinking of % which will jump to the next matching parenthesis. See :help % and take a look at all of :help motion.txt.