Support java debugging
The java architecture is a little different: - the debugger is a jdt.ls extension bundle. - to start the server, you send a startDebugSession command to jdt.ls - this returns a tcl port to connect to for DAP Loading of jdt.ls and the extension are out of scope for vimspector currently and instead you can tell it to ask you for a port to connect to. After connexting to that port, vimspector works as normal. To support TCP/IP was pretty simple: we provide the same API from vimscript as the job-based (stdin/out) comms layer, but instead just directly use a channel. The only wrinkle was that the java debug adapter broke the protocol on runInTerminal and didn't return a 'cwd', so we make one up.
This commit is contained in:
parent
9f8fddd1cd
commit
14603ae72f
6 changed files with 173 additions and 7 deletions
101
autoload/vimspector/internal/channel.vim
Normal file
101
autoload/vimspector/internal/channel.vim
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
" vimspector - A multi-language debugging system for Vim
|
||||||
|
" Copyright 2018 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.
|
||||||
|
|
||||||
|
|
||||||
|
" Boilerplate {{{
|
||||||
|
let s:save_cpo = &cpo
|
||||||
|
set cpo&vim
|
||||||
|
" }}}
|
||||||
|
|
||||||
|
function! s:_OnServerData( channel, data ) abort
|
||||||
|
py3 << EOF
|
||||||
|
_vimspector_session.OnChannelData( vim.eval( 'a:data' ) )
|
||||||
|
EOF
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:_OnServerError( channel, data ) abort
|
||||||
|
echom "Channel received error: " . a:data
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:_OnExit( channel, status ) abort
|
||||||
|
echom "Channel exit with status " . a:status
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:_OnClose( channel ) abort
|
||||||
|
echom "Channel closed"
|
||||||
|
" py3 _vimspector_session.OnChannelClosed()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:_Send( msg ) abort
|
||||||
|
call ch_sendraw( s:ch, a:msg )
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vimspector#internal#channel#StartDebugSession( config ) abort
|
||||||
|
|
||||||
|
if exists( 's:ch' )
|
||||||
|
echo "Channel is already running"
|
||||||
|
return v:none
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:addr = 'localhost:' . a:config[ 'port' ]
|
||||||
|
|
||||||
|
let s:ch = ch_open( l:addr,
|
||||||
|
\ {
|
||||||
|
\ 'mode': 'raw',
|
||||||
|
\ 'callback': funcref( 's:_OnServerData' ),
|
||||||
|
\ 'close_cb': funcref( 's:_OnClose' ),
|
||||||
|
\ }
|
||||||
|
\ )
|
||||||
|
|
||||||
|
if ch_status( s:ch ) != 'open'
|
||||||
|
echom 'Unable to connect to debug adapter'
|
||||||
|
return v:none
|
||||||
|
endif
|
||||||
|
|
||||||
|
return funcref( 's:_Send' )
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vimspector#internal#channel#StopDebugSession() abort
|
||||||
|
if !exists( 's:ch' )
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
if ch_status( s:ch ) == 'open'
|
||||||
|
call ch_close( s:ch )
|
||||||
|
endif
|
||||||
|
|
||||||
|
unlet s:ch
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vimspector#internal#channel#Reset() abort
|
||||||
|
if exists( 's:ch' )
|
||||||
|
call vimspector#internal#channel#StopDebugSession()
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vimspector#internal#channel#ForceRead() abort
|
||||||
|
if exists( 's:ch' )
|
||||||
|
let data = ch_readraw( s:ch, { 'timeout': 1000 } )
|
||||||
|
if data != ''
|
||||||
|
call s:_OnServerData( s:ch, data )
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Boilerplate {{{
|
||||||
|
let &cpo=s:save_cpo
|
||||||
|
unlet s:save_cpo
|
||||||
|
" }}}
|
||||||
|
|
||||||
|
|
@ -46,7 +46,7 @@ class DebugSession( object ):
|
||||||
self._next_sign_id = SIGN_ID_OFFSET
|
self._next_sign_id = SIGN_ID_OFFSET
|
||||||
|
|
||||||
# FIXME: This needs redesigning. There are a number of problems:
|
# FIXME: This needs redesigning. There are a number of problems:
|
||||||
# - breakpoints don't have to be line-wisw (e.g. method/exception)
|
# - breakpoints don't have to be line-wise (e.g. method/exception)
|
||||||
# - when the server moves/changes a breakpoint, this is not updated,
|
# - when the server moves/changes a breakpoint, this is not updated,
|
||||||
# leading to them getting out of sync
|
# leading to them getting out of sync
|
||||||
# - the split of responsibility between this object and the CodeView is
|
# - the split of responsibility between this object and the CodeView is
|
||||||
|
|
@ -133,8 +133,10 @@ class DebugSession( object ):
|
||||||
if not configuration:
|
if not configuration:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
self._workspace_root = os.path.dirname( launch_config_file )
|
||||||
|
|
||||||
utils.ExpandReferencesInDict( launch_config[ configuration ], {
|
utils.ExpandReferencesInDict( launch_config[ configuration ], {
|
||||||
'workspaceRoot': os.path.dirname( launch_config_file )
|
'workspaceRoot': self._workspace_root
|
||||||
} )
|
} )
|
||||||
|
|
||||||
adapter = launch_config[ configuration ].get( 'adapter' )
|
adapter = launch_config[ configuration ].get( 'adapter' )
|
||||||
|
|
@ -207,7 +209,8 @@ class DebugSession( object ):
|
||||||
vim.current.tabpage = self._uiTab
|
vim.current.tabpage = self._uiTab
|
||||||
vim.command( 'tabclose!' )
|
vim.command( 'tabclose!' )
|
||||||
|
|
||||||
vim.eval( 'vimspector#internal#job#Reset()' )
|
vim.eval( 'vimspector#internal#{}#Reset()'.format(
|
||||||
|
self._connection_type ) )
|
||||||
vim.eval( 'vimspector#internal#state#Reset()' )
|
vim.eval( 'vimspector#internal#state#Reset()' )
|
||||||
|
|
||||||
# make sure that we're displaying signs in any still-open buffers
|
# make sure that we're displaying signs in any still-open buffers
|
||||||
|
|
@ -347,8 +350,17 @@ class DebugSession( object ):
|
||||||
self._logger.info( 'Starting debug adapter with: {0}'.format( json.dumps(
|
self._logger.info( 'Starting debug adapter with: {0}'.format( json.dumps(
|
||||||
self._adapter ) ) )
|
self._adapter ) ) )
|
||||||
|
|
||||||
|
self._connection_type = 'job'
|
||||||
|
if 'port' in self._adapter:
|
||||||
|
self._connection_type = 'channel'
|
||||||
|
|
||||||
|
if self._adapter[ 'port' ] == 'ask':
|
||||||
|
port = utils.AskForInput( 'Enter port to connect to: ' )
|
||||||
|
self._adapter[ 'port' ] = port
|
||||||
|
|
||||||
channel_send_func = vim.bindeval(
|
channel_send_func = vim.bindeval(
|
||||||
"vimspector#internal#job#StartDebugSession( {0} )".format(
|
"vimspector#internal#{}#StartDebugSession( {} )".format(
|
||||||
|
self._connection_type,
|
||||||
json.dumps( self._adapter ) ) )
|
json.dumps( self._adapter ) ) )
|
||||||
|
|
||||||
if channel_send_func is None:
|
if channel_send_func is None:
|
||||||
|
|
@ -385,13 +397,16 @@ class DebugSession( object ):
|
||||||
tries = 0
|
tries = 0
|
||||||
while not state[ 'done' ] and tries < 10:
|
while not state[ 'done' ] and tries < 10:
|
||||||
tries = tries + 1
|
tries = tries + 1
|
||||||
vim.eval( 'vimspector#internal#job#ForceRead()' )
|
vim.eval( 'vimspector#internal#{}#ForceRead()'.format(
|
||||||
|
self._connection_type ) )
|
||||||
|
|
||||||
vim.eval( 'vimspector#internal#job#StopDebugSession()' )
|
vim.eval( 'vimspector#internal#{}#StopDebugSession()'.format(
|
||||||
|
self._connection_type ) )
|
||||||
|
|
||||||
def _StopDebugAdapter( self, callback = None ):
|
def _StopDebugAdapter( self, callback = None ):
|
||||||
def handler( message ):
|
def handler( message ):
|
||||||
vim.eval( 'vimspector#internal#job#StopDebugSession()' )
|
vim.eval( 'vimspector#internal#{}#StopDebugSession()'.format(
|
||||||
|
self._connection_type ) )
|
||||||
|
|
||||||
vim.command( 'au! vimspector_cleanup' )
|
vim.command( 'au! vimspector_cleanup' )
|
||||||
|
|
||||||
|
|
@ -489,6 +504,9 @@ class DebugSession( object ):
|
||||||
def OnRequest_runInTerminal( self, message ):
|
def OnRequest_runInTerminal( self, message ):
|
||||||
params = message[ 'arguments' ]
|
params = message[ 'arguments' ]
|
||||||
|
|
||||||
|
if 'cwd' not in params:
|
||||||
|
params[ 'cwd' ] = self._workspace_root
|
||||||
|
|
||||||
buffer_number = self._codeView.LaunchTerminal( params )
|
buffer_number = self._codeView.LaunchTerminal( params )
|
||||||
|
|
||||||
response = {
|
response = {
|
||||||
|
|
|
||||||
4
support/test/java/test_project/.gitignore
vendored
Normal file
4
support/test/java/test_project/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
.classpath
|
||||||
|
.project
|
||||||
|
.settings/
|
||||||
|
target/
|
||||||
22
support/test/java/test_project/.vimspector.json
Normal file
22
support/test/java/test_project/.vimspector.json
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"adapters": {
|
||||||
|
"java-debug-server": {
|
||||||
|
"name": "vscode-java",
|
||||||
|
"port": "ask"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"Java Launch": {
|
||||||
|
"adapter": "java-debug-server",
|
||||||
|
"configuration": {
|
||||||
|
"request": "launch",
|
||||||
|
"mainClass": "com.vimspector.test.TestApplication",
|
||||||
|
"sourcePaths": [ "${workspaceRoot}/src/main/java" ],
|
||||||
|
"classPaths": [ "${workspaceRoot}/target/classes" ],
|
||||||
|
"args": "hello world!",
|
||||||
|
"stopOnEntry": true,
|
||||||
|
"console": "integratedTerminal"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
support/test/java/test_project/pom.xml
Normal file
10
support/test/java/test_project/pom.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
<project>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>com.vimspector.test</groupId>
|
||||||
|
<artifactId>TestApplication</artifactId>
|
||||||
|
<version>1</version>
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>1.8</maven.compiler.source>
|
||||||
|
<maven.compiler.target>1.8</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
</project>
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package com.vimspector.test;
|
||||||
|
|
||||||
|
public class TestApplication {
|
||||||
|
public static void main( String[] args ) {
|
||||||
|
for ( String s : args ) {
|
||||||
|
System.out.println( "Arg: " + s );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue