Skip to content
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

Use balloon hovers instead of cursorhold hovers to show documents #4106

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 83 additions & 42 deletions autoload/youcompleteme.vim
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ function! youcompleteme#Enable()
" supported, enable it.
let s:resolve_completions = s:RESOLVE_ON_DEMAND
elseif require_resolve
" The preview window or info popup is enalbed - request the server
" The preview window or info popup is enabled - request the server
" pre-resolves completion items
let s:resolve_completions = s:RESOLVE_UP_FRONT
else
Expand Down Expand Up @@ -709,19 +709,28 @@ endfunction


function! s:EnableAutoHover()
if g:ycm_auto_hover ==# 'CursorHold' && s:enable_hover
augroup YcmBufHover
autocmd! * <buffer>
autocmd CursorHold <buffer> call s:Hover()
augroup END
if s:enable_hover
if has( 'balloon_eval' )
set ballooneval
endif
if has( 'balloon_eval_term' )
set balloonevalterm
endif
if exists( '+balloonexpr' ) && empty( &balloonexpr )
set balloonexpr=youcompleteme#hover()
endif
endif
endfunction


function! s:DisableAutoHover()
augroup YcmBufHover
autocmd! * <buffer>
augroup END
call popup_clear()
if has( 'balloon_eval' )
set noballooneval
endif
if has( 'balloon_eval_term' )
set noballoonevalterm
endif
endfunction


Expand Down Expand Up @@ -1245,7 +1254,7 @@ function! s:PollResolve( item, ... )

" Note we re-use the 'completion' request for resolves. This prevents us
" sending a completion request and a resolve request at the same time, as
" resolve requests re-use the requset data from the last completion request
" resolve requests re-use the request data from the last completion request
" and it must not change.
" We also re-use the poller, so that any new completion request effectively
" cancels this poller.
Expand All @@ -1258,9 +1267,12 @@ function! s:PollResolve( item, ... )
call s:ShowInfoPopup( completion_item )
endfunction

set completepopup+=align:menu

function! s:ShowInfoPopup( completion_item )
let id = popup_findinfo()
if id
if id && !empty( a:completion_item.info )
call popup_setoptions( id, { 'highlight': 'Pmenu' } )
call popup_settext( id, split( a:completion_item.info, '\n' ) )
call popup_show( id )
endif
Expand Down Expand Up @@ -1584,11 +1596,10 @@ function! s:ForceCompileAndDiagnostics()
endfunction


if exists( '*popup_atcursor' )
function s:Hover()
if exists( '*popup_atcursor' ) && exists( '*popup_beval' )
function s:Hover( hover_type )
if !py3eval( 'ycm_state.NativeFiletypeCompletionUsable()' )
" Cancel the autocommand if it happens to have been set
call s:DisableAutoHover()
return
endif

Expand Down Expand Up @@ -1618,14 +1629,28 @@ if exists( '*popup_atcursor' )
return
endif

call youcompleteme#GetCommandResponseAsync(
\ function( 's:ShowHoverResult' ),
\ b:ycm_hover.command )
let s:hover_syntax = b:ycm_hover.syntax
if a:hover_type == 'cursorhold'
let s:hover_pos = screenpos( win_getid(), line( '.' ), col( '.' ) )
let s:HoverPopupFunc = function( 'popup_atcursor' )
call youcompleteme#GetCommandResponseAsync(
\ function( 's:ShowHoverResult' ),
\ b:ycm_hover.command )
elseif a:hover_type == 'balloon'
let s:hover_pos = screenpos( v:beval_winid, v:beval_lnum, v:beval_col )
let s:HoverPopupFunc = function( 'popup_beval' )
call youcompleteme#GetCommandResponseAsync(
\ function( 's:ShowHoverResult' ),
\ b:ycm_hover.command,
\ '--bufnr=' . v:beval_bufnr,
\ '--line_num=' . v:beval_lnum,
\ '--column_num=' . v:beval_col )
endif
endfunction


function! s:ShowHoverResult( response )
call popup_hide( s:cursorhold_popup )
call popup_close( s:cursorhold_popup )

