Compare commits
13 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
208d18ef14 | ||
|
|
938dce1351 | ||
|
|
b7ca458672 | ||
|
|
81fa79ce58 | ||
|
|
e99559f6ad | ||
|
|
251a0ff314 | ||
|
|
5c8143a710 | ||
|
|
4fbafaa462 | ||
|
|
810946a1c1 | ||
|
|
68edda842a | ||
|
|
48076ba2ef | ||
|
|
7b37d4cbf5 | ||
|
|
57da7ff59b |
17 changed files with 493 additions and 70 deletions
|
|
@ -41,11 +41,11 @@ function! s:Enabled() abort
|
|||
return s:enabled
|
||||
endfunction
|
||||
|
||||
function! vimspector#Launch() abort
|
||||
function! vimspector#Launch( ... ) abort
|
||||
if !s:Enabled()
|
||||
return
|
||||
endif
|
||||
py3 _vimspector_session.Start()
|
||||
py3 _vimspector_session.Start( *vim.eval( 'a:000' ) )
|
||||
endfunction
|
||||
|
||||
function! vimspector#LaunchWithSettings( settings ) abort
|
||||
|
|
@ -234,6 +234,20 @@ function! vimspector#GoToFrame() abort
|
|||
py3 _vimspector_session.ExpandFrameOrThread()
|
||||
endfunction
|
||||
|
||||
function! vimspector#UpFrame() abort
|
||||
if !s:Enabled()
|
||||
return
|
||||
endif
|
||||
py3 _vimspector_session.UpFrame()
|
||||
endfunction
|
||||
|
||||
function! vimspector#DownFrame() abort
|
||||
if !s:Enabled()
|
||||
return
|
||||
endif
|
||||
py3 _vimspector_session.DownFrame()
|
||||
endfunction
|
||||
|
||||
function! vimspector#AddWatch( ... ) abort
|
||||
if !s:Enabled()
|
||||
return
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
@ -177,9 +173,13 @@ function! vimspector#internal#balloon#CursorFilter( winid, key ) abort
|
|||
\ . 'line_num = ' . line( '.', a:winid )
|
||||
\ . ')' )
|
||||
return 1
|
||||
elseif popup_filter_menu( a:winid, a:key )
|
||||
return 1
|
||||
else
|
||||
" Any other key dismisses the popup
|
||||
call vimspector#internal#balloon#Close()
|
||||
return 1
|
||||
endif
|
||||
|
||||
return popup_filter_menu( a:winid, a:key )
|
||||
endfunction
|
||||
|
||||
" }}}
|
||||
|
|
|
|||
|
|
@ -80,6 +80,31 @@ function! vimspector#internal#neopopup#HideSplash( id ) abort
|
|||
unlet s:db[ a:id ]
|
||||
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
|
||||
" in popup.vim)
|
||||
if result == 2
|
||||
" No is represented as 0
|
||||
let result = 0
|
||||
elseif result == 0
|
||||
" User pressed ESC/ctrl-c
|
||||
let result = -1
|
||||
elseif result == 3
|
||||
" Default
|
||||
let result = a:default_value
|
||||
endif
|
||||
|
||||
py3 __import__( 'vimspector', fromlist = [ 'utils' ] ).utils.ConfirmCallback(
|
||||
\ int( vim.eval( 'a:confirm_id' ) ),
|
||||
\ int( vim.eval( 'result' ) ) )
|
||||
endfunction
|
||||
" Boilerplate {{{
|
||||
let &cpoptions=s:save_cpo
|
||||
unlet s:save_cpo
|
||||
|
|
|
|||
|
|
@ -32,6 +32,105 @@ 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 ==# "\<CR>"
|
||||
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( [ "\<Tab>", "\<Right>" ], a:key ) >= 0
|
||||
let s:current_selection = ( s:current_selection + 1 ) % len( s:selections )
|
||||
call s:UpdatePopup( a:id )
|
||||
return 1
|
||||
elseif index( [ "\<S-Tab>", "\<Left>" ], 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 )
|
||||
endfunction
|
||||
|
||||
function! s:ConfirmCallback( confirm_id, id, result ) abort
|
||||
py3 __import__( 'vimspector', fromlist = [ 'utils' ] ).utils.ConfirmCallback(
|
||||
\ int( vim.eval( 'a:confirm_id' ) ),
|
||||
\ 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
|
||||
|
||||
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
|
||||
|
||||
return a:config
|
||||
endfunction
|
||||
|
||||
|
||||
" Boilerplate {{{
|
||||
let &cpoptions=s:save_cpo
|
||||
unlet s:save_cpo
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@ let s:mappings = get( g:, 'vimspector_enable_mappings', '' )
|
|||
|
||||
nnoremap <silent> <Plug>VimspectorContinue
|
||||
\ :<c-u>call vimspector#Continue()<CR>
|
||||
nnoremap <silent> <Plug>VimspectorLaunch
|
||||
\ :<c-u>call vimspector#Launch( v:true )<CR>
|
||||
nnoremap <silent> <Plug>VimspectorStop
|
||||
\ :<c-u>call vimspector#Stop()<CR>
|
||||
nnoremap <silent> <Plug>VimspectorRestart
|
||||
|
|
@ -67,6 +69,11 @@ nnoremap <silent> <Plug>VimspectorBalloonEval
|
|||
xnoremap <silent> <Plug>VimspectorBalloonEval
|
||||
\ :<c-u>call vimspector#ShowEvalBalloon( 1 )<CR>
|
||||
|
||||
nnoremap <silent> <Plug>VimspectorUpFrame
|
||||
\ :<c-u>call vimspector#UpFrame()<CR>
|
||||
nnoremap <silent> <Plug>VimspectorDownFrame
|
||||
\ :<c-u>call vimspector#DownFrame()<CR>
|
||||
|
||||
if s:mappings ==# 'VISUAL_STUDIO'
|
||||
nmap <F5> <Plug>VimspectorContinue
|
||||
nmap <S-F5> <Plug>VimspectorStop
|
||||
|
|
@ -79,6 +86,7 @@ if s:mappings ==# 'VISUAL_STUDIO'
|
|||
nmap <S-F11> <Plug>VimspectorStepOut
|
||||
elseif s:mappings ==# 'HUMAN'
|
||||
nmap <F5> <Plug>VimspectorContinue
|
||||
nmap <leader><F5> <Plug>VimspectorLaunch
|
||||
nmap <F3> <Plug>VimspectorStop
|
||||
nmap <F4> <Plug>VimspectorRestart
|
||||
nmap <F6> <Plug>VimspectorPause
|
||||
|
|
|
|||
43
python3/vimspector/custom/java.py
Normal file
43
python3/vimspector/custom/java.py
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
# vimspector - A multi-language debugging system for Vim
|
||||
# Copyright 2021 Ben Jackson
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from vimspector.debug_session import DebugSession
|
||||
from vimspector import utils
|
||||
|
||||
|
||||
class JavaDebugAdapter( object ):
|
||||
def __init__( self, debug_session: DebugSession ):
|
||||
self.debug_session = debug_session
|
||||
|
||||
def OnEvent_hotcodereplace( self, message ):
|
||||
# Hack for java debug server hot-code-replace
|
||||
body = message.get( 'body' ) or {}
|
||||
|
||||
if body.get( 'type' ) != 'hotcodereplace':
|
||||
return
|
||||
|
||||
if body.get( 'changeType' ) == 'BUILD_COMPLETE':
|
||||
def handler( result ):
|
||||
if result == 1:
|
||||
self.debug_session._connection.DoRequest( None, {
|
||||
'command': 'redefineClasses',
|
||||
'arguments': {},
|
||||
} )
|
||||
|
||||
utils.Confirm( self.debug_session._api_prefix,
|
||||
'Code has changed, hot reload?',
|
||||
handler )
|
||||
elif body.get( 'message' ):
|
||||
utils.UserMessage( 'Hot code replace: ' + body[ 'message' ] )
|
||||
|
|
@ -29,14 +29,14 @@ class PendingRequest( object ):
|
|||
|
||||
|
||||
class DebugAdapterConnection( object ):
|
||||
def __init__( self, handler, send_func ):
|
||||
def __init__( self, handlers, send_func ):
|
||||
self._logger = logging.getLogger( __name__ )
|
||||
utils.SetUpLogging( self._logger )
|
||||
|
||||
self._Write = send_func
|
||||
self._SetState( 'READ_HEADER' )
|
||||
self._buffer = bytes()
|
||||
self._handler = handler
|
||||
self._handlers = handlers
|
||||
self._next_message_id = 0
|
||||
self._outstanding_requests = {}
|
||||
|
||||
|
|
@ -124,7 +124,7 @@ class DebugAdapterConnection( object ):
|
|||
|
||||
def Reset( self ):
|
||||
self._Write = None
|
||||
self._handler = None
|
||||
self._handlers = None
|
||||
|
||||
while self._outstanding_requests:
|
||||
_, request = self._outstanding_requests.popitem()
|
||||
|
|
@ -237,7 +237,7 @@ class DebugAdapterConnection( object ):
|
|||
|
||||
|
||||
def _OnMessageReceived( self, message ):
|
||||
if not self._handler:
|
||||
if not self._handlers:
|
||||
return
|
||||
|
||||
if message[ 'type' ] == 'response':
|
||||
|
|
@ -270,25 +270,21 @@ class DebugAdapterConnection( object ):
|
|||
self._logger.error( 'Request failed: {0}'.format( reason ) )
|
||||
if request.failure_handler:
|
||||
request.failure_handler( reason, message )
|
||||
elif 'OnFailure' in dir( self._handler ):
|
||||
self._handler.OnFailure( reason, request.msg, message )
|
||||
else:
|
||||
utils.UserMessage( 'Request failed: {0}'.format( reason ) )
|
||||
for h in self._handlers:
|
||||
if 'OnFailure' in dir( h ):
|
||||
h.OnFailure( reason, request.msg, message )
|
||||
|
||||
elif message[ 'type' ] == 'event':
|
||||
method = 'OnEvent_' + message[ 'event' ]
|
||||
if method in dir( self._handler ):
|
||||
getattr( self._handler, method )( message )
|
||||
else:
|
||||
utils.UserMessage( 'Unhandled event: {0}'.format( message[ 'event' ] ),
|
||||
persist = True )
|
||||
for h in self._handlers:
|
||||
if method in dir( h ):
|
||||
getattr( h, method )( message )
|
||||
elif message[ 'type' ] == 'request':
|
||||
method = 'OnRequest_' + message[ 'command' ]
|
||||
if method in dir( self._handler ):
|
||||
getattr( self._handler, method )( message )
|
||||
else:
|
||||
utils.UserMessage(
|
||||
'Unhandled request: {0}'.format( message[ 'command' ] ),
|
||||
persist = True )
|
||||
for h in self._handlers:
|
||||
if method in dir( h ):
|
||||
getattr( h, method )( message )
|
||||
|
||||
|
||||
def _KillTimer( request ):
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import shlex
|
|||
import subprocess
|
||||
import functools
|
||||
import vim
|
||||
import importlib
|
||||
|
||||
from vimspector import ( breakpoints,
|
||||
code,
|
||||
|
|
@ -99,7 +100,7 @@ class DebugSession( object ):
|
|||
|
||||
return launch_config_file, configurations
|
||||
|
||||
def Start( self, launch_variables = None ):
|
||||
def Start( self, force_choose=False, launch_variables = None ):
|
||||
# We mutate launch_variables, so don't mutate the default argument.
|
||||
# https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments
|
||||
if launch_variables is None:
|
||||
|
|
@ -134,6 +135,11 @@ class DebugSession( object ):
|
|||
|
||||
if 'configuration' in launch_variables:
|
||||
configuration_name = launch_variables.pop( 'configuration' )
|
||||
elif force_choose:
|
||||
# Always display the menu
|
||||
configuration_name = utils.SelectFromList(
|
||||
'Which launch configuration?',
|
||||
sorted( configurations.keys() ) )
|
||||
elif ( len( configurations ) == 1 and
|
||||
next( iter( configurations.values() ) ).get( "autoselect", True ) ):
|
||||
configuration_name = next( iter( configurations.keys() ) )
|
||||
|
|
@ -571,6 +577,14 @@ class DebugSession( object ):
|
|||
def ExpandFrameOrThread( self ):
|
||||
self._stackTraceView.ExpandFrameOrThread()
|
||||
|
||||
@IfConnected()
|
||||
def UpFrame( self ):
|
||||
self._stackTraceView.UpFrame()
|
||||
|
||||
@IfConnected
|
||||
def DownFrame( self ):
|
||||
self._stackTraceView.DownCFrame()
|
||||
|
||||
def ToggleLog( self ):
|
||||
if self._HasUI():
|
||||
return self.ShowOutput( 'Vimspector' )
|
||||
|
|
@ -655,6 +669,30 @@ class DebugSession( object ):
|
|||
vim.command( 'tab split' )
|
||||
self._uiTab = vim.current.tabpage
|
||||
|
||||
mode = settings.Get( 'ui_mode' )
|
||||
|
||||
if mode == 'auto':
|
||||
# Go vertical if there isn't enough horizontal space for at least:
|
||||
# the left bar width
|
||||
# + the code min width
|
||||
# + the terminal min width
|
||||
# + enough space for a sign column and number column?
|
||||
min_width = ( settings.Int( 'sidebar_width' )
|
||||
+ 1 + 2 + 3
|
||||
+ settings.Int( 'code_minwidth' )
|
||||
+ 1 + settings.Int( 'terminal_minwidth' ) )
|
||||
|
||||
mode = ( 'vertical'
|
||||
if vim.options[ 'columns' ] < min_width
|
||||
else 'horizontal' )
|
||||
|
||||
if mode == 'vertical':
|
||||
self._SetUpUIVertical()
|
||||
else:
|
||||
self._SetUpUIHorizontal()
|
||||
|
||||
|
||||
def _SetUpUIHorizontal( self ):
|
||||
# Code window
|
||||
code_window = vim.current.window
|
||||
self._codeView = code.CodeView( code_window, self._api_prefix )
|
||||
|
|
@ -695,6 +733,66 @@ class DebugSession( object ):
|
|||
# TODO: If/when we support multiple sessions, we'll need some way to
|
||||
# indicate which tab was created and store all the tabs
|
||||
vim.vars[ 'vimspector_session_windows' ] = {
|
||||
'mode': 'horizontal',
|
||||
'tabpage': self._uiTab.number,
|
||||
'code': utils.WindowID( code_window, self._uiTab ),
|
||||
'stack_trace': utils.WindowID( stack_trace_window, self._uiTab ),
|
||||
'variables': utils.WindowID( vars_window, self._uiTab ),
|
||||
'watches': utils.WindowID( watch_window, self._uiTab ),
|
||||
'output': utils.WindowID( output_window, self._uiTab ),
|
||||
'eval': None # this is going to be updated every time eval popup is opened
|
||||
}
|
||||
with utils.RestoreCursorPosition():
|
||||
with utils.RestoreCurrentWindow():
|
||||
with utils.RestoreCurrentBuffer( vim.current.window ):
|
||||
vim.command( 'doautocmd User VimspectorUICreated' )
|
||||
|
||||
|
||||
def _SetUpUIVertical( self ):
|
||||
# Code window
|
||||
code_window = vim.current.window
|
||||
self._codeView = code.CodeView( code_window, self._api_prefix )
|
||||
|
||||
# Call stack
|
||||
vim.command(
|
||||
f'topleft { settings.Int( "topbar_height" ) }new' )
|
||||
stack_trace_window = vim.current.window
|
||||
one_third = int( vim.eval( 'winwidth( 0 )' ) ) / 3
|
||||
self._stackTraceView = stack_trace.StackTraceView( self,
|
||||
stack_trace_window )
|
||||
|
||||
|
||||
# Watches
|
||||
vim.command( 'leftabove vertical new' )
|
||||
watch_window = vim.current.window
|
||||
|
||||
# Variables
|
||||
vim.command( 'leftabove vertical new' )
|
||||
vars_window = vim.current.window
|
||||
|
||||
|
||||
with utils.LetCurrentWindow( vars_window ):
|
||||
vim.command( f'{ one_third }wincmd |' )
|
||||
with utils.LetCurrentWindow( watch_window ):
|
||||
vim.command( f'{ one_third }wincmd |' )
|
||||
with utils.LetCurrentWindow( stack_trace_window ):
|
||||
vim.command( f'{ one_third }wincmd |' )
|
||||
|
||||
self._variablesView = variables.VariablesView( vars_window,
|
||||
watch_window )
|
||||
|
||||
|
||||
# Output/logging
|
||||
vim.current.window = code_window
|
||||
vim.command( f'rightbelow { settings.Int( "bottombar_height" ) }new' )
|
||||
output_window = vim.current.window
|
||||
self._outputView = output.DAPOutputView( output_window,
|
||||
self._api_prefix )
|
||||
|
||||
# TODO: If/when we support multiple sessions, we'll need some way to
|
||||
# indicate which tab was created and store all the tabs
|
||||
vim.vars[ 'vimspector_session_windows' ] = {
|
||||
'mode': 'vertical',
|
||||
'tabpage': self._uiTab.number,
|
||||
'code': utils.WindowID( code_window, self._uiTab ),
|
||||
'stack_trace': utils.WindowID( stack_trace_window, self._uiTab ),
|
||||
|
|
@ -781,8 +879,21 @@ class DebugSession( object ):
|
|||
self._splash_screen,
|
||||
"Unable to start adapter" )
|
||||
else:
|
||||
if 'custom_handler' in self._adapter:
|
||||
spec = self._adapter[ 'custom_handler' ]
|
||||
if isinstance( spec, dict ):
|
||||
module = spec[ 'module' ]
|
||||
cls = spec[ 'class' ]
|
||||
else:
|
||||
module, cls = spec.rsplit( '.', 1 )
|
||||
|
||||
CustomHandler = getattr( importlib.import_module( module ), cls )
|
||||
handlers = [ CustomHandler( self ), self ]
|
||||
else:
|
||||
handlers = [ self ]
|
||||
|
||||
self._connection = debug_adapter_connection.DebugAdapterConnection(
|
||||
self,
|
||||
handlers,
|
||||
lambda msg: utils.Call(
|
||||
"vimspector#internal#{}#Send".format( self._connection_type ),
|
||||
msg ) )
|
||||
|
|
@ -790,39 +901,52 @@ class DebugSession( object ):
|
|||
self._logger.info( 'Debug Adapter Started' )
|
||||
|
||||
def _StopDebugAdapter( self, interactive = False, callback = None ):
|
||||
self._splash_screen = utils.DisplaySplash(
|
||||
self._api_prefix,
|
||||
self._splash_screen,
|
||||
"Shutting down debug adapter..." )
|
||||
def disconnect( arguments = {} ):
|
||||
self._splash_screen = utils.DisplaySplash(
|
||||
self._api_prefix,
|
||||
self._splash_screen,
|
||||
"Shutting down debug adapter..." )
|
||||
|
||||
def handler( *args ):
|
||||
self._splash_screen = utils.HideSplash( self._api_prefix,
|
||||
self._splash_screen )
|
||||
def handler( *args ):
|
||||
self._splash_screen = utils.HideSplash( self._api_prefix,
|
||||
self._splash_screen )
|
||||
|
||||
if callback:
|
||||
self._logger.debug( "Setting server exit handler before disconnect" )
|
||||
assert not self._run_on_server_exit
|
||||
self._run_on_server_exit = callback
|
||||
if callback:
|
||||
self._logger.debug( "Setting server exit handler before disconnect" )
|
||||
assert not self._run_on_server_exit
|
||||
self._run_on_server_exit = callback
|
||||
|
||||
vim.eval( 'vimspector#internal#{}#StopDebugSession()'.format(
|
||||
self._connection_type ) )
|
||||
vim.eval( 'vimspector#internal#{}#StopDebugSession()'.format(
|
||||
self._connection_type ) )
|
||||
|
||||
arguments = {}
|
||||
if ( interactive and
|
||||
self._server_capabilities.get( 'supportTerminateDebuggee' ) ):
|
||||
if self._stackTraceView.AnyThreadsRunning():
|
||||
choice = utils.AskForInput( "Terminate debuggee [Y/N/default]? ", "" )
|
||||
if choice == "Y" or choice == "y":
|
||||
self._connection.DoRequest( handler, {
|
||||
'command': 'disconnect',
|
||||
'arguments': {},
|
||||
}, failure_handler = handler, timeout = 5000 )
|
||||
|
||||
if not interactive:
|
||||
disconnect()
|
||||
elif not self._server_capabilities.get( 'supportTerminateDebuggee' ):
|
||||
disconnect()
|
||||
elif not self._stackTraceView.AnyThreadsRunning():
|
||||
disconnect()
|
||||
else:
|
||||
def handle_choice( choice ):
|
||||
arguments = {}
|
||||
if choice == 1:
|
||||
arguments[ 'terminateDebuggee' ] = True
|
||||
elif choice == "N" or choice == 'n':
|
||||
elif choice == 0:
|
||||
arguments[ 'terminateDebuggee' ] = False
|
||||
elif choice == -1:
|
||||
# Abort
|
||||
return
|
||||
|
||||
self._connection.DoRequest( handler, {
|
||||
'command': 'disconnect',
|
||||
'arguments': arguments,
|
||||
}, failure_handler = handler, timeout = 5000 )
|
||||
disconnect( arguments )
|
||||
|
||||
# TODO: Use the 'tarminate' request if supportsTerminateRequest set
|
||||
utils.Confirm( self._api_prefix,
|
||||
"Terminate debuggee?",
|
||||
handle_choice,
|
||||
default_value = 3 )
|
||||
|
||||
|
||||
def _PrepareAttach( self, adapter_config, launch_config ):
|
||||
|
|
|
|||
|
|
@ -159,7 +159,8 @@ GADGETS = {
|
|||
"port": "${DAPPort}",
|
||||
"configuration": {
|
||||
"cwd": "${workspaceRoot}"
|
||||
}
|
||||
},
|
||||
'custom_handler': 'vimspector.custom.java.JavaDebugAdapter'
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -20,11 +20,20 @@ from vimspector import utils
|
|||
|
||||
DEFAULTS = {
|
||||
# UI
|
||||
'bottombar_height': 10,
|
||||
'sidebar_width': 50,
|
||||
'code_minwidth': 82,
|
||||
'terminal_maxwidth': 80,
|
||||
'terminal_minwidth': 10,
|
||||
'ui_mode': 'auto',
|
||||
'bottombar_height': 10,
|
||||
|
||||
# For ui_mode = 'horizontal':
|
||||
'sidebar_width': 50,
|
||||
'code_minwidth': 82,
|
||||
'terminal_maxwidth': 80,
|
||||
'terminal_minwidth': 10,
|
||||
|
||||
# For ui_mode = 'vertical':
|
||||
'topbar_height': 15,
|
||||
'code_minheight': 20,
|
||||
'terminal_maxheight': 15,
|
||||
'terminal_minheight': 5,
|
||||
|
||||
# Signs
|
||||
'sign_priority': {
|
||||
|
|
|
|||
|
|
@ -367,6 +367,42 @@ class StackTraceView( object ):
|
|||
self._JumpToFrame( frame )
|
||||
|
||||
|
||||
|
||||
def _GetFrameOffset( self, delta ):
|
||||
thread: Thread
|
||||
for thread in self._threads:
|
||||
if thread != self._current_thread:
|
||||
continue
|
||||
|
||||
if not thread.stacktrace:
|
||||
return
|
||||
|
||||
frame_idx = None
|
||||
for index, frame in enumerate( thread.stacktrace ):
|
||||
if frame == self._current_frame:
|
||||
frame_idx = index
|
||||
break
|
||||
|
||||
if frame_idx is not None:
|
||||
target_idx = frame_idx + delta
|
||||
if target_idx >= 0 and target_idx < len( thread.stacktrace ):
|
||||
return thread.stacktrace[ target_idx ]
|
||||
|
||||
break
|
||||
|
||||
|
||||
def UpFrame( self ):
|
||||
frame = self._GetFrameOffset( self, -1 )
|
||||
if frame:
|
||||
self._JumpToFrame( frame, 'up' )
|
||||
|
||||
|
||||
def DownFrame( self ):
|
||||
frame = self._GetFrameOffset( self, 1 )
|
||||
if frame:
|
||||
self._JumpToFrame( frame, 'down' )
|
||||
|
||||
|
||||
def AnyThreadsRunning( self ):
|
||||
for thread in self._threads:
|
||||
if thread.state != Thread.TERMINATED:
|
||||
|
|
|
|||
|
|
@ -23,7 +23,18 @@ def LaunchTerminal( api_prefix,
|
|||
env = params.get( 'env' ) or {}
|
||||
|
||||
term_options = {
|
||||
'vertical': 1,
|
||||
# Use a vsplit in widw mode, and a horizontal split in narrow mode
|
||||
'vertical': (
|
||||
# Use a vsplit if we're in horizontal mode, or if we're in vertical mode,
|
||||
# but there's enough space for the code and the terminal horizontally
|
||||
# (this gives more vertical space, which becomes at at premium)
|
||||
vim.vars[ 'vimspector_session_windows' ][ 'mode' ] == 'horizontal' or
|
||||
vim.options[ 'columns' ] >= (
|
||||
settings.Int( 'terminal_maxwidth' ) +
|
||||
settings.Int( 'code_minwidth' ) +
|
||||
1 # for the split decoration
|
||||
)
|
||||
),
|
||||
'norestore': 1,
|
||||
'cwd': cwd,
|
||||
'env': env,
|
||||
|
|
@ -50,13 +61,23 @@ def LaunchTerminal( api_prefix,
|
|||
# If we're making a vertical split from the code window, make it no more
|
||||
# than 80 columns and no fewer than 10. Also try and keep the code window
|
||||
# at least 82 columns
|
||||
if term_options[ 'vertical' ] and not term_options.get( 'curwin', 0 ):
|
||||
if term_options.get( 'curwin', 0 ):
|
||||
pass
|
||||
elif term_options[ 'vertical' ]:
|
||||
term_options[ 'term_cols' ] = max(
|
||||
min ( int( vim.eval( 'winwidth( 0 )' ) )
|
||||
- settings.Int( 'code_minwidth' ),
|
||||
settings.Int( 'terminal_maxwidth' ) ),
|
||||
settings.Int( 'terminal_minwidth' )
|
||||
)
|
||||
else:
|
||||
term_options[ 'term_rows' ] = max(
|
||||
min ( int( vim.eval( 'winheight( 0 )' ) )
|
||||
- settings.Int( 'code_minheight' ),
|
||||
settings.Int( 'terminal_maxheight' ) ),
|
||||
settings.Int( 'terminal_minheight' )
|
||||
)
|
||||
|
||||
|
||||
buffer_number = int(
|
||||
utils.Call(
|
||||
|
|
|
|||
|
|
@ -375,6 +375,35 @@ def AskForInput( prompt, default_value = None, completion = None ):
|
|||
return None
|
||||
|
||||
|
||||
CONFIRM = {}
|
||||
CONFIRM_ID = 0
|
||||
|
||||
def ConfirmCallback( confirm_id, result ):
|
||||
try:
|
||||
handler = CONFIRM.pop( confirm_id )
|
||||
except KeyError:
|
||||
UserMessage( f"Internal error: unexpected callback id { confirm_id }",
|
||||
persist = True,
|
||||
error = True )
|
||||
return
|
||||
|
||||
handler( result )
|
||||
|
||||
|
||||
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 )
|
||||
|
||||
|
||||
def AppendToBuffer( buf, line_or_lines, modified=False ):
|
||||
line = 1
|
||||
try:
|
||||
|
|
@ -403,8 +432,10 @@ def AppendToBuffer( buf, line_or_lines, modified=False ):
|
|||
|
||||
|
||||
|
||||
def ClearBuffer( buf ):
|
||||
def ClearBuffer( buf, modified = False ):
|
||||
buf[ : ] = None
|
||||
if not modified:
|
||||
buf.options[ 'modified' ] = False
|
||||
|
||||
|
||||
def SetBufferContents( buf, lines, modified=False ):
|
||||
|
|
@ -494,7 +525,6 @@ def _Substitute( template, mapping ):
|
|||
if mo.group( 'braceddefault' ) is not None:
|
||||
named = mo.group( 'defname' )
|
||||
if named not in mapping:
|
||||
''
|
||||
raise MissingSubstitution(
|
||||
named,
|
||||
mo.group( 'default' ).replace( '\\}', '}' ) )
|
||||
|
|
@ -536,8 +566,11 @@ def ExpandReferencesInString( orig_s,
|
|||
if default_value is None and e.default_value is not None:
|
||||
try:
|
||||
default_value = _Substitute( e.default_value, mapping )
|
||||
except MissingSubstitution:
|
||||
default_value = e.default_value
|
||||
except MissingSubstitution as e2:
|
||||
if e2.name in calculus:
|
||||
default_value = calculus[ e2.name ]()
|
||||
else:
|
||||
default_value = e.default_value
|
||||
|
||||
mapping[ key ] = AskForInput( 'Enter value for {}: '.format( key ),
|
||||
default_value )
|
||||
|
|
|
|||
6
rebuild
Executable file
6
rebuild
Executable file
|
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
./install_gadget.py --all --force-all --basedir ../vimspector-fidessa
|
||||
|
||||
|
|
@ -115,12 +115,16 @@ function! s:OnDebugEnd() abort
|
|||
|
||||
let original_buf = bufnr()
|
||||
let hidden = &hidden
|
||||
augroup VimspectorSwapExists
|
||||
au!
|
||||
autocmd SwapExists * let v:swapchoice='o'
|
||||
augroup END
|
||||
|
||||
try
|
||||
set hidden
|
||||
for bufnr in keys( s:mapped )
|
||||
try
|
||||
execute 'noautocmd buffer' bufnr
|
||||
execute 'buffer' bufnr
|
||||
silent! nunmap <buffer> <LocalLeader>dn
|
||||
silent! nunmap <buffer> <LocalLeader>ds
|
||||
silent! nunmap <buffer> <LocalLeader>df
|
||||
|
|
@ -136,13 +140,15 @@ function! s:OnDebugEnd() abort
|
|||
let &hidden = hidden
|
||||
endtry
|
||||
|
||||
au! VimspectorSwapExists
|
||||
|
||||
let s:mapped = {}
|
||||
endfunction
|
||||
|
||||
augroup TestCustomMappings
|
||||
au!
|
||||
autocmd User VimspectorJumpedToFrame call s:OnJumpToFrame()
|
||||
autocmd User VimspectorDebugEnded call s:OnDebugEnd()
|
||||
autocmd User VimspectorDebugEnded ++nested call s:OnDebugEnd()
|
||||
augroup END
|
||||
|
||||
" }}}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<artifactId>TestApplication</artifactId>
|
||||
<version>1</version>
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
</properties>
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ class TestExpandReferencesInDict( unittest.TestCase ):
|
|||
'one': '${one}',
|
||||
'two': '${one} and ${two}',
|
||||
'three': '${three}',
|
||||
'three_with_default': '${three_with_default:${three\\}}', # uses calculus
|
||||
'four': '${four}',
|
||||
'five': '${five}',
|
||||
'list': [ '*${words}' ],
|
||||
|
|
@ -58,6 +59,7 @@ class TestExpandReferencesInDict( unittest.TestCase ):
|
|||
'one': 'one',
|
||||
'two': 'one and TWO',
|
||||
'three': '3',
|
||||
'three_with_default': '3',
|
||||
'four': 'typed text',
|
||||
'five': '5ive!',
|
||||
'list': [ 'these', 'are', 'some', 'words' ],
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue