7

Please note: I have been through this link Jump to CSS definition when editing HTML in VIM, but it couldn't help me.

I am looking to jump to the CSS definition or for that matter a javascript function from the html file. I would love to hit a key combo below the word to jump to its definition, not just the file in which the definition resides.

I currently need to search the word in opened buffers and then reach to all the search results in the required buffer. It is very time consuming.

Please help me with this very regular requirement.

Community
  • 1
  • 1
Gattoo
  • 3,019
  • 7
  • 25
  • 21

2 Answers2

8

This quick and dirty function seems to do the trick for *.html -> *.css:

function! JumpToCSS()
  let id_pos = searchpos("id", "nb", line('.'))[1]
  let class_pos = searchpos("class", "nb", line('.'))[1]

  if class_pos > 0 || id_pos > 0
    if class_pos < id_pos
      execute ":vim '#".expand('<cword>')."' **/*.css"
    elseif class_pos > id_pos
      execute ":vim '.".expand('<cword>')."' **/*.css"
    endif
  endif
endfunction

nnoremap <F9> :call JumpToCSS()<CR>
  • test.html

    <html>
      <body>
        <div class="foo" id="bar">lorem</div>
        <div id="bar" class="foo">ipsum</div>
        <div id="bar">dolor</div>
        <div class="foo">sit</div>
      </body>
    </html>
    
  • foo/foo.css

    .foo {
      background-color: red;
    }
    
  • bar/bar.css

    #bar {
      border-color: gold;
    }
    

With the cursor on any foo or bar attribute value in test.html, hitting <F9> jumps to the right definition in the right file. The function could be modified to open the target file in a split, search only the linked stylesheets… or be completely ridiculed and destroyed by ZyX ;-).

edit

A few additional pointers:

  • :help iskeyword for this function to work with dash-joined names
  • :help expand()
  • :help searchpos() and :help search() for the meanings of the arguments
  • :help starstar for the use of the ** wildcard
romainl
  • 186,200
  • 21
  • 280
  • 313
  • Thanks @romainl. Let me check this. How does it find the right css file? Does it need to be opened in a buffer? – Gattoo Oct 11 '12 at 08:59
  • 1
    `:vim '.foo' *.css` (`:vim` is short for `:vimgrep`) searches for `foo` in every CSS file in the working directory non-recursively. `**/` is added to tell vim to do the search recursively. It doesn't care about open buffers. – romainl Oct 11 '12 at 09:25
  • Works like charm for simple searches without '-', or '_' in a word, such as navbar-inner (even Vim's * under the word trick does not allow hyphens or underscore characters). Must build on to 'open the target in a new tab' as well as as search for entire word as default. It gives us insight into the powerful world of Vim scripting to get whatever you want. Thanks @romainl again. Your explanation of the script is awesome. – Gattoo Oct 12 '12 at 06:03
  • 1
    The dash is not included in `iskeyword` by default. You can add it explicitely with `set iskeyword+=-`. If you do that, temporarily in the function or in your vimrc, this function will work just as well with `navbar-inner` as with `navbar`. – romainl Oct 12 '12 at 07:19
  • Thanks @romainl. I think this is cool thing working out. This opens up all sorts of possibilities for intuitive search options and makes popular plugins like command-t or ctrlp look older. – Gattoo Oct 12 '12 at 10:02
  • 1
    I wouldn't cross out Command-T or CTrlP like that but Vim has a lot of cool tricks up its sleeve and, as you see, you can add your own tricks yourself. `:e **/foo` is very efficient for editing a file, `:b /bar` is just as efficient for jumping to a buffer… – romainl Oct 13 '12 at 17:01
8

I thought this deserved to be a separate answer so, there.

You can add CSS support to ctags and use it to jump to definition the same way you would do for JavaScript. It's as simple as adding the following lines to the ~/.ctags file:

--langdef=css
--langmap=css:.css
--regex-css=/^[ \t]*\.([A-Za-z0-9_-]+)/.\1/c,class,classes/
--regex-css=/^[ \t]*#([A-Za-z0-9_-]+)/#\1/i,id,ids/
--regex-css=/^[ \t]*(([A-Za-z0-9_-]+[ \t\n,]+)+)\{/\1/t,tag,tags/
--regex-css=/^[ \t]*@media\s+([A-Za-z0-9_-]+)/\1/m,media,medias/

Once you are done, the clasic :!ctags -R . will correctly index your CSS files and you'll be able to do :tag .myClass to jump to the correct CSS definition in the correct CSS file.

There's one catch, though. The classes an ids tags will include their . or # so :tag myClass won't work while :tag .myClass will. The simplest solution is to use "regexp search" instead of "whole tag search": :tag /myClass.

These two mappings have worked flawlessly (for JS for a while and for CSS since a few days) :

" alternative to <C-]>
" place your cursor on an id or class and hit <leader>]
" to jump to the definition
nnoremap <leader>] :tag /<c-r>=expand('<cword>')<cr><cr>

" alternative to <C-w>}
" place your cursor on an id or class and hit <leader>}
" to show a preview of the definition. This doesn't seem to be
" very useful for CSS but it rocks for JavaScript 
nnoremap <leader>} :ptag /<c-r>=expand('<cword>')<cr><cr>
romainl
  • 186,200
  • 21
  • 280
  • 313
  • Looks like a good trick. Let me see it at a later stage, when I am fully on ctags. Any reference on ctags, so I explore ctag functionality more? – Gattoo Oct 18 '12 at 08:14
  • That's smart. Rushing it is not a very good idea. `:help tags` has everything you need for a Vim-centric workflow and `$man ctags` has all the rest. – romainl Oct 18 '12 at 09:18
  • 3
    I updated the above code to afford SCSS tagging support: https://gist.github.com/dreki/da853aeb4d80c03a4448 – duma Oct 16 '14 at 14:05