Merge pull request #190 from puremourning/codelldb

Support running a command and connecting to a port
This commit is contained in:
mergify[bot] 2020-07-06 13:00:52 +00:00 committed by GitHub
commit 669b019e25
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 263 additions and 81 deletions

126
README.md
View file

@ -6,7 +6,6 @@ For a tutorial and usage overview, take a look at the
[![Build Status](https://dev.azure.com/puremouron/Vimspector/_apis/build/status/puremourning.vimspector?branchName=master)](https://dev.azure.com/puremouron/Vimspector/_build/latest?definitionId=1&branchName=master) [![Gitter](https://badges.gitter.im/vimspector/Lobby.svg)](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)

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 )

View file

@ -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', {} ) )

View file

@ -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':

View file

@ -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 ):

View file

@ -0,0 +1 @@
target/

View 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"
}
}
}
}

View 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"

View 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]

View file

@ -0,0 +1,4 @@
fn main() {
let s = "World!";
println!("Hello, {}!", s);
}