mirror of
https://github.com/neovim/neovim.git
synced 2024-12-19 10:45:16 -07:00
feat(termdebug): improve :Evaluate
floating window (#26621)
Problem: - The :Evaluate result window is not cleaned up when the cursor moves. - This window is not focusable. Solution: Replace the old implementation from autozimu/LanguageClient-neovim with vim.lsp.util.open_floating_preview and implement custom focusing logic. Also remove g:termdebug_useFloatingHover option now that it's working correctly.
This commit is contained in:
parent
6cb78e2d1c
commit
cd1b14f027
@ -240,7 +240,7 @@ gdb window and use a "print" command, e.g.: >
|
||||
If mouse pointer movements are working, Vim will also show a balloon when the
|
||||
mouse rests on text that can be evaluated by gdb.
|
||||
You can also use the "K" mapping that will either use Nvim floating windows
|
||||
if available to show the results or print below the status bar.
|
||||
to show the results.
|
||||
|
||||
Now go back to the source window and put the cursor on the first line after
|
||||
the for loop, then type: >
|
||||
@ -320,6 +320,8 @@ Inspecting variables ~
|
||||
|
||||
This is similar to using "print" in the gdb window.
|
||||
You can usually shorten `:Evaluate` to `:Ev`.
|
||||
The result is displayed in a floating window.
|
||||
You can move the cursor to this window by running `:Evaluate` (or `K`) again.
|
||||
|
||||
|
||||
Navigating stack frames ~
|
||||
@ -475,10 +477,6 @@ If the command needs an argument use a List: >vim
|
||||
If there is no g:termdebug_config you can use: >vim
|
||||
let g:termdebugger = ['rr', 'replay', '--']
|
||||
|
||||
To not use Nvim floating windows for previewing variable evaluation, set the
|
||||
`g:termdebug_useFloatingHover` variable like this: >vim
|
||||
let g:termdebug_useFloatingHover = 0
|
||||
|
||||
If you are a mouse person, you can also define a mapping using your right
|
||||
click to one of the terminal command like evaluate the variable under the
|
||||
cursor: >vim
|
||||
|
165
runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
vendored
165
runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
vendored
@ -35,21 +35,14 @@
|
||||
" The communication with gdb uses GDB/MI. See:
|
||||
" https://sourceware.org/gdb/current/onlinedocs/gdb/GDB_002fMI.html
|
||||
"
|
||||
" For neovim compatibility, the vim specific calls were replaced with neovim
|
||||
" specific calls:
|
||||
" term_start -> termopen
|
||||
" term_sendkeys -> chansend
|
||||
" term_getline -> getbufline
|
||||
" job_info && term_getjob -> using linux command ps to get the tty
|
||||
" balloon -> nvim floating window
|
||||
" NEOVIM COMPATIBILITY
|
||||
"
|
||||
" The code for opening the floating window was taken from the beautiful
|
||||
" implementation of LanguageClient-Neovim:
|
||||
" https://github.com/autozimu/LanguageClient-neovim/blob/0ed9b69dca49c415390a8317b19149f97ae093fa/autoload/LanguageClient.vim#L304
|
||||
"
|
||||
" Neovim terminal also works seamlessly on windows, which is why the ability
|
||||
" Author: Bram Moolenaar
|
||||
" Copyright: Vim license applies, see ":help license"
|
||||
" The vim specific functionalities were replaced with neovim specific calls:
|
||||
" - term_start -> termopen
|
||||
" - term_sendkeys -> chansend
|
||||
" - term_getline -> getbufline
|
||||
" - job_info && term_getjob -> nvim_get_chan_info
|
||||
" - balloon -> vim.lsp.util.open_floating_preview
|
||||
|
||||
" In case this gets sourced twice.
|
||||
if exists(':Termdebug')
|
||||
@ -1313,7 +1306,14 @@ endfunc
|
||||
|
||||
" :Evaluate - evaluate what is specified / under the cursor
|
||||
func s:Evaluate(range, arg)
|
||||
if s:eval_float_win_id > 0 && nvim_win_is_valid(s:eval_float_win_id)
|
||||
\ && a:range == 0 && empty(a:arg)
|
||||
call nvim_set_current_win(s:eval_float_win_id)
|
||||
return
|
||||
endif
|
||||
let expr = s:GetEvaluationExpression(a:range, a:arg)
|
||||
let s:evalFromBalloonExpr = 1
|
||||
let s:evalFromBalloonExprResult = ''
|
||||
let s:ignoreEvalError = 0
|
||||
call s:SendEval(expr)
|
||||
endfunc
|
||||
@ -1370,6 +1370,8 @@ let s:ignoreEvalError = 0
|
||||
let s:evalFromBalloonExpr = 0
|
||||
let s:evalFromBalloonExprResult = ''
|
||||
|
||||
let s:eval_float_win_id = -1
|
||||
|
||||
" Handle the result of data-evaluate-expression
|
||||
func s:HandleEvaluate(msg)
|
||||
let value = a:msg
|
||||
@ -1392,9 +1394,15 @@ func s:HandleEvaluate(msg)
|
||||
else
|
||||
let s:evalFromBalloonExprResult .= ' = ' . value
|
||||
endif
|
||||
let s:evalFromBalloonExprResult = split(s:evalFromBalloonExprResult, '\\n')
|
||||
call s:OpenHoverPreview(s:evalFromBalloonExprResult, v:null)
|
||||
let s:evalFromBalloonExprResult = ''
|
||||
" NEOVIM:
|
||||
" - Result pretty-printing is not implemented. Vim prettifies the result
|
||||
" with balloon_split(), which is not ported to nvim.
|
||||
" - Manually implement window focusing. Sometimes the result of pointer
|
||||
" evaluation arrives in two separate messages, one for the address
|
||||
" itself and the other for the value in that address. So with the stock
|
||||
" focus option, the second message will focus the window containing the
|
||||
" first message.
|
||||
let s:eval_float_win_id = luaeval('select(2, vim.lsp.util.open_floating_preview(_A))', [s:evalFromBalloonExprResult])
|
||||
else
|
||||
echomsg '"' . s:evalexpr . '": ' . value
|
||||
endif
|
||||
@ -1403,132 +1411,9 @@ func s:HandleEvaluate(msg)
|
||||
" Looks like a pointer, also display what it points to.
|
||||
let s:ignoreEvalError = 1
|
||||
call s:SendEval('*' . s:evalexpr)
|
||||
else
|
||||
let s:evalFromBalloonExprResult = ''
|
||||
endif
|
||||
endfunc
|
||||
|
||||
function! s:ShouldUseFloatWindow() abort
|
||||
if exists('*nvim_open_win') && (get(g:, 'termdebug_useFloatingHover', 1) == 1)
|
||||
return v:true
|
||||
else
|
||||
return v:false
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:CloseFloatingHoverOnCursorMove(win_id, opened) abort
|
||||
if getpos('.') == a:opened
|
||||
" Just after opening floating window, CursorMoved event is run.
|
||||
" To avoid closing floating window immediately, check the cursor
|
||||
" was really moved
|
||||
return
|
||||
endif
|
||||
autocmd! nvim_termdebug_close_hover
|
||||
let winnr = win_id2win(a:win_id)
|
||||
if winnr == 0
|
||||
return
|
||||
endif
|
||||
call nvim_win_close(a:win_id, v:true)
|
||||
endfunction
|
||||
|
||||
function! s:CloseFloatingHoverOnBufEnter(win_id, bufnr) abort
|
||||
let winnr = win_id2win(a:win_id)
|
||||
if winnr == 0
|
||||
" Float window was already closed
|
||||
autocmd! nvim_termdebug_close_hover
|
||||
return
|
||||
endif
|
||||
if winnr == winnr()
|
||||
" Cursor is moving into floating window. Do not close it
|
||||
return
|
||||
endif
|
||||
if bufnr('%') == a:bufnr
|
||||
" When current buffer opened hover window, it's not another buffer. Skipped
|
||||
return
|
||||
endif
|
||||
autocmd! nvim_termdebug_close_hover
|
||||
call nvim_win_close(a:win_id, v:true)
|
||||
endfunction
|
||||
|
||||
" Open preview window. Window is open in:
|
||||
" - Floating window on Neovim (0.4.0 or later)
|
||||
" - Preview window on Neovim (0.3.0 or earlier) or Vim
|
||||
function! s:OpenHoverPreview(lines, filetype) abort
|
||||
" Use local variable since parameter is not modifiable
|
||||
let lines = a:lines
|
||||
let bufnr = bufnr('%')
|
||||
|
||||
let use_float_win = s:ShouldUseFloatWindow()
|
||||
if use_float_win
|
||||
let pos = getpos('.')
|
||||
|
||||
" Calculate width and height
|
||||
let width = 0
|
||||
for index in range(len(lines))
|
||||
let line = lines[index]
|
||||
let lw = strdisplaywidth(line)
|
||||
if lw > width
|
||||
let width = lw
|
||||
endif
|
||||
let lines[index] = line
|
||||
endfor
|
||||
|
||||
let height = len(lines)
|
||||
|
||||
" Calculate anchor
|
||||
" Prefer North, but if there is no space, fallback into South
|
||||
let bottom_line = line('w0') + winheight(0) - 1
|
||||
if pos[1] + height <= bottom_line
|
||||
let vert = 'N'
|
||||
let row = 1
|
||||
else
|
||||
let vert = 'S'
|
||||
let row = 0
|
||||
endif
|
||||
|
||||
" Prefer West, but if there is no space, fallback into East
|
||||
if pos[2] + width <= &columns
|
||||
let hor = 'W'
|
||||
let col = 0
|
||||
else
|
||||
let hor = 'E'
|
||||
let col = 1
|
||||
endif
|
||||
|
||||
let buf = nvim_create_buf(v:false, v:true)
|
||||
call nvim_buf_set_lines(buf, 0, -1, v:true, lines)
|
||||
" using v:true for second argument of nvim_open_win make the floating
|
||||
" window disappear
|
||||
let float_win_id = nvim_open_win(buf, v:false, {
|
||||
\ 'relative': 'cursor',
|
||||
\ 'anchor': vert . hor,
|
||||
\ 'row': row,
|
||||
\ 'col': col,
|
||||
\ 'width': width,
|
||||
\ 'height': height,
|
||||
\ 'style': 'minimal',
|
||||
\ })
|
||||
|
||||
if a:filetype isnot v:null
|
||||
call nvim_set_option_value('filetype', a:filetype, { 'win' : float_win_id })
|
||||
endif
|
||||
|
||||
call nvim_set_option_value('modified', v:false, { 'buf' : buf })
|
||||
call nvim_set_option_value('modifiable', v:false, { 'buf' : buf })
|
||||
|
||||
" Unlike preview window, :pclose does not close window. Instead, close
|
||||
" hover window automatically when cursor is moved.
|
||||
let call_after_move = printf('<SID>CloseFloatingHoverOnCursorMove(%d, %s)', float_win_id, string(pos))
|
||||
let call_on_bufenter = printf('<SID>CloseFloatingHoverOnBufEnter(%d, %d)', float_win_id, bufnr)
|
||||
augroup nvim_termdebug_close_hover
|
||||
execute 'autocmd CursorMoved,CursorMovedI,InsertEnter <buffer> call ' . call_after_move
|
||||
execute 'autocmd BufEnter * call ' . call_on_bufenter
|
||||
augroup END
|
||||
else
|
||||
echomsg a:lines[0]
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Handle an error.
|
||||
func s:HandleError(msg)
|
||||
if s:ignoreEvalError
|
||||
|
Loading…
Reference in New Issue
Block a user