Move cursor and make gf, but in previous file move to old position

Viewed 59

I know that plugin that can do it almost certainly exists. Or maybe I could use something like LSP for this. But I want to make my simple command, that will go to file with definition of component / function / class in JS. It's not difficult, because in JS all imports are explicitly, so I wrote this command in my .vimrc

autocmd FileType javascript nnoremap gd gd/from<CR>:noh<CR>5lgf

gd = go to definition (first occurrence of symbol)

/from = find from in this string (because string will be like "import smth from 'filename'")

:noh = remove unnecessary highlighting

5l = skip from word to move to filename

gf = go file

This works good, it goes to required file but when I return to my old file, my cursor is obviously on line with import, but I want to remain in line for example(where I run gd command), but not in import ComponentName from './path/ComponentName'(for example). I heard about :keepjump but I don't understand how can I use it there. How can I do this ?

1 Answers

Assuming you didn't rename your import

With Vim default settings, eg $ vim --clean main.js, you should be able to use gf directly on any ComponentName in the buffer simply by setting the :help 'path' option properly.

In the example below, all I had to do was :set path+=./x/y/z (very explicit) but I could have simply done :set path+=x/** (more implicit):

gf

Of course, manually adding every single component directory is out of the question but front-end projects tend to have predictable structures so it won't be too difficult to write your own set path+=components/**,src/**,<other directories>.

Assuming you renamed your import

Your mapping as is won't cut it because it is too brittle. Instead, we can take a different approach:

gd                                 " jump to local definition of current word
$                                  " move cursor to end of the line
F'                                 " move cursor to nearest single quote to the left
yi'                                " yank filename
<C-o>                              " jump back to usage
:execute 'find' getreg('"')<CR>    " find filename in path

which gives us this:

nnoremap <key> gd$F'yi'<C-o><Cmd>execute 'find' getreg('"')<CR>

--- EDIT ---

As per your comment, here is a quote-agnostic variant that uses a custom function to make the added complexity manageable:

function! FindModule()
    " jump to definition of current word
    normal! gD
    " move cursor to end of line
    normal!
    " move cursor to opening quote
    normal! gEW
    " move cursor inside the quotes
    normal! l
    " grab filename
    let fn = expand('<cfile>')
    " jump back back to usage
    " ^O is obtained by pressing <C-v> then <C-o>
    normal! ^O
    " find filename in path
    execute 'find' fn
endfunction
nnoremap <key> <Cmd>call FindModule()<CR>

--- ENDEDIT ---


You might find this article interesting.

Related