puremourning
vimspector
Vim Script

vimspector - A multi-language debugging system for Vim

Last updated Jul 7, 2026
4.3k
Stars
178
Forks
42
Issues
+5
Stars/day
Attention Score
81
Language breakdown
Vim Script 51.7%
Python 42.8%
Shell 3.1%
Dockerfile 0.7%
Go 0.6%
JavaScript 0.2%
โ–ธ Files click to expand
README

vimspector - A multi language graphical debugger for Vim

For a tutorial and usage overview, take a look at the [Vimspector website][website].

For detailed explanation of the .vimspector.json format, see the [reference guide][vimspector-ref].

Build Matrix Gitter

* Supported debugging features * Supported languages * Other languages * Quick Start * Method 1: Using a repo clone, Vim packages and select gadgets to be installed * Method 2: Using a plugin manager * Dependencies * Neovim limitations * Windows differences * Trying it out * Installing the plugin * Install some gadgets * VimspectorInstall and VimspectorUpdate commands * installgadget.py * Manual gadget installation * The gadget directory * Upgrade * Background * Status * Experimental * Motivation * License * Sponsorship * Visual Studio / VSCode * Human Mode * Launch and attach by PID: * Picking a PID * Launch with options * Debug configuration selection * Get configurations * Breakpoints * Breakpoints Window * Line breakpoints * Conditional breakpoints and logpoints * Exception breakpoints * Data breakpoints * API Summary * Instruction breakpoints * Clear breakpoints * Run to Cursor * Go to current line * Save and restore * Stepping * Variables and scopes * Variable or selection hover evaluation * Watches * Watch autocompletion * Disassembly * Dump memory * Stack Traces * Child sessions * Program Output * Console * Console autocompletion * Log View * Closing debugger * Terminate debuggee * C, C++, Rust, etc. * Data visualization / pretty printing * C++ Remote debugging * C++ Remote launch and attach * Rust * Jai * Python * Python Remote Debugging * Python Remote launch and attach * Python 2 * TCL * Cโ™ฏ * Go * PHP * Debug web application * Debug cli application * JavaScript and TypeScript * Java * Hot code replace * Usage with YouCompleteMe * Other LSP clients * Lua * Other servers * Changing the default signs * Sign priority * Presentation Hints * Changing the default window sizes * Changing the terminal size * Custom mappings while debugging * Pre-launch building strategies * Disabling the WinBar * Advanced UI customisation * Customising the WinBar * Example

Features and Usage

The plugin is a capable Vim graphical debugger for multiple languages. It's mostly tested for C++, Python and TCL, but in theory supports any language that Visual Studio Code supports (but see caveats).

The [Vimspector website][website] has an overview of the UI, along with basic instructions for configuration and setup.

But for now, here's a (rather old) screenshot of Vimspector debugging Vim:

vimspector-vim-screenshot

And a couple of brief demos:

asciicast

asciicast

Supported debugging features

  • flexible configuration syntax that can be checked in to source control
  • breakpoints (function, line and exception breakpoints)
  • instruction breakpoints
  • data breakpoints
  • conditional breakpoints (function, line)
  • step in/out/over/up, stop, restart
  • run to cursor
  • go to line (reset program counter to line)
  • launch and attach, including PID picker
  • remote launch, remote attach
  • locals and globals display
  • watch expressions with autocompletion
  • variable inspection tooltip on hover
  • disassembly view and step-by-instruction
  • set variable value in locals, watch and hover windows
  • call stack display and navigation
  • hierarchical variable value display popup (see <Plug>VimspectorBalloonEval)
  • interactive debug console with autocompletion
  • launch debuggee within Vim's embedded terminal
  • logging/stdout display
  • simple stable API for custom tooling (e.g. integrate with language server)
  • view hex dump of process memory
  • multiple independent debugging sessions (debug different apps in tabs)
  • multi-process (multi-session) debugging

Supported languages

The following table lists the languages that are "built-in" (along with their runtime dependencies). They are categorised by their level of support:

  • Tested : Fully supported, Vimspector regression tests cover them
  • Supported : Fully supported, frequently used and manually tested
  • Experimental: Working, but not frequently used and rarely tested
  • Legacy: No longer supported, please migrate your config
  • Retired: No longer included or supported.
| Language(s) | Status | Switch (for install_gadget.py) | Adapter (for :VimspectorInstall) | Dependencies | | -------------------- | ----------- | ---------------------------------- | ------------------------------------ | -------------------------------------------- | | C, C++, Rust, Jai, etc. | Tested | --all or --enable-c (or cpp) | vscode-cpptools | mono-core | | C, C++, Rust, Jai, etc. | Tested | --enable-rust, --enable-c, etc. | CodeLLDB | none | | Python | Tested | --all or --enable-python | debugpy | Python 3 | | Go | Tested | --enable-go | delve | Go 1.16+ | | TCL | Supported | --all or --enable-tcl | tclpro | TCL >= 8.5 < 9.0 | | Bourne Shell | Supported | --all or --enable-bash | vscode-bash-debug | Bash v?? | | Lua | Tested | --all or --enable-lua | local-lua-debugger-vscode | Node >=12.13.0, Npm, Lua interpreter | | Node.js | Supported | --force-enable-node | vscode-js-debug | Node >= 18 | | Javascript | Legacy [Deprecated] | --force-enable-chrome | debugger-for-chrome | Chrome | | Javascript | Legacy [Unsupported] | --force-enable-firefox | vscode-firefox-debug | Firefox | | Java | Supported | --force-enable-java | vscode-java-debug | Compatible LSP plugin (see later) | | PHP | Experimental | --force-enable-php | vscode-php-debug | Node, PHP, XDEBUG | | C# (dotnet core) | Tested | --force-enable-csharp | netcoredbg | DotNet core | | F#, VB, etc. | Supported | --force-enable-[fsharp,vbnet] | netcoredbg | DotNet core |

Other languages

Vimspector should work for any debug adapter that works in Visual Studio Code.

To use Vimspector with a language that's not "built-in", see this wiki page.

Installation

Quick Start

There are 2 installation methods:

  • Using a repo clone and Vim packages
  • Using a plugin manager

Method 1: Using a repo clone, Vim packages and select gadgets to be installed

g:vimspector_configurations) - see the [reference guide][vimspector-ref]

Method 2: Using a plugin manager

For Vundle, use:
Plugin 'puremourning/vimspector'
g:vimspector_configurations) - see the [reference guide][vimspector-ref]

The following sections expand on the above brief overview.

Dependencies

Vimspector requires:

  • One of:
* Vim 8.2.4797 or later "huge" build compiled with Python 3.10 or later * Neovim 0.8 with Python 3.10 or later
  • One of the following operating systems:
* Linux * macOS Mojave or later * Windows (experimental)

Which Linux versions? I only test on Ubuntu 20.04 and later and RHEL 7.

Neovim limitations

Neovim doesn't implement mouse hover balloons. Instead there is the <Plug>VimspectorBalloonEval mapping. There is no default mapping for this, so I recommend something like this to get variable display in a popup:

" mnemonic 'di' = 'debug inspect' (pick your own, if you prefer!)

" for normal mode - the word under the cursor nmap <Leader>di <Plug>VimspectorBalloonEval " for visual mode, the visually selected text xmap <Leader>di <Plug>VimspectorBalloonEval

Windows differences

The following features are not implemented for Windows:

  • Tailing the vimspector log in the Output Window.

Trying it out

If you just want to try out vimspector without changing your vim config, there are example projects for a number of languages in support/test, including:

To test one of these out, cd to the directory and run:
vim -Nu /path/to/vimspector/tests/vimrc --cmd "let g:vimspectorenablemappings='HUMAN'"

Then press <F5>.

There's also a C++ project in tests/testdata/cpp/simple/ with a Makefile which can be used to check everything is working. This is used by the regression tests in CI so should always work, and is a good way to check if the problem is your configuration rather than a bug.

Installing the plugin

  • Clone the plugin
There are many Vim plugin managers, and I'm not going to state a particular preference, so if you choose to use one, follow the plugin manager's documentation. For example, for Vundle, use:
Plugin 'puremourning/vimspector'

If you don't use a plugin manager already, install vimspector as a Vim package by cloning this repository into your package path, like this:

$ git clone https://github.com/puremourning/vimspector ~/.vim/pack/vimspector/opt/vimspector
  • Configure vimspector in your .vimrc, for example to enable the standard
mappings:
let g:vimspectorenablemappings = 'HUMAN'
  • Load vimspector at runtime. This can also be added to your .vimrc after
configuring vimspector:
packadd! vimspector

See support/doc/example_vimrc.vim for a minimal example.

Install some gadgets

Vimspector is a generic client for Debug Adapters. Debug Adapters (referred to as 'gadgets' or 'adapters') are what actually do the work of talking to the real debuggers.

In order for Vimspector to be useful, you need to have some adapters installed.

There are a few ways to do this:

  • Using :VimspectorInstall <adapter> <args...> (use TAB wildmenu to see the
options, also accepts any install_gadget.py option)
  • Using python3 install_gadget.py <args> (use --help to see all options)
  • Attempting to launch a debug configuration; if the configured adapter
can't be found, vimspector will suggest installing one.
  • Using :VimspectorUpdate to install the latest supported versions of the
gadgets.

Here's a demo of doing some installs and an upgrade:

asciicast

Both install_gadget.py and :VimspectorInstall do the same set of things, though the default behaviours are slightly different. For supported languages, they will:

  • Download the relevant debug adapter at a version that's been tested from the
internet, either as a 'vsix' (Visual Studio plugin), or clone from GitHub. If you're in a corporate environment and this is a problem, you may need to install the gadgets manually.
  • Perform any necessary post-installation actions, such as:
* Building any binary components * Ensuring scripts are executable, because the VSIX packages are usually broken in this regard. * Set up the gadgetDir symlinks for the platform.

For example, to install the tested debug adapter for a language, run:

| To install | Script | Command | | --- | --- | --- | | <adapter> | | :VimspectorInstall <adapter> | | <adapter1>, <adapter2>, ... | | :VimspectorInstall <adapter1> <adapter2> ... | | <language> | ./install_gadget.py --enable-<language> ... | :VimspectorInstall --enable-<language> ... | | Supported adapters | ./install_gadget.py --all | :VimspectorInstall --all | | Supported adapters, but not TCL | ./install_gadget.py --all --disable-tcl | :VimspectorInstall --all --disable-tcl | | Supported and experimental adapters | ./install_gadget.py --all --force-all | :VimspectorInstall --all | | Adapter for specific debug config | | Suggested by Vimspector when starting debugging |

