Make confirm dialog take arbitrary keys

Confirm now takes the list of options, list of keys to select them and
the default value. Returned values are always a 1-based index into the
list (like SelectFromList) or -1 to mean esc/ctrl-c.

This uses a nice popup dialog in vim and a crappy input on neovim.
This commit is contained in:
Ben Jackson 2021-03-11 22:38:01 +00:00
commit 154e727b96
6 changed files with 82 additions and 28 deletions

View file

@ -82,29 +82,52 @@ endfunction
function! vimspector#internal#neopopup#Confirm( confirm_id, function! vimspector#internal#neopopup#Confirm( confirm_id,
\ text, \ text,
\ default_value ) abort \ options,
\ default_value,
\ keys ) abort
" Neovim doesn't have an equivalent of popup_dialog, and it's way too much " Neovim doesn't have an equivalent of popup_dialog, and it's way too much
" effort to write one, so we just use confirm(). " effort to write one, so we just use confirm().
let result = confirm( a:text, '&Yes &No &Default', 3 ) let prompt = a:text
for opt in a:options
let prompt .= ' ' . opt
endfor
let prompt .= ': '
" Annoyingly we can't use confirm() here because for some reason it doesn't
" render properly in a channel callback. So we use input() and mimic dialog
" behaviour.
try
let result = input( prompt, a:keys[ a:default_value - 1 ] )
catch /.*/
let result = -1
endtry
" Map the results to what popup_menu_filter would return (ok s:ConfirmCallback " Map the results to what popup_menu_filter would return (ok s:ConfirmCallback
" in popup.vim) " in popup.vim)
if result == 2 if result == ''
" No is represented as 0
let result = 0
elseif result == 0
" User pressed ESC/ctrl-c " User pressed ESC/ctrl-c
let result = -1 let result = -1
elseif result == 3 else
" Default let index = 1
let result = a:default_value for k in a:keys
if k ==? result
let result = index
break
endif
let index += 2
endfor
if index >= len( a:keys )
let result = -1
endif
endif endif
py3 __import__( 'vimspector', fromlist = [ 'utils' ] ).utils.ConfirmCallback( py3 __import__( 'vimspector', fromlist = [ 'utils' ] ).utils.ConfirmCallback(
\ int( vim.eval( 'a:confirm_id' ) ), \ int( vim.eval( 'a:confirm_id' ) ),
\ int( vim.eval( 'result' ) ) ) \ int( vim.eval( 'result' ) ) )
endfunction endfunction
" Boilerplate {{{ " Boilerplate {{{
let &cpoptions=s:save_cpo let &cpoptions=s:save_cpo
unlet s:save_cpo unlet s:save_cpo

View file

@ -42,13 +42,10 @@ function! s:UpdatePopup( id )
call popup_settext( a:id, buf ) call popup_settext( a:id, buf )
endfunction endfunction
function! s:YesNoDefaultFilter( default_value, id, key ) abort function! s:ConfirmKeyFilter( keys, id, key ) abort
if a:key ==# "\<CR>" if a:key ==# "\<CR>"
call popup_close( a:id, s:current_selection + 1 ) call popup_close( a:id, s:current_selection + 1 )
return 1 return 1
elseif a:key ==# 'D' || a:key ==# 'd'
call popup_close( a:id, a:default_value )
return 1
elseif index( [ "\<Tab>", "\<Right>" ], a:key ) >= 0 elseif index( [ "\<Tab>", "\<Right>" ], a:key ) >= 0
let s:current_selection = ( s:current_selection + 1 ) % len( s:selections ) let s:current_selection = ( s:current_selection + 1 ) % len( s:selections )
call s:UpdatePopup( a:id ) call s:UpdatePopup( a:id )
@ -58,9 +55,19 @@ function! s:YesNoDefaultFilter( default_value, id, key ) abort
\ ? len( s:selections ) - 1: s:current_selection - 1 \ ? len( s:selections ) - 1: s:current_selection - 1
call s:UpdatePopup( a:id ) call s:UpdatePopup( a:id )
return 1 return 1
elseif a:key ==# "\<Esc>" || a:key ==# "\<C-c>"
call popup_close( a:id, -1 )
return 1
endif endif
return popup_filter_yesno( a:id, a:key ) let index = 1
for key in a:keys
if a:key ==? key
call popup_close( a:id, index )
return 1
endif
let index += 1
endfor
endfunction endfunction
function! s:ConfirmCallback( confirm_id, id, result ) abort function! s:ConfirmCallback( confirm_id, id, result ) abort
@ -90,7 +97,8 @@ function! vimspector#internal#popup#Confirm(
\ confirm_id, \ confirm_id,
\ text, \ text,
\ options, \ options,
\ default_value ) abort \ default_value,
\ keys ) abort
silent! call prop_type_add( 'VimspectorSelectedItem', { silent! call prop_type_add( 'VimspectorSelectedItem', {
\ 'highlight': 'PMenuSel' \ 'highlight': 'PMenuSel'
@ -112,7 +120,7 @@ function! vimspector#internal#popup#Confirm(
let config = { let config = {
\ 'callback': function( 's:ConfirmCallback', [ a:confirm_id ] ), \ 'callback': function( 's:ConfirmCallback', [ a:confirm_id ] ),
\ 'filter': function( 's:YesNoDefaultFilter', [ a:default_value ] ), \ 'filter': function( 's:ConfirmKeyFilter', [ a:keys ] ),
\ 'mapping': v:false, \ 'mapping': v:false,
\ } \ }
let config = vimspector#internal#popup#SetBorderChars( config ) let config = vimspector#internal#popup#SetBorderChars( config )

View file

@ -14,7 +14,7 @@
# limitations under the License. # limitations under the License.
from vimspector.debug_session import DebugSession from vimspector.debug_session import DebugSession
from vimspector import utils from vimspector import utils, settings
class JavaDebugAdapter( object ): class JavaDebugAdapter( object ):
@ -36,8 +36,16 @@ class JavaDebugAdapter( object ):
'arguments': {}, 'arguments': {},
} ) } )
utils.Confirm( self.debug_session._api_prefix, mode = settings.Get( 'java_hotcodereplace_mode' )
'Code has changed, hot reload?', if mode == 'ask':
handler ) utils.Confirm( self.debug_session._api_prefix,
'Code has changed, hot reload?',
handler,
default_value = 1 )
elif mode == 'always':
self.debug_session._connection.DoRequest( None, {
'command': 'redefineClasses',
'arguments': {},
} )
elif body.get( 'message' ): elif body.get( 'message' ):
utils.UserMessage( 'Hot code replace: ' + body[ 'message' ] ) utils.UserMessage( 'Hot code replace: ' + body[ 'message' ] )

View file

@ -949,10 +949,12 @@ class DebugSession( object ):
def handle_choice( choice ): def handle_choice( choice ):
arguments = {} arguments = {}
if choice == 1: if choice == 1:
# yes
arguments[ 'terminateDebuggee' ] = True arguments[ 'terminateDebuggee' ] = True
elif choice == 0: elif choice == 2:
# no
arguments[ 'terminateDebuggee' ] = False arguments[ 'terminateDebuggee' ] = False
elif choice == -1: else:
# Abort # Abort
return return
@ -961,7 +963,9 @@ class DebugSession( object ):
utils.Confirm( self._api_prefix, utils.Confirm( self._api_prefix,
"Terminate debuggee?", "Terminate debuggee?",
handle_choice, handle_choice,
default_value = 3 ) default_value = 3,
options = [ '(Y)es', '(N)o', '(D)efault' ],
keys = [ 'y', 'n', 'd' ] )
def _PrepareAttach( self, adapter_config, launch_config ): def _PrepareAttach( self, adapter_config, launch_config ):

View file

@ -59,7 +59,10 @@ DEFAULTS = {
'expand_or_jump': [ '<CR>', '<2-LeftMouse>' ], 'expand_or_jump': [ '<CR>', '<2-LeftMouse>' ],
'focus_thread': [ '<leader><CR>' ], 'focus_thread': [ '<leader><CR>' ],
} }
} },
# Custom
'java_hotcodereplace_mode': 'ask',
} }

View file

@ -390,18 +390,26 @@ def ConfirmCallback( confirm_id, result ):
handler( result ) handler( result )
def Confirm( api_prefix, prompt, handler, default_value = 3, options = None ): def Confirm( api_prefix,
global CONFIRM_ID prompt,
handler,
default_value = 2,
options: list = None,
keys: list = None ):
if not options: if not options:
options = [ '(Y)es', '(N)o', '(D)efault' ] options = [ '(Y)es', '(N)o' ]
if not keys:
keys = [ 'y', 'n' ]
global CONFIRM_ID
CONFIRM_ID += 1 CONFIRM_ID += 1
CONFIRM[ CONFIRM_ID ] = handler CONFIRM[ CONFIRM_ID ] = handler
Call( f'vimspector#internal#{ api_prefix }popup#Confirm', Call( f'vimspector#internal#{ api_prefix }popup#Confirm',
CONFIRM_ID, CONFIRM_ID,
prompt, prompt,
options, options,
default_value ) default_value,
keys )
def AppendToBuffer( buf, line_or_lines, modified=False ): def AppendToBuffer( buf, line_or_lines, modified=False ):