diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index 32d17ab..23954e6 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -72,11 +72,7 @@ function! vimspector#internal#balloon#CreateTooltip( is_hover, ... ) abort \ 'mapping': 0 \ } - " When ambiwidth is single, use prettier characters for the border. This - " would look silly when ambiwidth is double. - if &ambiwidth ==# 'single' && &encoding ==? 'utf-8' - let config[ 'borderchars' ] = [ '─', '│', '─', '│', '╭', '╮', '┛', '╰' ] - endif + let config = vimspector#internal#popup#SetBorderChars( config ) if a:is_hover let config[ 'filter' ] = 'vimspector#internal#balloon#MouseFilter' diff --git a/autoload/vimspector/internal/neopopup.vim b/autoload/vimspector/internal/neopopup.vim index cc25020..189c78c 100644 --- a/autoload/vimspector/internal/neopopup.vim +++ b/autoload/vimspector/internal/neopopup.vim @@ -83,6 +83,9 @@ endfunction function! vimspector#internal#neopopup#Confirm( confirm_id, \ text, \ default_value ) abort + + " Neovim doesn't have an equivalent of popup_dialog, and it's way too much + " effort to write one, so we just use confirm(). let result = confirm( a:text, '&Yes &No &Default', 3 ) " Map the results to what popup_menu_filter would return (ok s:ConfirmCallback diff --git a/autoload/vimspector/internal/popup.vim b/autoload/vimspector/internal/popup.vim index e8658ab..5978987 100644 --- a/autoload/vimspector/internal/popup.vim +++ b/autoload/vimspector/internal/popup.vim @@ -32,9 +32,32 @@ function! vimspector#internal#popup#HideSplash( id ) abort call popup_hide( a:id ) endfunction +let s:current_selection = 0 +let s:selections = [] +let s:text = [] + +function! s:UpdatePopup( id ) + let buf = copy( s:text ) + call extend( buf, s:DrawButtons() ) + call popup_settext( a:id, buf ) +endfunction + function! s:YesNoDefaultFilter( default_value, id, key ) abort - if a:key ==# "\" || a:key ==# 'D' || a:key ==# 'd' + if a:key ==# "\" + call popup_close( a:id, s:current_selection + 1 ) + return 1 + elseif a:key ==# 'D' || a:key ==# 'd' call popup_close( a:id, a:default_value ) + return 1 + elseif index( [ "\", "\" ], a:key ) >= 0 + let s:current_selection = ( s:current_selection + 1 ) % len( s:selections ) + call s:UpdatePopup( a:id ) + return 1 + elseif index( [ "\", "\" ], a:key ) >= 0 + let s:current_selection = s:current_selection == 0 + \ ? len( s:selections ) - 1: s:current_selection - 1 + call s:UpdatePopup( a:id ) + return 1 endif return popup_filter_yesno( a:id, a:key ) @@ -46,23 +69,68 @@ function! s:ConfirmCallback( confirm_id, id, result ) abort \ int( vim.eval( 'a:result' ) ) ) endfunction +function! s:SelectionPosition( idx ) abort + return a:idx == 0 ? 0 : len( join( s:selections[ : a:idx - 1 ], ' ' ) ) + 1 +endfunction + +function! s:DrawButtons() abort + return [ { + \ 'text': join( s:selections, ' ' ), + \ 'props': [ + \ { + \ 'col': s:SelectionPosition( s:current_selection ) + 1, + \ 'length': len( s:selections[ s:current_selection ] ), + \ 'type': 'VimspectorSelectedItem' + \ }, + \ ] + \ } ] +endfunction + function! vimspector#internal#popup#Confirm( \ confirm_id, \ text, + \ options, \ default_value ) abort - let text = a:text - if type( a:text ) != v:t_list - let text = [ a:text ] + + silent! call prop_type_add( 'VimspectorSelectedItem', { + \ 'highlight': 'PMenuSel' + \ } ) + + let lines = split( a:text, "\n", v:true ) + let buf = [] + for line in lines + call add( buf, { 'text': line, 'props': [] } ) + endfor + + call add( buf, { 'text': '', 'props': [] } ) + + let s:selections = a:options + let s:current_selection = ( a:default_value - 1 ) + + let s:text = copy( buf ) + call extend( buf, s:DrawButtons() ) + + let config = { + \ 'callback': function( 's:ConfirmCallback', [ a:confirm_id ] ), + \ 'filter': function( 's:YesNoDefaultFilter', [ a:default_value ] ), + \ 'mapping': v:false, + \ } + let config = vimspector#internal#popup#SetBorderChars( config ) + + return popup_dialog( buf, config ) +endfunction + +function! vimspector#internal#popup#SetBorderChars( config ) + " When ambiwidth is single, use prettier characters for the border. This + " would look silly when ambiwidth is double. + if &ambiwidth ==# 'single' && &encoding ==? 'utf-8' + let a:config[ 'borderchars' ] = [ '─', '│', '─', '│', '╭', '╮', '┛', '╰' ] endif - call extend( text, [ '', '(Y)es (N)o (D)efault' ] ) - - return popup_dialog( text, { - \ 'callback': function( 's:ConfirmCallback', [ a:confirm_id ] ), - \ 'filter': function( 's:YesNoDefaultFilter', [ a:default_value ] ) - \ } ) + return a:config endfunction + " Boilerplate {{{ let &cpoptions=s:save_cpo unlet s:save_cpo diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index 5aefc37..290ca2e 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -390,13 +390,17 @@ def ConfirmCallback( confirm_id, result ): handler( result ) -def Confirm( api_prefix, prompt, handler, default_value = 1 ): +def Confirm( api_prefix, prompt, handler, default_value = 3, options = None ): global CONFIRM_ID + if not options: + options = [ '(Y)es', '(N)o', '(D)efault' ] + CONFIRM_ID += 1 CONFIRM[ CONFIRM_ID ] = handler Call( f'vimspector#internal#{ api_prefix }popup#Confirm', CONFIRM_ID, prompt, + options, default_value )