if empty( a:response )
return
Expand All @@ -1637,56 +1662,72 @@ if exists( '*popup_atcursor' )
"
" Find the longest line (FIXME: probably doesn't work well for multi-byte)
let lines = split( a:response, "\n" )
let len = max( map( copy( lines ), "len( v:val )" ) )
let len = max( map( copy( lines ), "strdisplaywidth( v:val )" ) )

let col = s:hover_pos.col
let wrap = 0
let col = 'cursor'

" max width is screen columns minus x padding (2)
if len >= (&columns - 2)
" There's at least one line > our max - enable word wrap and draw the
let border = { 'above': 1, 'right': 1, 'below': 1, 'left': 1 }
let padding = { 'above': 0, 'right': 1, 'below': 0, 'left': 1 }
let left_right_reserve = border.left + border.right + padding.left + padding.right
let above_below_reserve = border.above + border.below + padding.above + padding.below
let maxheight = max( [ s:hover_pos.row - 1, &lines - s:hover_pos.row ] ) - above_below_reserve

" max width is screen columns minus border and padding
let maxwidth = &columns - left_right_reserve
let minwidth = min( [ len, maxwidth ] )
if len >= maxwidth
" There's at least one line >= our max - enable word wrap and draw the
" popup at the leftmost column
let col = 1
let wrap = 1
endif

let s:cursorhold_popup = popup_atcursor(
let s:cursorhold_popup = s:HoverPopupFunc(
\ lines,
\ {
\ 'col': col,
\ 'wrap': wrap,
\ 'padding': [ 0, 1, 0, 1 ],
\ 'moved': 'word',
\ 'maxwidth': &columns,
\ 'close': 'click',
\ 'fixed': 0,
\ 'col' : col,
\ 'wrap' : wrap,
\ 'border' : [ border.above, border.right, border.below, border.left ],
\ 'padding' : [ padding.above, padding.right, padding.below, padding.left ],
\ 'maxheight': maxheight,
\ 'maxwidth' : maxwidth,
\ 'minwidth' : minwidth,
\ 'close' : 'click',
\ 'fixed' : 0,
\ 'resize' : 1,
\ 'drag' : 1
\ }
\ )
if popup_getpos( s:cursorhold_popup ).scrollbar
call popup_setoptions( s:cursorhold_popup,
\ { 'maxwidth': maxwidth - 1 } )
endif
call setbufvar( winbufnr( s:cursorhold_popup ),
\ '&syntax',
\ b:ycm_hover.syntax )
\ s:hover_syntax )
endfunction


function! s:ToggleHover()
let pos = popup_getpos( s:cursorhold_popup )
if !empty( pos ) && pos.visible
call popup_hide( s:cursorhold_popup )
call popup_close( s:cursorhold_popup )
let s:cursorhold_popup = -1

" Diable the auto-trigger until the next cursor movement.
call s:DisableAutoHover()
augroup YCMHover
autocmd! CursorMoved <buffer>
autocmd CursorMoved <buffer> call s:EnableAutoHover()
augroup END
else
call s:Hover()
call s:Hover( 'cursorhold' )
endif
endfunction

let s:enable_hover = 1
nnoremap <silent> <plug>(YCMHover) :<C-u>call <SID>ToggleHover()<CR>
nnoremap <silent> <plug>(YCMHoverON) :<C-u>call <SID>EnableAutoHover()<CR>
nnoremap <silent> <plug>(YCMHoverOFF) :<C-u>call <SID>DisableAutoHover()<CR>

function! youcompleteme#hover()
call win_execute( v:beval_winid, 'call s:Hover( "balloon" )' )
return ''
endfunction

else
" Don't break people's mappings if this feature is disabled, just do nothing.
nnoremap <silent> <plug>(YCMHover) <Nop>
Expand Down
6 changes: 6 additions & 0 deletions python/ycm/youcompleteme.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,12 @@ def _GetCommandRequestArguments( self,
elif argument.startswith( '--bufnr=' ):
extra_data[ 'bufnr' ] = int( argument[ len( '--bufnr=' ): ] )
continue
elif argument.startswith( '--line_num=' ):
extra_data[ 'line_num' ] = int( argument[ len( '--line_num=' ): ] )
continue
elif argument.startswith( '--column_num=' ):
extra_data[ 'column_num' ] = int( argument[ len( '--column_num=' ): ] )
continue

final_arguments.append( argument )

Expand Down