Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jumping to a Ruby bang method using Ctags in Vim

Tags:

vim

ruby

ctags

I'm having a problem with jumping to a Ruby bang method using Exhuberant Ctags. I have searched for others having a similar problem and am unable to find anything. An example of the problem can be shown using the following small Ruby class:

class Hello
  def start
    method!
  end

  def method
    # Blah
  end

  def method!
    # Blah
  end
end

When ctags -R . is run on this file the resulting tags file contains the following 2 lines demonstrating that both methods are discovered at generation:

method  test.rb /^  def method$/;"  f   class:Hello
method! test.rb /^  def method!$/;" f   class:Hello

However, if I place my cursor on the call to method! on line 3 and press ^] then the cursor jumps to the method definition rather than to the correct bang version. It seems as if the exclamation mark is not being included in the identifier that is searched for.

Is there a way to fix this so the correct method is jumped to?

like image 924
xoebus Avatar asked May 05 '12 02:05

xoebus


2 Answers

I realize this is super-old, but I ran into the same thing in both Vim 8.0 and Neovim. If I enter :tag mymethod! from vim's command-line, it finds the relevant tag, but if I try <C-]> with my cursor on the method name, it errors E426: tag not found: mymethod (note the lack of ! in the name it searched for).

You can fix this by adding ! to the list of characters recognized as keyword characters in Ruby syntax:

:set iskeyword+=!

You could add this to ~/.vim/after/syntax/ruby.vim to apply it in any Ruby file you open. I haven't tested this though, so can't say whether it will adversely affect anything else. I know it will change word jumping behavior. w will, for instance, treat the ! as part of the "small" word.

On second thought, it will definitely mishandle things like !some_test. If you were to hit <C-]> with the cursor anywhere in there, it would search for a method named !some_test, which is definitely not what you want. A better solution would be to write a wrapper function around the tag lookup for Ruby files. I'm actually working on something for that, so I'll post when I have something that presentable.

Update: I found a surprisingly simple workaround:

nnoremap <buffer><silent> <C-]> :tag <C-R><C-W><CR>

For some reason, the behavior of <C-R><C-W> in command-line mode differs from that of expand('<cword>'), and arguably from the documentation. Even though ! is not an 'iskeyword' character, and expand('<cword>') results in mymethod, <C-R><C-W> results in mymethod!. The same applies to is_this_your_method?. You could apply this workaround by putting the following in ~/.vim/ftplugin/ruby.vim:

nnoremap <buffer><silent>  <C-]> :tag     <C-R><C-W><CR>
nnoremap <buffer><silent>     g] :tselect <C-R><C-W><CR>
nnoremap <buffer><silent> g<C-]> :tjump   <C-R><C-W><CR>

Update 2

It turns out the special behavior of <C-R><C-W> was provided by vim-ruby (and included in Vim's runtime files by default). That script customizes <C-R><C-W> and also adds a <Plug><cword> mapping to correctly identify the Ruby cursor identifier. I only ran into the mishandling of ! because I had inadvertently clobbered the mappings already provided by vim-ruby when adding what I find to be more a comfortable keybinding:

nnoremap <C-.> <C-]>

If I'd done nmap instead, vim-ruby's mapping could have done its job. Alternatively, you could leverage what vim-ruby provides by doing (in a ruby ftplugin file):

nnoremap <buffer><silent>  <C-]> :<C-U>exe v:count1."tag <Plug><cword>"<CR>
nnoremap <buffer><silent>     g] :<C-U>tselect <Plug><cword><CR>
nnoremap <buffer><silent> g<C-]> :<C-U>tjump   <Plug><cword><CR>
like image 130
ivan Avatar answered Nov 13 '22 06:11

ivan


You can always use :tag:

  :tag method!

Or visual mode - if you highlight any text (with v + movement) before you hit ^], it will use the highlighted text as the tag instead of trying to find an 'identifier' under the cursor. So if your cursor is on the m in method!, then

   vE^]

should do the trick. If your cursor is elsewhere in the word, then hit b first.

like image 26
Mark Reed Avatar answered Nov 13 '22 04:11

Mark Reed