VimspectorInstall and VimspectorUpdate commands

:VimspectorInstall runs install_gadget.py in the background with some of the options defaulted.

:VimspectorUpdate runs install_gadget.py to re-install (i.e. update) any gadgets already installed in your .gadgets.json.

The output is minimal, to see the full output add --verbose to the command, as in :VimspectorInstall --verbose ... or :VimspectorUpdate --verbose ....

If the installation is successful, the output window is closed (and the output lost forever). Use a ! to keep it open (e.g. :VimspectorInstall! --verbose --all or :VimspectorUpdate! (etc.).

If you know in advance which gadgets you want to install, for example so that you can reproduce your config from source control, you can set g:vimspectorinstallgadgets to a list of gadgets. This will be used when:

  • Running :VimspectorInstall with no arguments, or
  • Running :VimspectorUpdate
For example:
let g:vimspectorinstallgadgets = [ 'debugpy', 'vscode-cpptools', 'CodeLLDB' ]

install\_gadget.py

By default install_gadget.py will overwrite your .gadgets.json with the set of adapters just installed, whereas :VimspectorInstall will update it, overwriting only newly changed or installed adapters.

If you want to just add a new adapter using the script without destroying the existing ones, add --update-gadget-config, as in:

$ ./install_gadget.py --enable-tcl
$ ./install_gadget.py --enable-rust --update-gadget-config
$ ./install_gadget.py --enable-java --update-gadget-config

If you want to maintain configurations outside of the vimspector repository (this can be useful if you have custom gadgets or global configurations), you can tell the installer to use a different basedir, then set g:vimspectorbasedir to point to that directory, for example:

$ ./install_gadget.py --basedir $HOME/.vim/vimspector-config --all --force-all

Then add this to your .vimrc:

let g:vimspectorbasedir=expand( '$HOME/.vim/vimspector-config' )

When using :VimspectorInstall, the g:vimspectorbasedir setting is respected unless --basedir is manually added (not recommended).

See --help for more info on the various options.

Manual gadget installation

If the language you want to debug is not in the supported list above, you can probably still make it work, but it's more effort.

You essentially need to get a working installation of the debug adapter, find out how to start it, and configure that in an adapters entry in either your .vimspector.json or in .gadgets.json or in g:vimspector_adapters.

The simplest way in practice is to install or start Visual Studio Code and use its extension manager to install the relevant extension. You can then configure the adapter manually in the adapters section of your .vimspector.json or in a gadgets.json or in g:vimspector_adapters.

PRs are always welcome to add supported languages (which roughly translates to updating python/vimspector/gadgets.py and testing it).

The gadget directory

Vimspector uses the following directory by default to look for a file named .gadgets.json: </path/to/vimspector>/gadgets/<os>.

This path is exposed as the vimspector variable ${gadgetDir}. This is useful for configuring gadget command lines.

Where os is one of:

  • macos
  • linux
  • windows (though note: Windows is not supported)
The format is the same as .vimspector.json, but only the adapters key is used:

Example:

{
  "adapters": {
    "lldb-dap": {
      "variables": {
        "LLVM": {
          "shell": "brew --prefix llvm"
        }
      },
      "attach": {
        "pidProperty": "pid",
        "pidSelect": "ask"
      },
      "command": [
        "lldb-dap"
      ],
      "env": {
        "LLDBLAUNCHFLAGLAUNCHIN_TTY": "YES"
      },
      "name": "lldb"
    },
    "vscode-cpptools": {
      "attach": {
        "pidProperty": "processId",
        "pidSelect": "ask"
      },
      "command": [
        "${gadgetDir}/vscode-cpptools/debugAdapters/bin/OpenDebugAD7"
      ],
      "name": "cppdbg"
    }
  }
}

The gadget file is automatically written by install_gadget.py (or :VimspectorInstall).

Vimspector will also load any files matching: </path/to/vimspector>/gadgets/<os>/.gadgets.d/*.json. These have the same format as .gadgets.json but are not overwritten when running install_gadget.py.

Upgrade

After updating the Vimspector code (either via git pull or whatever package manager), run :VimspectorUpdate to update any already-installed gadgets.

About

Background

The motivation is that debugging in Vim is a pretty horrible experience, particularly if you use multiple languages. With pyclewn no more and the built-in termdebug plugin limited to gdb, I wanted to explore options.

While Language Server Protocol is well known, the Debug Adapter Protocol is less well known, but achieves a similar goal: language agnostic API abstracting debuggers from clients.

The aim of this project is to provide a simple but effective debugging experience in Vim for multiple languages, by leveraging the debug adapters that are being built for Visual Studio Code.

The ability to do remote debugging is a must. This is key to my workflow, so baking it in to the debugging experience is a top bill goal for the project. So vimspector has first-class support for executing programs remotely and attaching to them. This support is unique to vimspector and on top of (complementary to) any such support in actual debug adapters.

What Vimspector is not

Vimspector is a vim UI on top of the Debug Adapter Protocol. It's intended to be high level and convenient for day-to-day debugging tasks.

Vimspector is not:

  • a debugger! It's just the UI and some glue.
  • fast. It's abstractions all the way down. If you want a fast, native debugger,
there are other options.
  • comprehensive. It's limited by DAP, and limited by my time. I implement the
features I think most users will need, not every feature possible.
  • for everyone. Vimspector intentionally provides a "one size fits all" UI and
approach. This means that it can only provide essential/basic debugging features for a given language. This makes it convenient for everyday usage, but not ideal for power users or those with very precise or specific requirements. See motivation for more info.

Status

Vimspector is a work in progress, and any feedback/contributions are more than welcome.

The backlog can be viewed on Trello.

Experimental

The plugin is currently experimental. That means that any part of it can (and probably will) change, including things like:

  • breaking changes to the configuration
  • keys, layout, functionality of the UI
However, I commit to only doing this in the most extreme cases and to announce such changes on Gitter well in advance. There's nothing more annoying than stuff just breaking on you. I get that.

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

Copyright ยฉ 2018 Ben Jackson

Sponsorship

If you like Vimspector so much that you're wiling to part with your hard-earned cash, please consider donating to one of the following charities, which are meaningful to the author of Vimspector (in order of preference):

Mappings

By default, vimspector does not change any of your mappings. Mappings are very personal and so you should work out what you like and use vim's powerful mapping features to set your own mappings. To that end, Vimspector defines the following <Plug> mappings:

| Mapping | Function | API | | --- | --- | --- | | <Plug>VimspectorContinue | When debugging, continue. Otherwise start debugging. | vimspector#Continue() | | <Plug>VimspectorStop | Stop debugging. | vimspector#Stop() | | <Plug>VimspectorRestart | Restart debugging with the same configuration. | vimspector#Restart() | | <Plug>VimspectorPause | Pause debuggee. | vimspector#Pause() | | <Plug>VimspectorBreakpoints | Show/hide the breakpoints window | vimspector#ListBreakpoints() | | <Plug>VimspectorToggleBreakpoint | Toggle line breakpoint on the current line. | vimspector#ToggleBreakpoint() | | <Plug>VimspectorToggleConditionalBreakpoint | Toggle conditional line breakpoint or logpoint on the current line. | vimspector#ToggleBreakpoint( { trigger expr, hit count expr } ) | | <Plug>VimspectorAddFunctionBreakpoint | Add a function breakpoint for the expression under cursor | vimspector#AddFunctionBreakpoint( '<cexpr>' ) | | <Plug>VimspectorGoToCurrentLine | Reset the current program counter to the current line | vimspector#GoToCurrentLine() | | <Plug>VimspectorRunToCursor | Run to Cursor | vimspector#RunToCursor() | | <Plug>VimspectorStepOver | Step Over | vimspector#StepOver() | | <Plug>VimspectorStepInto | Step Into | vimspector#StepInto() | | <Plug>VimspectorStepOut | Step out of current function scope | vimspector#StepOut() | | <Plug>VimspectorDisassemble | Show disassembly. Enable instruction stepping | vimspector#ShowDisassembly() | | <Plug>VimspectorUpFrame | Move up a frame in the current call stack | vimspector#UpFrame() | | <Plug>VimspectorDownFrame | Move down a frame in the current call stack | vimspector#DownFrame() | | <Plug>VimspectorJumpToNextBreakpoint | Move Cursor to the next breakpoint in current file | vimspector#JumpToNextBreakpoint() | | <Plug>VimspectorJumpToPreviousBreakpoint | Move Cursor to the previous breakpoint in current file | vimspector#JumpToPreviousBreakpoint() | | <Plug>VimspectorJumpToProgramCounter | Move Cursor to the program counter in the current frame | vimspector#JumpToProgramCounter() | | <Plug>VimspectorBalloonEval | Evaluate expression under cursor (or visual) in popup | internal |

These map roughly 1-1 with the API functions below.

For example, if you want <F5> to start/continue debugging, add this to some appropriate place, such as your vimrc (hint: run :e $MYVIMRC).

nmap <F5> <Plug>VimspectorContinue

In addition, many users probably want to only enable certain Vimspector mappings while debugging is active. This is also possible, though it requires writing some vimscript.

That said, many people are familiar with particular debuggers, so the following mappings can be enabled by setting g:vimspectorenablemappings to the specified value.

Visual Studio / VSCode

To use Visual Studio-like mappings, add the following to your vimrc **before loading vimspector**:

let g:vimspectorenablemappings = 'VISUAL_STUDIO'

| Key | Mapping | Function | --- | --- | --- | F5 | <Plug>VimspectorContinue | When debugging, continue. Otherwise start debugging. | Shift F5 | <Plug>VimspectorStop | Stop debugging. | Ctrl Shift F5 | <Plug>VimspectorRestart | Restart debugging with the same configuration. | F6 | <Plug>VimspectorPause | Pause debuggee. | F8 | <Plug>VimspectorJumpToNextBreakpoint | Jump to next breakpoint in the current file. | Shift F8 | <Plug>VimspectorJumpToPreviousBreakpoint | Jump to previous breakpoint in the current file. | F9 | <Plug>VimspectorToggleBreakpoint | Toggle line breakpoint on the current line. | Shift F9 | <Plug>VimspectorAddFunctionBreakpoint | Add a function breakpoint for the expression under cursor | F10 | <Plug>VimspectorStepOver | Step Over | Ctrl F10 | <Plug>VimspectorRunToCursor | Run to cursor* | F11 | <Plug>VimspectorStepInto | Step Into | Shift F11 | <Plug>VimspectorStepOut | Step out of current function scope | Alt 8 | <Plug>VimspectorDisassemble | Show disassembly

*NOTE: Some mappings, such as ctrl and F-keys may not work depending on your terminal, keyboard, windowing system and all sorts of other things. See :help modifyOtherKeys and other sources. If you are unable to make this work, just use the "human mode" mappings.*

Human Mode

If, like me, you only have 2 hands and 10 fingers, you probably don't like Ctrl-Shift-F keys. Also, if you're running in a terminal, there's a real possibility of terminfo being wrong for shifted-F-keys, particularly if your TERM is screen-256color. If these issues (number of hands, TERM variables) are unfixable, try the following mappings, by adding the following **before loading vimspector**:

let g:vimspectorenablemappings = 'HUMAN'

| Key | Mapping | Function | --- | --- | --- | F5 | <Plug>VimspectorContinue | When debugging, continue. Otherwise start debugging. | F3 | <Plug>VimspectorStop | Stop debugging. | F4 | <Plug>VimspectorRestart | Restart debugging with the same configuration. | F6 | <Plug>VimspectorPause | Pause debuggee. | F9 | <Plug>VimspectorToggleBreakpoint | Toggle line breakpoint on the current line. | <leader>F9 | <Plug>VimspectorToggleConditionalBreakpoint | Toggle conditional line breakpoint or logpoint on the current line. | F8 | <Plug>VimspectorAddFunctionBreakpoint | Add a function breakpoint for the expression under cursor | <leader>F8 | <Plug>VimspectorRunToCursor | Run to Cursor | F10 | <Plug>VimspectorStepOver | Step Over | F11 | <Plug>VimspectorStepInto | Step Into | F12 | <Plug>VimspectorStepOut | Step out of current function scope

In addition, I recommend adding a mapping to <Plug>VimspectorBalloonEval, in normal and visual modes, for example:

" mnemonic 'di' = 'debug inspect' (pick your own, if you prefer!)

" for normal mode - the word under the cursor nmap <Leader>di <Plug>VimspectorBalloonEval " for visual mode, the visually selected text xmap <Leader>di <Plug>VimspectorBalloonEval

You may also wish to add mappings for navigating up/down the stack, toggling the breakpoints window, and showing disassembly, for example:

nmap <LocalLeader><F11> <Plug>VimspectorUpFrame
nmap <LocalLeader><F12> <Plug>VimspectorDownFrame
nmap <LocalLeader>B     <Plug>VimspectorBreakpoints
nmap <LocalLeader>D     <Plug>VimspectorDisassemble

Usage and API

This section defines detailed usage instructions, organised by feature. For most users, the mappings section contains the most common commands and default usage. This section can be used as a reference to create your own mappings or custom behaviours.

All the below instructions assume a single debugging session. For details on how to debug multiple independent apps at the same time, see [multiple debugging sessions][#multiple-debugging-sessions].

Launch and attach by PID:

  • Create .vimspector.json. See below.
  • :call vimspector#Launch() and select a configuration.
debug session

Launching a new session makes it the active [debugging session][#multiple-debugging-sessions].

Picking a PID

If the debug adapter configuration uses pidProperty, and you make an attach request, then you will be asked to enter a PID (process ID) to attach to.

To make this easier, Vimspector supplies a little utility for listing PIDs. It's like a very very simple clone of ps but works on all the supported platforms. See its README for instructions on setting it up.

Run go build in the support/vimspectorprocesslist directory to set it up.

If Vimspector is able to find this app, it will try to list all processes owned by the current user by default.

Alternatively (preferably), you can use a special form of variable expansion called ${PickProcess(\"binaryName\")}. The version of this call will list all processes for the current user that match this binary name.

For example:

"Attach": {
  "adapter": "CodeLLDB",
  "configuration": {
    "request": "attach",
    "program": "${workspaceRoot}/Jails",
    "pid": "${PickProcess(\"jails\")}"
  }
}

This will list each matching processes, its parent process, start time and working directory. It's looks something like this:

PID   PPID           CWD                                           START
52218 52217 (Python) /Users/ben/.vim/bundle/lsp-examples/jai/Jails 2023-05-22 16:02:24
Enter Process ID:

You then enter the PID and hit <CR>.

You can even replace the process picker with your own function. If you define some function and set g:vimspectorcustomprocesspickerfunc to the name of that function. It will be passed any arguments passed to the PickProcess expansion function. It will also be used whenever a pidProperty is specified, so it must also handle no arguments (use ... as the formal arguments for the function, see :help ...).

For example, to use fzf along with the supplied vimspectorprocesslist:

function! CustomPickProcess( ... ) abort
  let ps = $HOME .. '/.vim/bundle/vimspector/support/vimspectorprocesslist/vimspectorprocesslist'
  " a:0 is number of args
  " a:1 is the optional binary name
  if a:0 > 0
    let ps .= ' ^' . a:1 . '$'
  endif

let line_selected = fzf#run( { \ 'source': ps, \ 'options': '--header-lines=1 ' \ . '--prompt="Select Process: " ' \ , \ \ } )[ 0 ] if empty( line_selected) return 0 endif let pid = split( line_selected )[ 0 ] return str2nr( pid ) endfunction

let g:vimspectorcustomprocesspickerfunc = 'CustomPickProcess'

Or to use fzf with the output of ps:

function! CustomPickProcess( ... ) abort
  let ps = 'ps aux'

let line_selected = fzf#run( { \ 'source': ps, \ 'options': '--header-lines=1 ' \ . '--prompt="Select Process: " ' \ , \ \ } )[ 0 ] if empty( line_selected) return 0 endif let pid = split( line_selected )[ 0 ] return str2nr( pid ) endfunction

let g:vimspectorcustomprocesspickerfunc = 'CustomPickProcess'

Launch with options

To launch a specific debug configuration, or specify [replacement variables][vimspector-ref-var] for the launch, you can use:

  • :call vimspector#LaunchWithSettings( dict )
The argument is a dict with the following keys:
  • configuration: (optional) Name of the debug configuration to launch
  • <anything else>: (optional) Name of a variable to set
This allows for some integration and automation. For example, if you have a configuration named Run Test that contains a [replacement variable][vimspector-ref-var] named ${Test} you could write a mapping which ultimately executes:
vimspector#LaunchWithSettings( #{ configuration: 'Run Test'
                                \ Test: 'Name of the test' } )

This would start the Run Test configuration with ${Test} set to 'Name of the test' and Vimspector would not prompt the user to enter or confirm these things.

See our YouCompleteMe integration guide for another example where it can be used to specify the port to connect the java debugger

To launch with an ad-hoc config you can use:

  • call vimspector#LaunchWithConfigurations( dict )
The argument is a dict which is the configurations section of a .vimspector file. Pass one configuration in and that will be selected as the one to run. For example:
let pid = <some_expression>
   call vimspector#LaunchWithConfigurations({
               \  "attach": {
               \    "adapter": "netcoredbg",
               \    "configuration": {
               \      "request": "attach",
               \      "processId": pid
               \    }
               \  }
               \})

This would launch the debugger and attach to the specified process without the need to have a local .vimspector file on disk. The ${workspaceRoot} variable will point to the parent folder of the file that is currently open in vim.

Debug configuration selection

Vimspector uses the following logic to choose a configuration to launch:

  • If a configuration was specified in the launch options (as above), use that.
  • Otherwise if there's only one configuration and it doesn't have autoselect
set to false, use that.
  • Otherwise if there's exactly one configuration with default set to true
and without autoselect set to false, use that.
  • Otherwise, prompt the user to select a configuration.
See [the reference guide][vimspector-ref-config-selection] for details.

Get configurations

  • Use vimspector#GetConfigurations() to get a list of configurations for the
filetype of the current buffer

For example, to get an array of configurations and fuzzy matching on the result

:call matchfuzzy(vimspector#GetConfigurations(), "test::case_1")

Breakpoints

See the mappings section for the default mappings for working with breakpoints. This section describes the full API in vimscript functions.

Breakpoints are associated with the current [debugging session][#multiple-debugging-sessions]. When switching between sessions, the breakpoint signs for the previous session are removed and the breakpoints for the newly activated session are displayed. While it might be useful to see breakpoints for all sessions, this can be very confusing.

Breakpoints Window

Use :VimspectorBreakpoints or map something to <Plug>VimspectorBreakpoints to open the breakpoints view. From here you can list, jump to delete, add and toggle breakpoints.

I recommend a mapping like this to toggle the breakpoints window:

nmap <Leader>db <Plug>VimspectorBreakpoints

The following mappings apply by default in the breakpoints window:

  • t, <F9> - toggle, i.e. enable/disable breakpoint
  • T - toggle, i.e. enable/disable ALL breakpoints
  • dd, <Del> - delete the current breakpoint
  • cc, C - edit the current breakpoint options
  • i, a, o - add a new line breakpoint
  • I, A, O - add a new function breakpoint
  • <Enter> or double-click - jump to the line breakpoint
A WinBar is provided (where supported) too. This adds functions like saving/restoring sessions, clearing all breakpoints, and resetting the exception breakpoints options.

Line breakpoints

The simplest and most common form of breakpoint is a line breakpoint. Execution is paused when the specified line is executed.

For most debugging scenarios, users will just hit <F9> to create a line breakpoint on the current line and <F5> to launch the application.

Conditional breakpoints and logpoints

Some debug adapters support conditional breakpoints. Note that vimspector does not tell you if the debugger doesn't support conditional breakpoints (yet). A conditional breakpoint is a breakpoint which only triggers if some expression evaluates to true, or has some other constraints met.

Some of these functions above take a single optional argument which is a dictionary of options. The dictionary can have the following keys:

  • condition: An optional expression evaluated to determine if the breakpoint
should fire. Not supported by all debug adapters. For example, to break when abc is 10, enter something like abc == 10, depending on the language.
  • hitCondition: An optional expression evaluated to determine a number of
times the breakpoint should be ignored. Should (probably?) not be used in combination with condition. Not supported by all debug adapters. For example, to break on the 3rd time hitting this line, enter 3.
  • logMessage: An optional string to make this breakpoint a "logpoint" instead.
When triggered, this message is printed to the console rather than interrupting execution. You can embed expressions in braces {like this}, for example #{ logMessage: "Iteration {i} or {num_entries / 2}" }

In each case expressions are evaluated by the debugger, so should be in whatever dialect the debugger understands when evaluating expressions.

When using the <leader><F9> mapping, the user is prompted to enter these expressions in a command line (with history).

Exception breakpoints

Exception breakpoints typically fire when an exception is throw or other error condition occurs. Depending on the debugger, when starting debugging, you may be asked a few questions about how to handle exceptions. These are "exception breakpoints" and vimspector remembers your choices while Vim is still running.

Typically you can accept the defaults (just keep pressing <CR>!) as most debug adapter defaults are sane, but if you want to break on, say uncaught exception then answer Y to that (for example).

You can configure your choices in the .vimspector.json. See [the configuration guide][vimspector-ref-exception] for details on that.

Data breakpoints

Data breakpoints are not supported by all debug adapters. They are breakpoints which trigger when some memory is read or written. They can be created:

  • For a given variable in the variables window (<F9> on variable)
  • For a given child variable in the watches or variables windows
(<F9> on child variable)
  • For an arbitrary expression which evaluates to an address (<F9> in watch
window, not on any variable)

When specifying an expression, you can also specify a size.

In general, if you hit <F9> (or whatever mapping you have) in the Variables or Watch window, you'll be adding a Data Breakpoint. If the context looks like a variable, then Vimspector will ask the debug adapter to create a data breakpoint on that variable expression. Otherwise, you'll be asked to enter an expression, or an address and a size, depending on the capabilities of the debugger.

NOTE: Not all debug adapters support data breakpoints, and the ability to actually create them often depends on the hardware of the target.

API Summary

NOTE: Previously, ToggleBreakpoint would cycle between 3 states: enabled, disabled, deleted. Many users found the 'disabled' state was rarely useful, so the behaviour has been changed. ToggleBreakpoint always creates or deletes a breakpoint. If you wish to 'disable' breakpoints, use the breakpoints window and 'toggle' (t) from there.

  • Use vimspector#ToggleBreakpoint( { options dict } ) to set/delete
a line breakpoint. The argument is optional (see below).
  • Use vimspector#AddFunctionBreakpoint( '<name>', { options dict} )
to add a function breakpoint. The second argument is optional (see below).
  • Use vimspector#SetLineBreakpoint( filename, linenum, { options dict } ) to
set a breakpoint at a specific file/line. The last argument is optional (see below)
  • Use vimspector#ClearLineBreakpoint( filename, linenum ) to
remove a breakpoint at a specific file/line
  • Use vimspector#ClearBreakpoints() to clear all breakpoints
  • Use vimspector#ResetExceptionBreakpoints() to clear the exception breakpoints
configuration and re-answer the various questions like "Break on C++ Throw"
  • Use :VimspectorMkSession and :VimspectorLoadSession to save and restore
breakpoints
  • call vimspector#ListBreakpoints() - toggle breakpoints window
  • call vimspector#BreakpointsAsQuickFix() - return the current set of
breakpoints in vim quickfix format
  • call vimspector#AddDataBreakpoint() - add a data breakpoint
Examples:
  • call vimspector#ToggleBreakpoint() - toggle breakpoint on current line
  • call vimspector#SetLineBreakpoint( 'some_file.py', 10 ) - set a breakpoint
on some_filepy:10
  • call vimspector#AddFunctionBreakpoint( 'main' ) - add a function breakpoint
on the main function
  • call vimspector#ToggleBreakpoint( { 'condition': 'i > 5' } ) - add a
breakpoint on the current line that triggers only when i > 5 is true
  • call vimspector#SetLineBreakpoint( 'some_file.py', 10, { 'condition': 'i > 5' } ) - add a
breakpoint at some_file.py:10 that triggers only when i > 5 is true
  • call vimspector#ClearLineBreakpoint( 'some_file.py', 10 ) - delete the
breakpoint at some_file.py:10
  • call vimspector#ClearBreakpoints() - clear all breakpoints
  • VimspectorMkSession - create .vimspector.session
  • VimspectorLoadSession - read .vimspector.session
  • VimspectorMkSession mysessionfile - create mysessionfile
  • VimspectorLoadSession mysessionfile - read mysessionfile

Instruction breakpoints

NOTE: Experimental feature, which may change significantly in future based on user feedback.

Instruction breakpoints can be added from the disassembly window in the same way that you add line breakpoints in the code window. The same mappings and functions work for adding and toggling them. Where supported by the debug adapter, you can even create logpoints and conditional breakpoints this way.

Currently, instruction breakpoints are internally modelled as line breakpoints against the buffer containing the disassembly, but that may change in future, so please don't rely on this.

Instruction breakpoints are also visible from and can be deleted/disabled from the breakpoints window.

Currently, instruction breakpoints are automatically cleared when the debug session ends. The reason for this is that the addresses can't be guaranteed to be valid for any other debug session. However, this may also change in future.

Clear breakpoints

Use vimspector#ClearBreakpoints() to clear all breakpoints including the memory of exception breakpoint choices.

Run to Cursor

Use vimspector#RunToCursor or <leader><F8>: this creates a temporary breakpoint on the current line, then continues execution, clearing the breakpoint when it is hit.

Go to current line

Use vimspector#GoToCurrentLine() or some mapping to <Plug>VimspectorGoToCurrentLine to jump the current execution to the line your cursor is currently on.

Where supported this can be useful to re-run sections of code or skip over them entirely.

If there are multiple possible "targets" on the current line, you're prompted to pick one.

Save and restore

Vimspector can save and restore breakpoints (and some other stuff) to a session file. The following commands exist for that:

  • VimspectorMkSession [file/dir name] - save the current set of line breakpoints,
logpoints, conditional breakpoints, function breakpoints and exception breakpoint filters to the supplied session file or the default file in the supplied directory.
  • VimspectorLoadSession [file/dir name] - read breakpoints from the session
file supplied or the default file in the supplied directory and replace any currently set breakpoints. Prior to loading, all current breakpoints are cleared (as if vimspector#ClearLineBreakpoints() was called).

In both cases, the file/dir name argument is optional. By default, the file is named .vimspector.session, but this can be changed globally by setting g:vimspectorsessionfile_name to something else, or by manually specifying a path when calling the command. If you supply a directory, the default or configured session file name is read from or written to that directory. Otherwise, the file is read based on the currently open buffer or written to the current working directory.

Advanced users may wish to automate the process of loading and saving, for example by adding VimEnter and VimLeave autocommands. It's recommended in that case to use silent! to avoid annoying errors if the file can't be read or written.

The simplest form of automation is to load the vimspector session whenever you start vim with a session file. This is as simple as doing this:

$ echo silent VimspectorLoadSession > Sessionx.vim

See :help mksession for details of the *x.vim file. You can also do something like this using SessionLoadPost:

autocmd SessionLoadPost * silent! VimspectorLoadSession

Stepping

  • Step in/out, finish, continue, pause etc. using the WinBar, or mappings.
  • Stepping is contextual. By default, stepping is statement granularity. But
if your cursor is in the disassembly window, then stepping defaults to instruction granularity.
  • If you really want to, the API is vimspector#StepInto() etc.. There are also
vimspector#StepSOver() and vimspector#StepIOver() etc. variants for statement and instruction granularity respectively.

code window

Variables and scopes

  • Current scope shows values of locals.
  • Use <CR>, or double-click with left mouse to expand/collapse (+, -).
  • Set the value of the variable with <C-CR> (control + <CR>) or
<leader><CR> (if modifyOtherKeys doesn't work for you)
  • View the type of the variable via mouse hover.
  • When changing the stack frame the locals window updates.
  • While paused, hover to see values.
  • Create a data breakpoint with <F9>.
locals window

Scopes and variables are represented by the buffer vimspector.Variables.

If you prefer a more verbose display for variables and watches, then you can let g:vimspectorvariablesdisplay_mode = 'full'. By default only the name and value are displayed, with other data available from hovering the mouse or triggering <Plug>VimspectorBalloonEval on the line containing the value in the variables (or watches) window.

Variable or selection hover evaluation

All rules for Variables and scopes apply plus the following:

  • With mouse enabled, hover over a variable and get the value it evaluates to.
This applies to the variables and watches windows too, and allows you to view the type of the value.
  • Use your mouse to perform a visual selection of an expression (e.g. a + b)
and get its result.
  • Make a normal mode (nmap) and visual mode (xmap) mapping to
<Plug>VimspectorBalloonEval to manually trigger the popup. * Set the value of the variable with <C-CR> (control + <CR>) or <leader><CR> (if modifyOtherKeys doesn't work for you) * Use regular navigation keys (j, k) to choose the current selection; <Esc> (or leave the tooltip window) to close the tooltip.

variable eval hover

You can disable automatic hovering popup by settings g:vimspectorenableauto_hover=0 before starting the debug session. You can then map something to <Plug>VimspectorBalloonEval and trigger it manually.

Watches

The watch window is used to inspect variables and expressions. Expressions are evaluated in the selected stack frame which is "focussed"

The watches window is a prompt buffer, where that's available. Enter insert mode to add a new watch expression.

  • Add watches to the variables window by entering insert mode and
typing the expression. Commit with <CR>.
  • Alternatively, use :VimspectorWatch <expression>. Tab-completion for
expression is available in some debug adapters.
  • View the type of the variable via mouse hover.
  • Expand result with <CR>, or double-click with left mouse.
  • Set the value of the variable with <C-CR> (control + <CR>) or
<leader><CR> (if modifyOtherKeys doesn't work for you)
  • Delete with <DEL>.
  • Create a data breakpoint with <F9>.
watch window

The watches are represented by the buffer vimspector.Watches.

If you prefer a more verbose display for variables and watches, then you can let g:vimspectorvariablesdisplay_mode = 'full'. By default only the name and value are displayed, with other data available from hovering the mouse or triggering <Plug>VimspectorBalloonEval on the line containing the value in the variables (or watches) window.

You can disable automatic hovering popup by settings g:vimspectorenableauto_hover=0 before starting the debug session. You can then map something to <Plug>VimspectorBalloonEval and trigger it manually.

Watch autocompletion

The watch prompt buffer has its omnifunc set to a function that will calculate completion for the current expression. This is trivially used with <Ctrl-x><Ctrl-o> (see :help ins-completion), or integrated with your favourite completion system. The filetype in the buffer is set to VimspectorPrompt.

For YouCompleteMe, the following config works well:

let g:ycmsemantictriggers =  {
  \   'VimspectorPrompt': [ '.', '->', ':', '<' ]
}

Disassembly

  • Display disassembly around current PC
  • Step over/into/out by instruction (contextually, or using the WinBar)
  • :VimspectorDisassemble, vimspector#ShowDisassembly() or
<Plug>VimspectorDisassemble

Demo

Some debug adapters (few!) support disassembly. The way this works in DAP is a little weird, but in practice vimspector will ask to disassemble a number of in


README truncated. View on GitHub

ยฉ 2026 GitRepoTrend ยท puremourning/vimspector ยท Updated daily from GitHub