-
Notifications
You must be signed in to change notification settings - Fork 174
Additional Language Support
This page details how to make Vimspector work for languages not officially mentioned in the README.
How to use these files:
- If there is a gadget installer file, save it to
<vimspector base dir>/gadgets/custom/cust_<Language>.json
. Then run./install_gadget.py --upgrade
- Merge or copy the
vimspector.json
snippet to your local.vimspector.json
or custom configurations directory and modify as appropriate.
- Introduction
- Ruby (rdbg) * Simple * Advanced
- Ruby (legacy)
- Puppet
- Kotlin
- Dart & Flutter
- Probe-rs Remote Hardware Assisted Debugging
- Help wanted
- Using an arbitrary server
- Gadget Installer Files
Debugger: https://github.com/ruby/debug
Instalation: gem install debug
(https://github.com/ruby/debug#installation)
A very simple way is to run rdbg manually and attach vimspector to it:
-
rdbg --open --port 54321 yourfile.rb
, or -
rdbg --open --port 54321 -c -- bundle exec yourthing
, or rdbg --open --port 54321 -c -- rails server
See https://github.com/ruby/debug#use-rdbg-with-commands-written-in-ruby
- Use vimspector config:
{
"$schema": "https://puremourning.github.io/vimspector/schema/vimspector.schema.json",
"configurations": {
"run": {
"adapter": {
"port": 54321
},
"configuration": {
"request": "launch"
}
}
}
}
More advanced: get vimspector to run rdbg
for you, using "remote" debugging,
for example:
{
"$schema": "https://puremourning.github.io/vimspector/schema/vimspector.schema.json",
"adapters": {
"rdbg-script": {
"variables": {
"port": "${unusedLocalPort}"
},
"launch": {
"remote": {
"runCommand": [
"rdbg",
"--open",
"--port", "${port}",
"--",
"%CMD%"
]
}
},
"port": "${port}"
},
"rdbg-command": {
"variables": {
"port": "${unusedLocalPort}"
},
"launch": {
"remote": {
"runCommand": [
"rdbg",
"--open",
"--port", "${port}",
"-c",
"--",
"%CMD%"
]
}
},
"port": "${port}",
"configuration": {
"request": "launch"
}
}
},
"configurations": {
"run current script": {
"adapter": "rdbg-script",
"remote-cmdLine": [
"${file}"
],
"configuration": {}
},
"run rails": {
"adapter": "rdbg-command",
"remote-cmdLine": [
"rails",
"server"
]
}
}
}
cust_vscode-ruby.json
{
"cust_vscode-ruby": {
"download": {
"url": "https://github.com/rubyide/vscode-ruby/releases/download/v${version}/${file_name}"
},
"all": {
"version": "0.25.0",
"file_name": "ruby-0.25.0.vsix",
"checksum": "fc67efbdc7261e7e1ae53707ead9bda10ec19c498369ff8a3ccd2e7fb8125a68",
"adapters": {
"cust_vscode-ruby": {
"command": [
"node",
"${gadgetDir}/cust_vscode-ruby/dist/debugger/main.js"
],
"name": "vscode-ruby-debug",
"configuration": {
"cwd": "${workspaceRoot}",
"showDebugOutput": false,
"trace": false
}
}
}
}
}
}
{
"configurations": {
"launch current file": {
"adapter": "cust_vscode-ruby",
"configuration": {
"request": "launch",
"program": "${file}",
"args": [ "*${args}" ]
}
}
}
}
Details and Dependencies: https://github.com/rubyide/vscode-ruby/blob/master/docs/debugger.md
cust_puppet-debugserver.json
{
"cust_puppet-debugserver": {
"download": {
"url": "https://github.com/puppetlabs/puppet-editor-services/releases/download/${version}/${file_name}"
},
"all": {
"version": "1.0.1",
"file_name": "puppet_editor_services_1.0.1.zip",
"checksum": "15b33bf63062f226466191d4417368a411f6a14f53c67d4898ca488a8b22454b",
"extension_path": "",
"adapters": {
"cust_puppet-debugserver": {
"command": [
"ruby",
"${gadgetDir}/cust_puppet-debugserver/puppet-debugserver",
"--port",
"${unusedLocalPort}"
],
"configuration": {
"cwd": "${workspaceRoot}"
},
"name": "puppet-debugserver",
"port": "${unusedLocalPort}"
}
}
}
}
}
{
"configurations": {
"launch current file": {
"adapter": "cust_puppet-debugserver",
"configuration": {
"request": "launch",
"manifest": "${file}",
"noop": true,
"args": [
"--modulepath",
"/path/to/your/modules"
]
}
}
}
}
Some considerations:
- about the configurations:
- the
manifest
configuration parameter is required, otherwisepuppet apply
errors out and thepuppet-debugserver
adapter crashes -
noop
is convenient in order to avoid applying manifests for real on your machine -
args
are additional arguments given topuppet apply
, so of course--modulepath
is optional, but it's handy when debugging anything with dependencies.
- the
- The debugger doesn't seem to have a configuration to stop on entry. You need to set at least one breakpoint somewhere to make it stop.
cust_kotlin-debug-adapter.json
{
"cust_kotlin-debug-adapter": {
"download": {
"url": "https://github.com/fwcd/kotlin-debug-adapter/releases/download/${version}/${file_name}"
},
"all": {
"version": "0.4.2",
"file_name": "adapter.zip",
"checksum": "434abbcc5600fa6d2424930a7c81e4c30ae5fbf05cce1cbb0af96b58db540294",
"make_executable": [
"bin/kotlin-debug-adapter"
],
"extension_path": "adapter",
"adapters": {
"cust_kotlin-debug-adapter": {
"command": [
"${gadgetDir}/cust_kotlin-debug-adapter/bin/kotlin-debug-adapter"
],
"name": "kotlin-debug-adapter",
"configuration": {
"projectRoot": "${workspaceRoot}"
}
}
}
}
}
}
.vimspector.json
{
"configurations": {
"kotlin-debug-adapter launch": {
"adapter": "cust_kotlin-debug-adapter",
"configuration": {
"request": "launch",
"projectRoot": "${workspaceFolder}",
"mainClass": "vimspector/test/ApplicationKt"
}
},
"kotlin-debug-adapter attach": {
"adapter": "cust_kotlin-debug-adapter",
"configuration": {
"request": "attach",
"projectRoot": "${workspaceFolder}",
"hostName": "${hostName}",
"port": "${port}"
}
}
}
}
Details and Dependencies: https://github.com/fwcd/kotlin-debug-adapter
Clone the Dart-Code repo onto your system.
Use "type": "flutter"
to debug Flutter apps.
cust_dart_flutter-debug-adapter.json
"cust_dart-debug-adapter": {
"command": [
"node",
"${root}/out/dist/debug.js",
"dart"
],
"type": "dart",
"variables": {
"root": "/path/to/Dart-Code"
}
}
{
"configurations": {
"launch": {
"adapter": "cust_dart-debug-adapter",
"configuration": {
"request": "launch",
"type": "flutter",
"flutterSdkPath": "/path/to/flutter", // Change this
"dartSdkPath": "/path/to/flutter/bin/cache/dart-sdk/bin", // Change this
"program": "${workspaceRoot}/main.dart", // Change this
"cwd": "${workspaceRoot}" // Change this (optionally)
}
}
}
}
Place this in e.g. your ~/.vimrc
to enable hot-reloading on save.
function! s:DartHotReload()
if py3eval( 'not _vimspector_session or not _vimspector_session._connection' )
return
endif
py3 _vimspector_session._connection.DoRequest( None, { 'command': 'hotReload' } )
endfunction
autocmd BufWritePost *.dart call s:DartHotReload()
Probe-rs is software to make use of various "debug probes" (hardware interfaces - often USB adapters such as CMSIS-DAP, JLink, FTDI, STLink etc.) to program and debug many microcontrollers and microprocessors. It uses hardware features to debug "bare metal" software such as embedded control systems, RTOS, or full operating systems. Although it's most often used to debug Rust on microcontrollers, it can also be used to debug a diverse range of languages and hardware for instance it can be used to interactively debug the Linux kernel C code running on the Raspberry Pi 4 from another machine.
Follow the install instructions on the probe-rs website. You must use a version newer than Release 0.21.0 (or build from git master). Since there are a very large number of possible combinations of host OS, debug hardware and target hardware, it is strongly recommended to configure and manually test the probe-run
binary with your particular hardware configuration (e.g. to program and execute code, and receive simple debug output strings etc.) before moving on to configure vimspector.
The "configuration"
section is passed to probe-rs, and can be edited with reference to the probe-rs option documentation
The first RUST_LOG
entry will enable verbose debug logging output from probe-rs itself, (this could be changed to warn
or info
).
The example configuration below is suitable for debugging a bare metal Rust executable running on an STM32F401CEU6 microcontroller (ARM Cortex-M4) with an "STLink" USB to SWD debug probe (autodetected by probe-rs):
{
"$schema": "https://puremourning.github.io/vimspector/schema/vimspector.schema.json#",
"adapters": {
"probe-rs": {
"command": [
"probe-rs",
"dap-server",
"--port",
"${unusedLocalPort}"
],
"name": "probe-rs",
"port": "${unusedLocalPort}",
"env": {
"RUST_LOG": "debug"
}
}
},
"configurations": {
"attach to probe-rs dap": {
"adapter": "probe-rs",
"filetypes": [ "rust" ],
"configuration": {
"request": "launch",
"cwd": "${workspaceRoot}",
"chip": "STM32F401CEUx",
"coreConfigs": [
{
"coreIndex": 0,
"svdFile": "/home/tim/prog/rust/stm32-rs/svd/stm32f401.svd.patched",
"programBinary": "./target/thumbv7em-none-eabihf/release/fugit-test1",
"rttEnabled": true
}
],
"env": {
"DEFMT_LOG": "debug",
"RUST_LOG": "debug"
},
"runtimeExecutable": "probe-rs",
"runtimeArgs": ["dap-server"],
"flashingConfig": {
"flashingEnabled": true,
"haltAfterReset": false,
"formatOptions": {
"format": "elf"
}
},
"connectUnderReset": false,
"consoleLogLevel": "Debug"
}
}
}
}
... alternatively you can change "adapter": "probe-rs"
to "adapter": "multi-session"
and run probe-rs manually on the command line: e.g. $ probe-rs dap-server --port 4567
.
Help improve Vimspector by writing gadget installer files and configuration snippets for these servers:
In general, the approach is:
- Install the VSCode extension. You can either use VSCode to install it, or you can extract the file manually (it's usually a zip file). Vimspector also supports an experrimental configuration which will use Vimspector's own installer (see later)
-
Work out how to launch it. Find out how the VSCode extension launches the
debug adapter. This is usually a matter of opening the
package.json
for the extension and finding thecontributes
entry fordebuggers
. Most of the time, it's just a simple command likenode some/path/main.js
). -
Set up the
adapter
block in your.vimspector.json
. This can be as simple as just a command, but see the full adapter specification for details.
{
"adapters": {
"<your-adapter-name>": {
"command": "<command to launch adapter>"
}
}
}
- Find out what launch arguments are needed. This is often documented by the server author, but will usually be targetted at VScode users and may be incomplete. Most of the time, however, launch arguments are documented and generally work the same in Vimspector as any other DAP client (e.g. VSCode).
You can save the gadget config (adapter
block) to <vimspector base dir>/gadgets/.gadgets.d/<name>.json
or just put it in your local
.vimspector.json
. In general, I recommend the former.
** NOTE: This is an experimental feature and may change at any time, or be completely withdrawn **
Vimspector's installer has support for downloading and unpacking arbitrary gadgets using the same mechanisms that the 'officially' supported gadgets use. It is however somewhat limited and only works for some types of gadget.
The way this is done is by dropping a JSON file in gadgets/custom/
which
contains a specification for the gadget to install. This tells Vimspector what
to download and how to set up the gadget config.
Currently this is only supported with install_gadget.py
(not with
:VimspectorInstall
or :VimspectorUpdate
).
Each gadget installer file must contain a single object with keys as the names
of gadgets (and conventionally start with cust_
to differentiate from those
officially supported), and whose values as an object describing the gadget as
follows:
-
download (object): Describes what to download
- download.url: (string) URL to download
- download.target (string, optional): File name to save the result to
-
download.format (string, optional, default:
zip
): one ofzip
,zip.gz
,tar
-
repo (object): If supplied, clone this repo (rather than downloading a zip)
- repo.url (string): Url to clone
-
repo.ref (string): Ref (branch/tag) to check out (e.g.
master
orvX.Y.Z
)
- make_executable (list of string): List of relative paths within the bundle to make executable after download/install. See next section.
-
all (object): parameters for the gadget on all platforms. These items are
available as
${item}
(e.g.${version}
) within thedownload
andrepo
string keys.-
all.version (string): The version. Available as
${version}
. -
all.file_name (string): The resulting downloaded file name.
${file_name}
- all.checksum (string): The expected SHA256 checksum of downloaded file.
-
all.extension_path (string, optional, default:
extension
): The base path of the downloaded extension. The purpose of this property is to support generic debug adapters, vs code extensions should work with the default value. - all.'anything' (string): Any additional parameters
-
all.adapters (object): Adapters to create. Same format as
adapter
block in.vimspector.json
-
all.version (string): The version. Available as
-
<os>
(object):<os>
can bewindows
,linux
ormacos
and the object has the same definition asall
. Any values supplied in this block override those inall
for the specified OS.
This format is a JSON-equivalent of the format used in
python3/vimspector/gadgets.py
.
For some reason that can only be explained by history, the vsix
format used
for VScode does not include 'execute' file permissions. Therefore, when
unzipping such extensions, you need to manually set the execute flag on all the
files in the bundle that should be executable.
Therefore when creating a gadget installer file, you need to work out which files should be made executable. Usually this is just the debug adapter itself if anything.
The process for working this out is to test it and see what doesn't work, or read the VScode extension's code. Sad, but that's the way it is.
Things that are defined in these blocks are used to determine if an upgrade is required. So include the version and anything that changes on upgrade.
These values are also made available in the 'download' and 'repo' blocks to save
typing. However, they are not available to each other, so you can't include
${version}
in "file_name"
, unfortunately.