Merge pull request #190 from puremourning/codelldb
Support running a command and connecting to a port
This commit is contained in:
commit
669b019e25
13 changed files with 263 additions and 81 deletions
126
README.md
126
README.md
|
|
@ -6,7 +6,6 @@ For a tutorial and usage overview, take a look at the
|
|||
[](https://dev.azure.com/puremouron/Vimspector/_build/latest?definitionId=1&branchName=master) [](https://gitter.im/vimspector/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
|
||||
<!--ts-->
|
||||
* [Motivation](#motivation)
|
||||
* [Features and Usage](#features-and-usage)
|
||||
* [Supported debugging features](#supported-debugging-features)
|
||||
* [Supported languages:](#supported-languages)
|
||||
|
|
@ -42,8 +41,12 @@ For a tutorial and usage overview, take a look at the
|
|||
* [Console](#console)
|
||||
* [Closing debugger](#closing-debugger)
|
||||
* [Debug adapter configuration](#debug-adapter-configuration)
|
||||
* [C, C++, Rust, etc.](#c-c-rust-etc)
|
||||
* [C, C , Rust, etc.](#c-c-rust-etc)
|
||||
* [Remote debugging](#remote-debugging)
|
||||
* [Remote launch and attach](#remote-launch-and-attach)
|
||||
* [Python](#python)
|
||||
* [Remote Debugging](#remote-debugging-1)
|
||||
* [Remote launch and attach](#remote-launch-and-attach-1)
|
||||
* [Legacy: vscode-python](#legacy-vscode-python)
|
||||
* [TCL](#tcl)
|
||||
* [C♯](#c)
|
||||
|
|
@ -55,60 +58,18 @@ For a tutorial and usage overview, take a look at the
|
|||
* [Java](#java)
|
||||
* [Usage with YouCompleteMe](#usage-with-youcompleteme)
|
||||
* [Other LSP clients](#other-lsp-clients)
|
||||
* [Rust](#rust)
|
||||
* [Other servers](#other-servers)
|
||||
* [Customisation](#customisation)
|
||||
* [Changing the default signs](#changing-the-default-signs)
|
||||
* [FAQ](#faq)
|
||||
* [Motivation](#motivation)
|
||||
* [License](#license)
|
||||
|
||||
<!-- Added by: ben, at: Thu 7 May 2020 22:30:21 BST -->
|
||||
<!-- Added by: ben, at: Mon 6 Jul 2020 11:30:01 BST -->
|
||||
|
||||
<!--te-->
|
||||
|
||||
# Motivation
|
||||
|
||||
A message from the author about the motivation for this plugin:
|
||||
|
||||
> Many development environments have a built-in debugger. I spend an inordinate
|
||||
> amount of my time in Vim. I do all my development in Vim and I have even
|
||||
> customised my workflows for building code, running tests etc.
|
||||
>
|
||||
> For many years I have observed myself, friends and colleagues have been
|
||||
> writing `printf`, `puts`, `print`, etc. debugging statements in all sorts of
|
||||
> files simply because there is no _easy_ way to run a debugger for _whatever_
|
||||
> language we happen to be developing in.
|
||||
>
|
||||
> I truly believe that interactive, graphical debugging environments are the
|
||||
> best way to understand and reason about both unfamiliar and familiar code, and
|
||||
> that the lack of ready, simple access to a debugger is a huge hidden
|
||||
> productivity hole for many.
|
||||
>
|
||||
> Don't get me wrong, I know there are literally millions of developers out
|
||||
> there that are more than competent at developing without a graphical debugger,
|
||||
> but I maintain that if they had the ability to _just press a key_ and jump
|
||||
> into the debugger, it would be faster and more enjoyable that just cerebral
|
||||
> code comprehension.
|
||||
>
|
||||
> I created Vimsepctor because I find changing tools frustrating. `gdb` for c++,
|
||||
> `pdb` for python, etc. Each has its own syntax. Each its own lexicon. Each its
|
||||
> own foibles.
|
||||
>
|
||||
> I designed the configuration system in such a way that the configuration can
|
||||
> be committed to source control so that it _just works_ for any of your
|
||||
> colleagues, friends, collaborators or complete strangers.
|
||||
>
|
||||
> I made remote debugging a first-class feature because that's a primary use
|
||||
> case for me in my job.
|
||||
>
|
||||
> With Vimspector I can _just hit `<F5>`_ in all of the languages I develop in
|
||||
> and debug locally or remotely using the exact same workflow, mappings and UI.
|
||||
> I have integrated this with my Vim in such a way that I can hit a button and
|
||||
> _run the test under the cursor in Vimspector_. This kind of integration has
|
||||
> massively improved my workflow and productivity. It's even made the process
|
||||
> of learning a new codebase... fun.
|
||||
>
|
||||
> \- Ben Jackson, Creator.
|
||||
|
||||
# Features and Usage
|
||||
|
||||
The plugin is a capable Vim graphical debugger for multiple languages.
|
||||
|
|
@ -277,6 +238,7 @@ categorised as follows:
|
|||
| Java | Supported | `--force-enable-java ` | vscode-java-debug | Compatible LSP plugin (see [later](#java)) |
|
||||
| C# (dotnet core) | Experimental | `--force-enable-csharp` | netcoredbg | DotNet core |
|
||||
| C# (mono) | Experimental | `--force-enable-csharp` | vscode-mono-debug | Mono |
|
||||
| Rust (CodeLLDB) | Experimental | `--force-enable-rust` | CodeLLDB | Python 3 |
|
||||
| Python.legacy | Legacy | `--force-enable-python.legacy` | vscode-python | Node 10, Python 2.7 or Python 3 |
|
||||
|
||||
For other languages, you'll need some other way to install the gadget.
|
||||
|
|
@ -1222,6 +1184,32 @@ For the launch arguments, see the
|
|||
See [this issue](https://github.com/puremourning/vimspector/issues/3) for more
|
||||
background.
|
||||
|
||||
## Rust
|
||||
|
||||
Rust is supported with any gdb/lldb-based debugger. So it works fine with
|
||||
`vscode-cpptools` and `lldb-vscode` above. However, support for rust is best in
|
||||
[`CodeLLDB`](https://github.com/vadimcn/vscode-lldb#features).
|
||||
|
||||
* `./install_gadget.py --force-enable-rust`
|
||||
* Example: `support/test/rust/vimspector_test`
|
||||
|
||||
```json
|
||||
{
|
||||
"configurations": {
|
||||
"launch": {
|
||||
"adapter": "CodeLLDB",
|
||||
"configuration": {
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/target/debug/vimspector_test"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
* Docs: https://github.com/vadimcn/vscode-lldb/blob/master/MANUAL.md
|
||||
|
||||
|
||||
## Other servers
|
||||
|
||||
* Java - vscode-javac. This works, but is not as functional as Java Debug
|
||||
|
|
@ -1275,6 +1263,50 @@ hi link jsonCommentError Comment
|
|||
hi link jsonComment Comment
|
||||
```
|
||||
|
||||
# Motivation
|
||||
|
||||
A message from the author about the motivation for this plugin:
|
||||
|
||||
> Many development environments have a built-in debugger. I spend an inordinate
|
||||
> amount of my time in Vim. I do all my development in Vim and I have even
|
||||
> customised my workflows for building code, running tests etc.
|
||||
>
|
||||
> For many years I have observed myself, friends and colleagues have been
|
||||
> writing `printf`, `puts`, `print`, etc. debugging statements in all sorts of
|
||||
> files simply because there is no _easy_ way to run a debugger for _whatever_
|
||||
> language we happen to be developing in.
|
||||
>
|
||||
> I truly believe that interactive, graphical debugging environments are the
|
||||
> best way to understand and reason about both unfamiliar and familiar code, and
|
||||
> that the lack of ready, simple access to a debugger is a huge hidden
|
||||
> productivity hole for many.
|
||||
>
|
||||
> Don't get me wrong, I know there are literally millions of developers out
|
||||
> there that are more than competent at developing without a graphical debugger,
|
||||
> but I maintain that if they had the ability to _just press a key_ and jump
|
||||
> into the debugger, it would be faster and more enjoyable that just cerebral
|
||||
> code comprehension.
|
||||
>
|
||||
> I created Vimsepctor because I find changing tools frustrating. `gdb` for c++,
|
||||
> `pdb` for python, etc. Each has its own syntax. Each its own lexicon. Each its
|
||||
> own foibles.
|
||||
>
|
||||
> I designed the configuration system in such a way that the configuration can
|
||||
> be committed to source control so that it _just works_ for any of your
|
||||
> colleagues, friends, collaborators or complete strangers.
|
||||
>
|
||||
> I made remote debugging a first-class feature because that's a primary use
|
||||
> case for me in my job.
|
||||
>
|
||||
> With Vimspector I can _just hit `<F5>`_ in all of the languages I develop in
|
||||
> and debug locally or remotely using the exact same workflow, mappings and UI.
|
||||
> I have integrated this with my Vim in such a way that I can hit a button and
|
||||
> _run the test under the cursor in Vimspector_. This kind of integration has
|
||||
> massively improved my workflow and productivity. It's even made the process
|
||||
> of learning a new codebase... fun.
|
||||
>
|
||||
> \- Ben Jackson, Creator.
|
||||
|
||||
# License
|
||||
|
||||
[Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0)
|
||||
|
|
|
|||
|
|
@ -39,6 +39,21 @@ function! vimspector#internal#channel#StartDebugSession( config ) abort
|
|||
return v:false
|
||||
endif
|
||||
|
||||
" If we _also_ have a command line, then start the actual job. This allows for
|
||||
" servers which start up and listen on some port
|
||||
if has_key( a:config, 'command' )
|
||||
let s:job = job_start( a:config[ 'command' ],
|
||||
\ {
|
||||
\ 'in_mode': 'raw',
|
||||
\ 'out_mode': 'raw',
|
||||
\ 'err_mode': 'raw',
|
||||
\ 'stoponexit': 'term',
|
||||
\ 'env': a:config[ 'env' ],
|
||||
\ 'cwd': a:config[ 'cwd' ],
|
||||
\ }
|
||||
\ )
|
||||
endif
|
||||
|
||||
let l:addr = get( a:config, 'host', 'localhost' ) . ':' . a:config[ 'port' ]
|
||||
|
||||
echo 'Connecting to ' . l:addr . '... (waiting fo up to 10 seconds)'
|
||||
|
|
@ -52,7 +67,7 @@ function! vimspector#internal#channel#StartDebugSession( config ) abort
|
|||
\ )
|
||||
|
||||
if ch_status( s:ch ) !=# 'open'
|
||||
echom 'Unable to connect to debug adapter'
|
||||
echom 'Unable to connect to' l:addr
|
||||
redraw
|
||||
return v:false
|
||||
endif
|
||||
|
|
@ -72,11 +87,7 @@ EOF
|
|||
endfunction
|
||||
|
||||
function! vimspector#internal#channel#StopDebugSession() abort
|
||||
if !exists( 's:ch' )
|
||||
return
|
||||
endif
|
||||
|
||||
if ch_status( s:ch ) ==# 'open'
|
||||
if exists( 's:ch' ) && ch_status( s:ch ) ==# 'open'
|
||||
" channel is open, close it and trigger the callback. The callback is _not_
|
||||
" triggered when manually calling ch_close. if we get here and the channel
|
||||
" is not open, then we there is a _OnClose callback waiting for us, so do
|
||||
|
|
@ -84,10 +95,17 @@ function! vimspector#internal#channel#StopDebugSession() abort
|
|||
call ch_close( s:ch )
|
||||
call s:_OnClose( s:ch )
|
||||
endif
|
||||
|
||||
if exists( 's:job' )
|
||||
if job_status( s:job ) ==# 'run'
|
||||
call job_stop( s:job, 'kill' )
|
||||
endif
|
||||
unlet s:job
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! vimspector#internal#channel#Reset() abort
|
||||
if exists( 's:ch' )
|
||||
if exists( 's:ch' ) || exists( 's:job' )
|
||||
call vimspector#internal#channel#StopDebugSession()
|
||||
endif
|
||||
endfunction
|
||||
|
|
|
|||
|
|
@ -128,8 +128,8 @@ function! vimspector#internal#job#StopDebugSession() abort
|
|||
endif
|
||||
|
||||
if job_status( s:job ) ==# 'run'
|
||||
echom 'Terminating job'
|
||||
redraw
|
||||
echom 'Terminating job'
|
||||
redraw
|
||||
call job_stop( s:job, 'kill' )
|
||||
endif
|
||||
endfunction
|
||||
|
|
|
|||
|
|
@ -34,20 +34,50 @@ endfunction
|
|||
|
||||
function! vimspector#internal#neochannel#StartDebugSession( config ) abort
|
||||
if exists( 's:ch' )
|
||||
echom 'Not starging: Channel is already running'
|
||||
echom 'Not starting: Channel is already running'
|
||||
redraw
|
||||
return v:false
|
||||
endif
|
||||
|
||||
let l:addr = get( a:config, 'host', 'localhost' ) . ':' . a:config[ 'port' ]
|
||||
|
||||
let s:ch = sockconnect( 'tcp', addr, { 'on_data': funcref( 's:_OnEvent' ) } )
|
||||
if s:ch <= 0
|
||||
unlet s:ch
|
||||
return v:false
|
||||
" If we _also_ have a command line, then start the actual job. This allows for
|
||||
" servers which start up and listen on some port
|
||||
if has_key( a:config, 'command' )
|
||||
let old_env={}
|
||||
try
|
||||
let old_env = vimspector#internal#neoterm#PrepareEnvironment(
|
||||
\ a:config[ 'env' ] )
|
||||
let s:job = jobstart( a:config[ 'command' ],
|
||||
\ {
|
||||
\ 'cwd': a:config[ 'cwd' ],
|
||||
\ 'env': a:config[ 'env' ],
|
||||
\ }
|
||||
\ )
|
||||
finally
|
||||
call vimspector#internal#neoterm#ResetEnvironment( a:config[ 'env' ],
|
||||
\ old_env )
|
||||
endtry
|
||||
endif
|
||||
|
||||
return v:true
|
||||
let l:addr = get( a:config, 'host', 'localhost' ) . ':' . a:config[ 'port' ]
|
||||
|
||||
let attempt = 1
|
||||
while attempt <= 10
|
||||
echo 'Connecting to ' . l:addr . '... (attempt' attempt 'of 10)'
|
||||
try
|
||||
let s:ch = sockconnect( 'tcp',
|
||||
\ addr,
|
||||
\ { 'on_data': funcref( 's:_OnEvent' ) } )
|
||||
redraw
|
||||
return v:true
|
||||
catch /connection refused/
|
||||
sleep 1
|
||||
endtry
|
||||
let attempt += 1
|
||||
endwhile
|
||||
|
||||
echom 'Unable to connect to' l:addr 'after 10 attempts'
|
||||
redraw
|
||||
return v:false
|
||||
endfunction
|
||||
|
||||
function! vimspector#internal#neochannel#Send( msg ) abort
|
||||
|
|
@ -62,16 +92,19 @@ function! vimspector#internal#neochannel#Send( msg ) abort
|
|||
endfunction
|
||||
|
||||
function! vimspector#internal#neochannel#StopDebugSession() abort
|
||||
if !exists( 's:ch' )
|
||||
echom "Not stopping session: Channel doesn't exist"
|
||||
redraw
|
||||
return
|
||||
if exists( 's:ch' )
|
||||
call chanclose( s:ch )
|
||||
" It doesn't look like we get a callback after chanclos. Who knows if we
|
||||
" will subsequently receive data callbacks.
|
||||
call s:_OnEvent( s:ch, [ '' ], 'data' )
|
||||
endif
|
||||
|
||||
call chanclose( s:ch )
|
||||
" It doesn't look like we get a callback after chanclos. Who knows if we will
|
||||
" subsequently receive data callbacks.
|
||||
call s:_OnEvent( s:ch, [ '' ], 'data' )
|
||||
if exists( 's:job' )
|
||||
if vimspector#internal#neojob#JobIsRunning( s:job )
|
||||
call jobstop( s:job )
|
||||
endif
|
||||
unlet s:job
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! vimspector#internal#neochannel#Reset() abort
|
||||
|
|
|
|||
|
|
@ -70,8 +70,8 @@ function! vimspector#internal#neojob#StartDebugSession( config ) abort
|
|||
return v:true
|
||||
endfunction
|
||||
|
||||
function! s:JobIsRunning( job ) abort
|
||||
return jobwait( [ s:job ], 0 )[ 0 ] == -1
|
||||
function! vimspector#internal#neojob#JobIsRunning( job ) abort
|
||||
return jobwait( [ a:job ], 0 )[ 0 ] == -1
|
||||
endfunction
|
||||
|
||||
function! vimspector#internal#neojob#Send( msg ) abort
|
||||
|
|
@ -81,7 +81,7 @@ function! vimspector#internal#neojob#Send( msg ) abort
|
|||
return 0
|
||||
endif
|
||||
|
||||
if !s:JobIsRunning( s:job )
|
||||
if !vimspector#internal#neojob#JobIsRunning( s:job )
|
||||
echom "Can't send message: Job is not running"
|
||||
redraw
|
||||
return 0
|
||||
|
|
@ -96,7 +96,7 @@ function! vimspector#internal#neojob#StopDebugSession() abort
|
|||
return
|
||||
endif
|
||||
|
||||
if s:JobIsRunning( s:job )
|
||||
if vimspector#internal#neojob#JobIsRunning( s:job )
|
||||
echom 'Terminating job'
|
||||
redraw
|
||||
call jobstop( s:job )
|
||||
|
|
|
|||
|
|
@ -412,9 +412,76 @@ GADGETS = {
|
|||
},
|
||||
},
|
||||
},
|
||||
'CodeLLDB': {
|
||||
'language': 'rust',
|
||||
'enabled': False,
|
||||
'download': {
|
||||
'url': 'https://github.com/vadimcn/vscode-lldb/releases/download/'
|
||||
'${version}/${file_name}',
|
||||
},
|
||||
'all': {
|
||||
'version': 'v1.5.3',
|
||||
},
|
||||
'macos': {
|
||||
'file_name': 'codelldb-x86_64-darwin.vsix',
|
||||
'checksum':
|
||||
'7505bc1cdfcfd1cb981e2996aec62d63577440709bac31dcadb41a3b4b44631a',
|
||||
'make_executable': [
|
||||
'adapter/codelldb',
|
||||
'lldb/bin/debugserver',
|
||||
'lldb/bin/lldb',
|
||||
'lldb/bin/lldb-argdumper',
|
||||
],
|
||||
},
|
||||
'linux': {
|
||||
'file_name': 'codelldb-x86_64-linux.vsix',
|
||||
'checksum':
|
||||
'ce7efc3e94d775368e5942a02bf5c326b6809a0b4c389f79ffa6a8f6f6b72139',
|
||||
'make_executable': [
|
||||
'adapter/codelldb',
|
||||
'lldb/bin/lldb',
|
||||
'lldb/bin/lldb-server',
|
||||
'lldb/bin/lldb-argdumper',
|
||||
],
|
||||
},
|
||||
'windows': {
|
||||
'file_name': 'codelldb-x86_64-windows.vsix',
|
||||
'checksum':
|
||||
'',
|
||||
'make_executable': []
|
||||
},
|
||||
'adapters': {
|
||||
'CodeLLDB': {
|
||||
'name': 'CodeLLDB',
|
||||
'type': 'CodeLLDB',
|
||||
"command": [
|
||||
"${gadgetDir}/CodeLLDB/adapter/codelldb",
|
||||
"--port", "${port}"
|
||||
],
|
||||
"port": "${port}",
|
||||
"configuration": {
|
||||
"type": "lldb",
|
||||
"name": "lldb",
|
||||
"cargo": {},
|
||||
"args": [],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"env": {},
|
||||
"terminal": "integrated",
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def InstallGeneric( name, root, gadget ):
|
||||
extension = os.path.join( root, 'extension' )
|
||||
for f in gadget.get( 'make_executable', [] ):
|
||||
installer.MakeExecutable( os.path.join( extension, f ) )
|
||||
|
||||
installer.MakeExtensionSymlink( vimspector_base, name, root )
|
||||
|
||||
|
||||
def InstallCppTools( name, root, gadget ):
|
||||
extension = os.path.join( root, 'extension' )
|
||||
|
||||
|
|
@ -550,7 +617,7 @@ def InstallGagdet( name, gadget, failed, all_adapters ):
|
|||
if 'do' in gadget:
|
||||
gadget[ 'do' ]( name, root, v )
|
||||
else:
|
||||
installer.MakeExtensionSymlink( vimspector_base, name, root )
|
||||
InstallGeneric( name, root, v )
|
||||
|
||||
# Allow per-OS adapter overrides. v already did that for us...
|
||||
all_adapters.update( v.get( 'adapters', {} ) )
|
||||
|
|
|
|||
|
|
@ -267,7 +267,7 @@ class DebugAdapterConnection( object ):
|
|||
if request.failure_handler:
|
||||
request.failure_handler( reason, message )
|
||||
elif 'OnFailure' in dir( self._handler ):
|
||||
self._handler.OnFailure( reason, message )
|
||||
self._handler.OnFailure( reason, request.msg, message )
|
||||
else:
|
||||
utils.UserMessage( 'Request failed: {0}'.format( reason ) )
|
||||
elif message[ 'type' ] == 'event':
|
||||
|
|
|
|||
|
|
@ -776,9 +776,10 @@ class DebugSession( object ):
|
|||
} )
|
||||
|
||||
|
||||
def OnFailure( self, reason, message ):
|
||||
msg = "Request for '{}' failed: {}".format( message[ 'command' ],
|
||||
reason )
|
||||
def OnFailure( self, reason, request, message ):
|
||||
msg = "Request for '{}' failed: {}\nResponse: {}".format( request,
|
||||
reason,
|
||||
message )
|
||||
self._outputView.Print( 'server', msg )
|
||||
|
||||
def _Launch( self ):
|
||||
|
|
|
|||
1
support/test/rust/vimspector_test/.gitignore
vendored
Normal file
1
support/test/rust/vimspector_test/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
target/
|
||||
12
support/test/rust/vimspector_test/.vimspector.json
Normal file
12
support/test/rust/vimspector_test/.vimspector.json
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"$schema": "https://puremourning.github.io/vimspector/schema/vimspector.schema.json",
|
||||
"configurations": {
|
||||
"Run - CodeLLDB": {
|
||||
"adapter": "CodeLLDB",
|
||||
"configuration": {
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/target/debug/vimspector_test"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
5
support/test/rust/vimspector_test/Cargo.lock
generated
Normal file
5
support/test/rust/vimspector_test/Cargo.lock
generated
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "vimspector_test"
|
||||
version = "0.1.0"
|
||||
9
support/test/rust/vimspector_test/Cargo.toml
Normal file
9
support/test/rust/vimspector_test/Cargo.toml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
[package]
|
||||
name = "vimspector_test"
|
||||
version = "0.1.0"
|
||||
authors = ["Ben Jackson <puremourning@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
4
support/test/rust/vimspector_test/src/main.rs
Normal file
4
support/test/rust/vimspector_test/src/main.rs
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
fn main() {
|
||||
let s = "World!";
|
||||
println!("Hello, {}!", s);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue