Created
May 12, 2021 00:33
-
-
Save idbrii/321688f9748155520c4a7bd90ca435c1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
" An extremely rough approximation of vscode's inliner: | |
" https://www.youtube.com/watch?v=EenznqbW5w8 | |
" Uses vim's popupwin to show the definition of a tag. Hijacks the arrow keys | |
" to let you move a cursor inside that window and jump to another tag. | |
" | |
" Public domain, CC0. | |
let g:tagpopper_z = 0 | |
" Turning this off hides some bugs but then preview window is even more | |
" superior. Not sure why sometimes popup contents is clobbered. | |
let g:tagpopper_can_display_multiple = 1 | |
function! TagPopper_ShowTagInPopup(tag) abort | |
if g:tagpopper_winid | |
call setwinvar(g:tagpopper_winid, '&cursorline', 0) | |
call setwinvar(g:tagpopper_winid, '&colorcolumn', 0) | |
endif | |
let tag = taglist(a:tag)[0] | |
" ensure buffer is loaded | |
" You'd think you could just do this, but you cannot: | |
"~ call bufload(tag.filename) | |
try | |
exec 'ptag' a:tag | |
pclose | |
catch /^Vim\%((\a\+)\)\=:E994/ " Error: Not allowed in a popup window | |
" don't care if it fails. this is enough to load the buffer. | |
endtry | |
let g:tagpopper_z += 1 | |
let maxheight = 10 | |
let offset = 0 | |
if g:tagpopper_can_display_multiple | |
if g:tagpopper_z > 1 | |
let offset = 1 | |
endif | |
let offset = (offset + maxheight) * g:tagpopper_z | |
endif | |
let winid = popup_atcursor(bufnr(tag.filename), | |
\ #{ | |
\ zindex: g:tagpopper_z, | |
\ line: 'cursor+'.. offset, | |
\ maxheight: maxheight, | |
\ moved: 'WORD', | |
\ callback: 'TagPopper_Clear', | |
\ title: tag.filename, | |
\ }) | |
call win_execute(winid, tag.cmd) | |
call win_execute(winid, 'norm! zt') | |
call setwinvar(winid, '&cursorline', 1) | |
call s:PopupMap() | |
let g:tagpopper_winid = winid | |
let g:tagpopper_cursorcol = 1 | |
endf | |
" Experiment with passing other commands to this function. | |
function! TagPopper_RunInPopup(cmd) abort | |
call win_execute(g:tagpopper_winid, a:cmd) | |
endf | |
function! s:ExtractTagAtPos(line, col) abort | |
let start = a:line[: a:col - 1] | |
let end = a:line[a:col :] | |
let start = substitute(start, '\v.{-}\ze\k+$', '', '') | |
let end = substitute(end, '^\v\k+\zs.*', '', '') | |
return start .. end | |
endf | |
function! PopupJumpToTagAtCol() abort | |
let tagword = s:ExtractTagAtPos(getline('.'), g:tagpopper_cursorcol) | |
return 'call TagPopper_ShowTagInPopup("'.. tagword ..'")' | |
endf | |
" Move single char | |
function! s:PopupCursor(direction) abort | |
" Can't figure out how to change cursor column. setpos doesn't work and | |
" getcurpos returns current buffer instead of popup's. | |
let g:tagpopper_cursorcol += a:direction * 4 | |
call setwinvar(g:tagpopper_winid, '&colorcolumn', g:tagpopper_cursorcol) | |
endf | |
" Move by word | |
function! PopupCursorWord(direction) abort | |
let g:tagpopper_cursorcol += a:direction | |
let line = getline('.') | |
if a:direction < 0 | |
let line = line[:g:tagpopper_cursorcol-1] | |
let g:tagpopper_cursorcol = len(matchstr(line, '^.*\W\k')) | |
else | |
let pos = match(line, '\W\k', g:tagpopper_cursorcol) | |
if pos <= 0 | |
let pos = match(line, '\k', g:tagpopper_cursorcol) | |
endif | |
let g:tagpopper_cursorcol = pos + 2 | |
endif | |
call setwinvar(g:tagpopper_winid, '&colorcolumn', g:tagpopper_cursorcol) | |
endf | |
function! s:PopupMap() abort | |
" Popups don't seem to have a cursor you can manipulate (especially not | |
" the column), so we must fake it. This weakness shows this feature | |
" probably won't be well supported by vim. | |
nnoremap <silent> <Up> :<C-u>call TagPopper_RunInPopup('-')<CR> | |
nnoremap <silent> <Down> :<C-u>call TagPopper_RunInPopup('+')<CR> | |
nnoremap <silent> <Left> :<C-u>call TagPopper_RunInPopup("call PopupCursorWord(-1)")<CR> | |
nnoremap <silent> <Right> :<C-u>call TagPopper_RunInPopup("call PopupCursorWord(1)")<CR> | |
" Moving by single characters is too slow. | |
"~ nnoremap <silent> <Left> :<C-u>call <sid>PopupCursor(-1)<CR> | |
"~ nnoremap <silent> <Right> :<C-u>call <sid>PopupCursor(1)<CR> | |
nnoremap <silent> \t :<C-u>call TagPopper_RunInPopup('exec PopupJumpToTagAtCol()')<CR> | |
endf | |
function! TagPopper_Clear(id, result) abort | |
let g:tagpopper_z = 0 | |
let g:tagpopper_winid = 0 | |
silent! nunmap <Up> | |
silent! nunmap <Down> | |
silent! nunmap <Left> | |
silent! nunmap <Right> | |
nnoremap \t :<C-u>call TagPopper_ShowTagInPopup(expand("<cword>"))<CR> | |
endf | |
nnoremap \t :<C-u>call TagPopper_ShowTagInPopup(expand("<cword>"))<CR> | |
" ----------------------------------------------------------------------------- | |
" However, using the previewwindow is a much simpler solution: | |
nnoremap \T :<C-u>ptag <C-r><C-w><CR><C-w>P | |
" You can use Ctrl-o and Ctrl-i to move back and forth between tag jumps. | |
" Lots of lsp plugins support opening definitions in preview as well. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment