Merge branch 'master' into master
This commit is contained in:
commit
91e0426e88
13 changed files with 363 additions and 61 deletions
18
README.md
18
README.md
|
|
@ -59,6 +59,7 @@ For detailed explanatin of the `.vimspector.json` format, see the
|
||||||
* [Console autocompletion](#console-autocompletion)
|
* [Console autocompletion](#console-autocompletion)
|
||||||
* [Log View](#log-view)
|
* [Log View](#log-view)
|
||||||
* [Closing debugger](#closing-debugger)
|
* [Closing debugger](#closing-debugger)
|
||||||
|
* [Terminate debuggee](#terminate-debuggee)
|
||||||
* [Debug profile configuration](#debug-profile-configuration)
|
* [Debug profile configuration](#debug-profile-configuration)
|
||||||
* [C, C , Rust, etc.](#c-c-rust-etc)
|
* [C, C , Rust, etc.](#c-c-rust-etc)
|
||||||
* [C Remote debugging](#c-remote-debugging)
|
* [C Remote debugging](#c-remote-debugging)
|
||||||
|
|
@ -76,6 +77,7 @@ For detailed explanatin of the `.vimspector.json` format, see the
|
||||||
* [Debug cli application](#debug-cli-application)
|
* [Debug cli application](#debug-cli-application)
|
||||||
* [JavaScript, TypeScript, etc.](#javascript-typescript-etc)
|
* [JavaScript, TypeScript, etc.](#javascript-typescript-etc)
|
||||||
* [Java](#java)
|
* [Java](#java)
|
||||||
|
* [Hot code replace](#hot-code-replace)
|
||||||
* [Usage with YouCompleteMe](#usage-with-youcompleteme)
|
* [Usage with YouCompleteMe](#usage-with-youcompleteme)
|
||||||
* [Other LSP clients](#other-lsp-clients)
|
* [Other LSP clients](#other-lsp-clients)
|
||||||
* [Lua](#lua)
|
* [Lua](#lua)
|
||||||
|
|
@ -91,7 +93,7 @@ For detailed explanatin of the `.vimspector.json` format, see the
|
||||||
* [Example](#example)
|
* [Example](#example)
|
||||||
* [FAQ](#faq)
|
* [FAQ](#faq)
|
||||||
|
|
||||||
<!-- Added by: ben, at: Sun 21 Feb 2021 21:15:32 GMT -->
|
<!-- Added by: ben, at: Fri 19 Mar 2021 22:57:28 GMT -->
|
||||||
|
|
||||||
<!--te-->
|
<!--te-->
|
||||||
|
|
||||||
|
|
@ -1591,6 +1593,20 @@ editor plugin to use Java. I recommend [YouCompleteMe][], which has full support
|
||||||
for jdt.ls, and most importantly a trivial way to load the debug adapter and to
|
for jdt.ls, and most importantly a trivial way to load the debug adapter and to
|
||||||
use it with Vimspector.
|
use it with Vimspector.
|
||||||
|
|
||||||
|
### Hot code replace
|
||||||
|
|
||||||
|
When using the [java debug server][java-debug-server], Vimspector supports the
|
||||||
|
hot code replace custom feature. By default, when the underlying class files
|
||||||
|
change, vimspector asks the user if they wish to reload these classes at
|
||||||
|
runtime.
|
||||||
|
|
||||||
|
This behaviour can be customised:
|
||||||
|
|
||||||
|
* `let g:ycm_java_hotcodereplace_mode = 'ask'` - the default, ask the user for
|
||||||
|
each reload.
|
||||||
|
* `let g:ycm_java_hotcodereplace_mode = 'always'` - don't ask, always reload
|
||||||
|
* `let g:ycm_java_hotcodereplace_mode = 'never'` - don't ask, never reload
|
||||||
|
|
||||||
### Usage with YouCompleteMe
|
### Usage with YouCompleteMe
|
||||||
|
|
||||||
* Set up [YCM for java][YcmJava].
|
* Set up [YCM for java][YcmJava].
|
||||||
|
|
|
||||||
|
|
@ -41,11 +41,11 @@ function! s:Enabled() abort
|
||||||
return s:enabled
|
return s:enabled
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! vimspector#Launch() abort
|
function! vimspector#Launch( ... ) abort
|
||||||
if !s:Enabled()
|
if !s:Enabled()
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
py3 _vimspector_session.Start()
|
py3 _vimspector_session.Start( *vim.eval( 'a:000' ) )
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! vimspector#LaunchWithSettings( settings ) abort
|
function! vimspector#LaunchWithSettings( settings ) abort
|
||||||
|
|
|
||||||
|
|
@ -71,11 +71,7 @@ function! vimspector#internal#balloon#CreateTooltip( is_hover, ... ) abort
|
||||||
\ 'callback': 'vimspector#internal#balloon#CloseCallback',
|
\ 'callback': 'vimspector#internal#balloon#CloseCallback',
|
||||||
\ }
|
\ }
|
||||||
|
|
||||||
" When ambiwidth is single, use prettier characters for the border. This
|
let config = vimspector#internal#popup#SetBorderChars( config )
|
||||||
" would look silly when ambiwidth is double.
|
|
||||||
if &ambiwidth ==# 'single' && &encoding ==? 'utf-8'
|
|
||||||
let config[ 'borderchars' ] = [ '─', '│', '─', '│', '╭', '╮', '┛', '╰' ]
|
|
||||||
endif
|
|
||||||
|
|
||||||
if a:is_hover
|
if a:is_hover
|
||||||
let config[ 'filter' ] = 'vimspector#internal#balloon#MouseFilter'
|
let config[ 'filter' ] = 'vimspector#internal#balloon#MouseFilter'
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,56 @@ function! vimspector#internal#neopopup#HideSplash( id ) abort
|
||||||
unlet s:db[ a:id ]
|
unlet s:db[ a:id ]
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! vimspector#internal#neopopup#Confirm( confirm_id,
|
||||||
|
\ text,
|
||||||
|
\ options,
|
||||||
|
\ default_value,
|
||||||
|
\ keys ) 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()...
|
||||||
|
" 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.
|
||||||
|
let prompt = a:text
|
||||||
|
for opt in a:options
|
||||||
|
let prompt .= ' ' . opt
|
||||||
|
endfor
|
||||||
|
let prompt .= ': '
|
||||||
|
|
||||||
|
try
|
||||||
|
let result = input( prompt, a:keys[ a:default_value - 1 ] )
|
||||||
|
catch /.*/
|
||||||
|
let result = -1
|
||||||
|
endtry
|
||||||
|
|
||||||
|
" Map the results to what the vim popup stuff would return (s:ConfirmCallback
|
||||||
|
" in popup.vim), i.e.:
|
||||||
|
" - 1-based index of selected item, or
|
||||||
|
" - -1 or 0 for cancellation
|
||||||
|
if result == ''
|
||||||
|
" User pressed ESC/ctrl-c
|
||||||
|
let result = -1
|
||||||
|
else
|
||||||
|
let index = 1
|
||||||
|
for k in a:keys
|
||||||
|
if k ==? result
|
||||||
|
let result = index
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
let index += 1
|
||||||
|
endfor
|
||||||
|
|
||||||
|
if index > len( a:keys )
|
||||||
|
let result = -1
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
py3 __import__( 'vimspector', fromlist = [ 'utils' ] ).utils.ConfirmCallback(
|
||||||
|
\ int( vim.eval( 'a:confirm_id' ) ),
|
||||||
|
\ int( vim.eval( 'result' ) ) )
|
||||||
|
endfunction
|
||||||
|
|
||||||
" Boilerplate {{{
|
" Boilerplate {{{
|
||||||
let &cpoptions=s:save_cpo
|
let &cpoptions=s:save_cpo
|
||||||
unlet s:save_cpo
|
unlet s:save_cpo
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
" See the License for the specific language governing permissions and
|
" See the License for the specific language governing permissions and
|
||||||
" limitations under the License.
|
" limitations under the License.
|
||||||
|
scriptencoding utf-8
|
||||||
|
|
||||||
|
|
||||||
" Boilerplate {{{
|
" Boilerplate {{{
|
||||||
|
|
@ -32,6 +33,113 @@ function! vimspector#internal#popup#HideSplash( id ) abort
|
||||||
call popup_hide( a:id )
|
call popup_hide( a:id )
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
let s:current_selection = 0
|
||||||
|
let s:selections = []
|
||||||
|
let s:text = []
|
||||||
|
|
||||||
|
function! s:UpdatePopup( id ) abort
|
||||||
|
let buf = copy( s:text )
|
||||||
|
call extend( buf, s:DrawButtons() )
|
||||||
|
call popup_settext( a:id, buf )
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:ConfirmKeyFilter( keys, id, key ) abort
|
||||||
|
if a:key ==# "\<CR>"
|
||||||
|
call popup_close( a:id, s:current_selection + 1 )
|
||||||
|
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
|
||||||
|
elseif a:key ==# "\<Esc>" || a:key ==# "\<C-c>"
|
||||||
|
call popup_close( a:id, -1 )
|
||||||
|
return 1
|
||||||
|
endif
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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,
|
||||||
|
\ keys ) 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:ConfirmKeyFilter', [ a:keys ] ),
|
||||||
|
\ 'mapping': v:false,
|
||||||
|
\ }
|
||||||
|
let config = vimspector#internal#popup#SetBorderChars( config )
|
||||||
|
|
||||||
|
return popup_dialog( buf, config )
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vimspector#internal#popup#SetBorderChars( config ) abort
|
||||||
|
" 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 {{{
|
" Boilerplate {{{
|
||||||
let &cpoptions=s:save_cpo
|
let &cpoptions=s:save_cpo
|
||||||
unlet s:save_cpo
|
unlet s:save_cpo
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,8 @@ let s:mappings = get( g:, 'vimspector_enable_mappings', '' )
|
||||||
|
|
||||||
nnoremap <silent> <Plug>VimspectorContinue
|
nnoremap <silent> <Plug>VimspectorContinue
|
||||||
\ :<c-u>call vimspector#Continue()<CR>
|
\ :<c-u>call vimspector#Continue()<CR>
|
||||||
|
nnoremap <silent> <Plug>VimspectorLaunch
|
||||||
|
\ :<c-u>call vimspector#Launch( v:true )<CR>
|
||||||
nnoremap <silent> <Plug>VimspectorStop
|
nnoremap <silent> <Plug>VimspectorStop
|
||||||
\ :<c-u>call vimspector#Stop()<CR>
|
\ :<c-u>call vimspector#Stop()<CR>
|
||||||
nnoremap <silent> <Plug>VimspectorRestart
|
nnoremap <silent> <Plug>VimspectorRestart
|
||||||
|
|
@ -84,6 +86,7 @@ if s:mappings ==# 'VISUAL_STUDIO'
|
||||||
nmap <S-F11> <Plug>VimspectorStepOut
|
nmap <S-F11> <Plug>VimspectorStepOut
|
||||||
elseif s:mappings ==# 'HUMAN'
|
elseif s:mappings ==# 'HUMAN'
|
||||||
nmap <F5> <Plug>VimspectorContinue
|
nmap <F5> <Plug>VimspectorContinue
|
||||||
|
nmap <leader><F5> <Plug>VimspectorLaunch
|
||||||
nmap <F3> <Plug>VimspectorStop
|
nmap <F3> <Plug>VimspectorStop
|
||||||
nmap <F4> <Plug>VimspectorRestart
|
nmap <F4> <Plug>VimspectorRestart
|
||||||
nmap <F6> <Plug>VimspectorPause
|
nmap <F6> <Plug>VimspectorPause
|
||||||
|
|
|
||||||
51
python3/vimspector/custom/java.py
Normal file
51
python3/vimspector/custom/java.py
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
# 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, settings
|
||||||
|
|
||||||
|
|
||||||
|
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': {},
|
||||||
|
} )
|
||||||
|
|
||||||
|
mode = settings.Get( 'java_hotcodereplace_mode' )
|
||||||
|
if mode == 'ask':
|
||||||
|
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' ):
|
||||||
|
utils.UserMessage( 'Hot code replace: ' + body[ 'message' ] )
|
||||||
|
|
@ -29,14 +29,14 @@ class PendingRequest( object ):
|
||||||
|
|
||||||
|
|
||||||
class DebugAdapterConnection( object ):
|
class DebugAdapterConnection( object ):
|
||||||
def __init__( self, handler, send_func ):
|
def __init__( self, handlers, send_func ):
|
||||||
self._logger = logging.getLogger( __name__ )
|
self._logger = logging.getLogger( __name__ )
|
||||||
utils.SetUpLogging( self._logger )
|
utils.SetUpLogging( self._logger )
|
||||||
|
|
||||||
self._Write = send_func
|
self._Write = send_func
|
||||||
self._SetState( 'READ_HEADER' )
|
self._SetState( 'READ_HEADER' )
|
||||||
self._buffer = bytes()
|
self._buffer = bytes()
|
||||||
self._handler = handler
|
self._handlers = handlers
|
||||||
self._next_message_id = 0
|
self._next_message_id = 0
|
||||||
self._outstanding_requests = {}
|
self._outstanding_requests = {}
|
||||||
|
|
||||||
|
|
@ -124,7 +124,7 @@ class DebugAdapterConnection( object ):
|
||||||
|
|
||||||
def Reset( self ):
|
def Reset( self ):
|
||||||
self._Write = None
|
self._Write = None
|
||||||
self._handler = None
|
self._handlers = None
|
||||||
|
|
||||||
while self._outstanding_requests:
|
while self._outstanding_requests:
|
||||||
_, request = self._outstanding_requests.popitem()
|
_, request = self._outstanding_requests.popitem()
|
||||||
|
|
@ -237,7 +237,7 @@ class DebugAdapterConnection( object ):
|
||||||
|
|
||||||
|
|
||||||
def _OnMessageReceived( self, message ):
|
def _OnMessageReceived( self, message ):
|
||||||
if not self._handler:
|
if not self._handlers:
|
||||||
return
|
return
|
||||||
|
|
||||||
if message[ 'type' ] == 'response':
|
if message[ 'type' ] == 'response':
|
||||||
|
|
@ -270,25 +270,21 @@ class DebugAdapterConnection( object ):
|
||||||
self._logger.error( 'Request failed: {0}'.format( reason ) )
|
self._logger.error( 'Request failed: {0}'.format( reason ) )
|
||||||
if request.failure_handler:
|
if request.failure_handler:
|
||||||
request.failure_handler( reason, message )
|
request.failure_handler( reason, message )
|
||||||
elif 'OnFailure' in dir( self._handler ):
|
|
||||||
self._handler.OnFailure( reason, request.msg, message )
|
|
||||||
else:
|
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':
|
elif message[ 'type' ] == 'event':
|
||||||
method = 'OnEvent_' + message[ 'event' ]
|
method = 'OnEvent_' + message[ 'event' ]
|
||||||
if method in dir( self._handler ):
|
for h in self._handlers:
|
||||||
getattr( self._handler, method )( message )
|
if method in dir( h ):
|
||||||
else:
|
getattr( h, method )( message )
|
||||||
utils.UserMessage( 'Unhandled event: {0}'.format( message[ 'event' ] ),
|
|
||||||
persist = True )
|
|
||||||
elif message[ 'type' ] == 'request':
|
elif message[ 'type' ] == 'request':
|
||||||
method = 'OnRequest_' + message[ 'command' ]
|
method = 'OnRequest_' + message[ 'command' ]
|
||||||
if method in dir( self._handler ):
|
for h in self._handlers:
|
||||||
getattr( self._handler, method )( message )
|
if method in dir( h ):
|
||||||
else:
|
getattr( h, method )( message )
|
||||||
utils.UserMessage(
|
|
||||||
'Unhandled request: {0}'.format( message[ 'command' ] ),
|
|
||||||
persist = True )
|
|
||||||
|
|
||||||
|
|
||||||
def _KillTimer( request ):
|
def _KillTimer( request ):
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import shlex
|
||||||
import subprocess
|
import subprocess
|
||||||
import functools
|
import functools
|
||||||
import vim
|
import vim
|
||||||
|
import importlib
|
||||||
|
|
||||||
from vimspector import ( breakpoints,
|
from vimspector import ( breakpoints,
|
||||||
code,
|
code,
|
||||||
|
|
@ -99,7 +100,7 @@ class DebugSession( object ):
|
||||||
|
|
||||||
return launch_config_file, configurations
|
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.
|
# We mutate launch_variables, so don't mutate the default argument.
|
||||||
# https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments
|
# https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments
|
||||||
if launch_variables is None:
|
if launch_variables is None:
|
||||||
|
|
@ -134,6 +135,11 @@ class DebugSession( object ):
|
||||||
|
|
||||||
if 'configuration' in launch_variables:
|
if 'configuration' in launch_variables:
|
||||||
configuration_name = launch_variables.pop( 'configuration' )
|
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
|
elif ( len( configurations ) == 1 and
|
||||||
next( iter( configurations.values() ) ).get( "autoselect", True ) ):
|
next( iter( configurations.values() ) ).get( "autoselect", True ) ):
|
||||||
configuration_name = next( iter( configurations.keys() ) )
|
configuration_name = next( iter( configurations.keys() ) )
|
||||||
|
|
@ -888,8 +894,21 @@ class DebugSession( object ):
|
||||||
self._splash_screen,
|
self._splash_screen,
|
||||||
"Unable to start adapter" )
|
"Unable to start adapter" )
|
||||||
else:
|
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._connection = debug_adapter_connection.DebugAdapterConnection(
|
||||||
self,
|
handlers,
|
||||||
lambda msg: utils.Call(
|
lambda msg: utils.Call(
|
||||||
"vimspector#internal#{}#Send".format( self._connection_type ),
|
"vimspector#internal#{}#Send".format( self._connection_type ),
|
||||||
msg ) )
|
msg ) )
|
||||||
|
|
@ -897,39 +916,58 @@ class DebugSession( object ):
|
||||||
self._logger.info( 'Debug Adapter Started' )
|
self._logger.info( 'Debug Adapter Started' )
|
||||||
|
|
||||||
def _StopDebugAdapter( self, interactive = False, callback = None ):
|
def _StopDebugAdapter( self, interactive = False, callback = None ):
|
||||||
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 )
|
|
||||||
|
|
||||||
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 ) )
|
|
||||||
|
|
||||||
arguments = {}
|
arguments = {}
|
||||||
if ( interactive and
|
|
||||||
self._server_capabilities.get( 'supportTerminateDebuggee' ) ):
|
def disconnect():
|
||||||
if self._stackTraceView.AnyThreadsRunning():
|
self._splash_screen = utils.DisplaySplash(
|
||||||
choice = utils.AskForInput( "Terminate debuggee [Y/N/default]? ", "" )
|
self._api_prefix,
|
||||||
if choice == "Y" or choice == "y":
|
self._splash_screen,
|
||||||
|
"Shutting down debug adapter..." )
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
vim.eval( 'vimspector#internal#{}#StopDebugSession()'.format(
|
||||||
|
self._connection_type ) )
|
||||||
|
|
||||||
|
self._connection.DoRequest( handler, {
|
||||||
|
'command': 'disconnect',
|
||||||
|
'arguments': 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 ):
|
||||||
|
if choice == 1:
|
||||||
|
# yes
|
||||||
arguments[ 'terminateDebuggee' ] = True
|
arguments[ 'terminateDebuggee' ] = True
|
||||||
elif choice == "N" or choice == 'n':
|
elif choice == 2:
|
||||||
|
# no
|
||||||
arguments[ 'terminateDebuggee' ] = False
|
arguments[ 'terminateDebuggee' ] = False
|
||||||
|
elif choice <= 0:
|
||||||
|
# Abort
|
||||||
|
return
|
||||||
|
# Else, use server default
|
||||||
|
|
||||||
self._connection.DoRequest( handler, {
|
disconnect()
|
||||||
'command': 'disconnect',
|
|
||||||
'arguments': arguments,
|
|
||||||
}, failure_handler = handler, timeout = 5000 )
|
|
||||||
|
|
||||||
# TODO: Use the 'tarminate' request if supportsTerminateRequest set
|
utils.Confirm( self._api_prefix,
|
||||||
|
"Terminate debuggee?",
|
||||||
|
handle_choice,
|
||||||
|
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 ):
|
||||||
|
|
|
||||||
|
|
@ -159,7 +159,8 @@ GADGETS = {
|
||||||
"port": "${DAPPort}",
|
"port": "${DAPPort}",
|
||||||
"configuration": {
|
"configuration": {
|
||||||
"cwd": "${workspaceRoot}"
|
"cwd": "${workspaceRoot}"
|
||||||
}
|
},
|
||||||
|
'custom_handler': 'vimspector.custom.java.JavaDebugAdapter'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -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',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -375,6 +375,44 @@ def AskForInput( prompt, default_value = None, completion = None ):
|
||||||
return 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 = 2,
|
||||||
|
options: list = None,
|
||||||
|
keys: list = None ):
|
||||||
|
if not options:
|
||||||
|
options = [ '(Y)es', '(N)o' ]
|
||||||
|
if not keys:
|
||||||
|
keys = [ 'y', 'n' ]
|
||||||
|
|
||||||
|
global CONFIRM_ID
|
||||||
|
CONFIRM_ID += 1
|
||||||
|
CONFIRM[ CONFIRM_ID ] = handler
|
||||||
|
Call( f'vimspector#internal#{ api_prefix }popup#Confirm',
|
||||||
|
CONFIRM_ID,
|
||||||
|
prompt,
|
||||||
|
options,
|
||||||
|
default_value,
|
||||||
|
keys )
|
||||||
|
|
||||||
|
|
||||||
def AppendToBuffer( buf, line_or_lines, modified=False ):
|
def AppendToBuffer( buf, line_or_lines, modified=False ):
|
||||||
line = 1
|
line = 1
|
||||||
try:
|
try:
|
||||||
|
|
@ -403,8 +441,10 @@ def AppendToBuffer( buf, line_or_lines, modified=False ):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def ClearBuffer( buf ):
|
def ClearBuffer( buf, modified = False ):
|
||||||
buf[ : ] = None
|
buf[ : ] = None
|
||||||
|
if not modified:
|
||||||
|
buf.options[ 'modified' ] = False
|
||||||
|
|
||||||
|
|
||||||
def SetBufferContents( buf, lines, modified=False ):
|
def SetBufferContents( buf, lines, modified=False ):
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<artifactId>TestApplication</artifactId>
|
<artifactId>TestApplication</artifactId>
|
||||||
<version>1</version>
|
<version>1</version>
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>8</maven.compiler.source>
|
<maven.compiler.source>11</maven.compiler.source>
|
||||||
<maven.compiler.target>8</maven.compiler.target>
|
<maven.compiler.target>11</maven.compiler.target>
|
||||||
</properties>
|
</properties>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue