Skip to content

Instantly share code, notes, and snippets.

@idbrii
Created May 12, 2021 00:33
Show Gist options
  • Save idbrii/321688f9748155520c4a7bd90ca435c1 to your computer and use it in GitHub Desktop.
Save idbrii/321688f9748155520c4a7bd90ca435c1 to your computer and use it in GitHub Desktop.
" 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