-
Notifications
You must be signed in to change notification settings - Fork 271
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature request: When jumping to a definition, increment the tag stack #517
Comments
Adding this was enough in my case, maybe it helps you too: nnoremap <silent> gd :normal! m'<CR>:call LanguageClient_textDocument_definition()<CR> |
@balta2ar Does that just create a mark? Marks are local to the current buffer, so if you go to the definition to a different file (so 90% of the time) then you won't be able to jump back. |
Looks like vim/neovim doesn't have plugin API for tagstack interaction. (neovim/neovim#398) All ctrl+] and ctrl+t stuff is hardcoded, and there is no way how to implement this feature except hooking these hotkeys and emulate tagstack behavior :-( . |
It seems that vim now have api's for incrementing tagstack, see the reference implementation here it will be good to add now. |
Thanks for @qrux0 and @amgoyal's comment. They give me the idea. Maybe we don't have to rewrite I have no idea about rust. If the idea is ok, I would try to learn rust and write rust version. " ref: https://github.com/fatih/vim-go/blob/8b4b0e3cea0f41aeb6810fbc30d57e4a639d1ee6/autoload/go/def.vim
let s:lsp_stack = []
let s:lsp_stack_level = 0
function! MyGoToDefinition(...) abort
" Get the current position
let l:fname = expand('%:p')
let l:line = line(".")
let l:col = col(".")
" Call the original function to jump to the definition
let l:result = LanguageClient_runSync('LanguageClient#textDocument_definition', {
\ 'handle': v:true,
\ })
" Get the position of definition
let l:jump_fname = expand('%:p')
let l:jump_line = line(".")
let l:jump_col = col(".")
" If the position is the same as previous, ignore the jump action
if l:fname == l:jump_fname && l:line == l:jump_line
return
endif
" Remove anything newer than the current position, just like basic
" vim tag support
if s:lsp_stack_level == 0
let s:lsp_stack = []
else
let s:lsp_stack = s:lsp_stack[0:s:lsp_stack_level-1]
endif
" Push entry into stack
let s:lsp_stack_level += 1
let l:stack_entry = {'line': l:line, 'col': l:col, 'file': l:fname}
call add(s:lsp_stack, l:stack_entry)
endfunction
function! MyTagStackPop() abort
if s:lsp_stack_level == 0
echo "lsp stack empty!"
return
endif
" Get previous position
let l:curr_stack_level = s:lsp_stack_level - 1
let l:jump_entry = s:lsp_stack[l:curr_stack_level]
" Pop stack
let s:lsp_stack = s:lsp_stack[0:l:curr_stack_level]
let s:lsp_stack_level = s:lsp_stack_level - 1
" Jump to previous location
if &modified
exec 'hide edit' l:jump_entry['file']
else
exec 'edit' l:jump_entry['file']
endif
call cursor(l:jump_entry['line'], l:jump_entry['col'])
normal! zz
endfunction
nnoremap gd :call MyGoToDefinition()<cr>
nnoremap gt :<C-U>call MyTagStackPop()<cr>
"nnoremap <c-]> :call MyGoToDefinition()<cr>
"nnoremap <c-t> :<C-U>call MyTagStackPop()<cr> |
The jedi-vim uses a trick to insert tags into vim's original stack. The benefit of the method is that the implementation does not need to manipulate a stack to memory user's behaviour. But the function is still vim version. In next step, I would lean rust in my free time and try to write rust version. function! MyGoToDefinition(...) abort
" ref: https://github.com/davidhalter/jedi-vim/blob/master/pythonx/jedi_vim.py#L329-L345
" Get the current position
let l:fname = expand('%:p')
let l:line = line(".")
let l:col = col(".")
let l:word = expand("<cword>")
" Call the original function to jump to the definition
let l:result = LanguageClient_runSync(
\ 'LanguageClient#textDocument_definition', {
\ 'handle': v:true,
\ })
" Get the position of definition
let l:jump_fname = expand('%:p')
let l:jump_line = line(".")
let l:jump_col = col(".")
" If the position is the same as previous, ignore the jump action
if l:fname == l:jump_fname && l:line == l:jump_line
return
endif
" Workaround: Jump to origial file. If the function is in rust, there is a
" way to ignore the behaviour
if &modified
exec 'hide edit' l:fname
else
exec 'edit' l:fname
endif
call cursor(l:line, l:col)
" Store the original setting
let l:ori_wildignore = &wildignore
let l:ori_tags = &tags
" Write a temp tags file
let l:temp_tags_fname = tempname()
let l:temp_tags_content = printf("%s\t%s\t%s", l:word, l:jump_fname,
\ printf("call cursor(%d, %d)", l:jump_line, l:jump_col+1))
call writefile([l:temp_tags_content], l:temp_tags_fname)
" Set temporary new setting
set wildignore=
let &tags = l:temp_tags_fname
" Add to new stack
execute ":tjump " . l:word
" Restore original setting
let &tags = l:ori_tags
let &wildignore = l:ori_wildignore
" Remove temporary file
if filereadable(l:temp_tags_fname)
call delete(l:temp_tags_fname, "rf")
endif
endfunction
nnoremap gd :call MyGoToDefinition()<cr>
" No need to remap <c-t> anymore |
I slightly modified the script by @yen3 to make it asynchronous: function! MyGoToDefinition(...) abort
" ref: https://github.com/davidhalter/jedi-vim/blob/master/pythonx/jedi_vim.py#L329-L345
" Get the current position
let pos = {
\ 'fname': expand('%:p'),
\ 'line': line("."),
\ 'col': col("."),
\ 'word': expand("<cword>")
\ }
call LanguageClient#textDocument_definition({'handle': v:true}, function('MyGoToDefinitionCallback', [pos]))
endfunction
function! MyGoToDefinitionCallback(pos, ...) abort
" Get the original position
let l:fname = a:pos['fname']
let l:line = a:pos['line']
let l:col = a:pos['col']
let l:word = a:pos['word']
" Get the position of definition
let l:jump_fname = expand('%:p')
let l:jump_line = line(".")
let l:jump_col = col(".")
" If the position is the same as previous, ignore the jump action
if l:fname == l:jump_fname && l:line == l:jump_line
return
endif
" Workaround: Jump to origial file. If the function is in rust, there is a
" way to ignore the behaviour
if &modified
exec 'hide edit' l:fname
else
exec 'edit' l:fname
endif
call cursor(l:line, l:col)
" Write a temp tags file
let l:temp_tags_fname = tempname()
let l:temp_tags_content = printf("%s\t%s\t%s", l:word, l:jump_fname,
\ printf("call cursor(%d, %d)", l:jump_line, l:jump_col))
call writefile([l:temp_tags_content], l:temp_tags_fname)
" Store the original setting
let l:ori_wildignore = &wildignore
let l:ori_tags = &tags
" Set temporary new setting
set wildignore=
let &tags = l:temp_tags_fname
" Add to new stack
execute ":tjump " . l:word
" Restore original setting
let &tags = l:ori_tags
let &wildignore = l:ori_wildignore
" Remove temporary file
if filereadable(l:temp_tags_fname)
call delete(l:temp_tags_fname, "rf")
endif
endfunction |
This feature would be really useful for jumping back to where you came from, when you do multiple jumps and browse around in various files.
Just a note,
C-]
which pops the tag stack, is different toC-o
, which is not necessarily jump-to-definition-related. The stack forC-o
gets modified very often, for example when doinggg
, so simply using this key would not be ideal, as I often have to press the scheme the times to come back to where I was before using the jump to definition feature.The text was updated successfully, but these errors were encountered: