- Neovim >= 0.5.0
- For regular Vim, you will likely need to use the vimspector plugin. This document does not support configuring vimspector.
- Neovim plugin https://github.com/mfussenegger/nvim-dap (tested at commit fafd7f9a)
- Installation instructions at the README.
- Dart SDK >= 2.15.0-121.0.dev (see commit)
- Flutter SDK with flutter/flutter#91802 (not yet merged)
Consider the program:
// Filename `fib.dart`
void main() {
final int n = fib(33);
print(n);
}
int fib(int n) {
// We will set a breakpoint here
if (n == 0 || n == 1) {
return n;
}
return fib(n - 1) + fib(n - 2);
}
Update your vimrc to configure the adapter plugin to know how to launch Dart's DAP server:
# Since the mfussenegger/nvim-dap plugin is written in Lua, you must embed Lua in your vimrc
lua << EOF
local dap = require('dap')
dap.adapters.dart = {
type = "executable",
command = "dart",
-- This command was introduced upstream in https://github.com/dart-lang/sdk/commit/b68ccc9a
args = {"debug_adapter"}
}
dap.configurations.dart = {
{
type = "dart",
request = "launch",
name = "Launch Dart Program",
-- The nvim-dap plugin populates this variable with the filename of the current buffer
program = "${file}",
-- The nvim-dap plugin populates this variable with the editor's current working directory
cwd = "${workspaceFolder}",
args = {"--help"}, -- Note for Dart apps this is args, for Flutter apps toolArgs
}
}
EOF
After updating your .vimrc
, (re)start nvim
, opening our source file fib.dart
..
If you would like to monitor verbose logs, enter command-line mode (:
) and enter lua require('dap').set_log_level('TRACE')
. Find your editor's cache dir with :echo stdpath('cache')
(for me this is
$HOME/.config/nvim
). nvim-dap
should have created a log file under this directory; tail it in a separate terminal
window with tail -f <your editor's cache dir>/dap.log
.
Navigate to the comment where we indicated we would be setting a breakpoint, enter command-line mode (:
), and enter
lua require('dap').set_breakpoint()
(.toggle_breakpoint()
would also work). The buffer should now indicate a letter
B
to indicate the breakpoint has been set. Now launch the program with :lua require('dap').continue()
(this will parse
the config that we set in our .vimrc
). The debugger should launch the program and run until it hits the breakpoint (if not, check the logging to see if there was a configuration problem).
With the program paused, we can now launch a repl to inspect the state of the VM with :lua require('dap').repl.open()
.
Navigate to the new vim window that was opened and enter insert mode to attach STDIN to the subprocess. You should see the
prompt: dap>
. Here is a sample repl session:
Connecting to VM Service at ws://127.0.0.1:60321/bUcCdeiBh4w=/ws
dap> n
33
We can verify that value of the argument n
is 33. Without closing the repl window, return to command-line mode and enter
:lua require('dap').continue()
to resume the program. The program should continue executing until it recursively calls
itself with n - 1
. When execution pauses again, re-enter insert mode in the repl window and check the value of n
again
(it should be 32
).
See :help dap.txt
(https://github.com/mfussenegger/nvim-dap/blob/master/doc/dap.txt) for the full neovim/lua api for
interacting with the underlying Dart DAP server.
Create a new Flutter counter app with: flutter create flutter_counter; cd flutter_counter
. You will need to update your
.vimrc
again to teach nvim-dap how to launch the Flutter wrapper for the Dart DAP server:
# Since the mfussenegger/nvim-dap plugin is written in Lua, you must embed Lua in your vimrc
lua << EOF
local dap = require('dap')
dap.adapters.dart = {
type = "executable",
-- As of this writing, this functionality is open for review in https://github.com/flutter/flutter/pull/91802
command = "flutter",
args = {"debug_adapter"}
}
dap.configurations.dart = {
{
type = "dart",
request = "launch",
name = "Launch Flutter Program",
-- The nvim-dap plugin populates this variable with the filename of the current buffer
program = "${file}",
-- The nvim-dap plugin populates this variable with the editor's current working directory
cwd = "${workspaceFolder}",
-- This gets forwarded to the Flutter CLI tool, substitute `linux` for whatever device you wish to launch
toolArgs = {"-d", "linux"}
}
}
EOF
To be safe, restart neovim (I experienced problems re-sourcing my vimrc that a restart solved ¯\_(ツ)_/¯
).
As before, you can monitor verbose logs by entering :lua require('dap').set_log_level('TRACE')
and tail -f <your editor's cache dir>/dap.log
.
Open lib/main.dart
and set a breakpoint at in _MyHomePageState
's _incrementCounter()
method on a new (empty)
line after _counter++
: :lua require('dap').set_breakpoint()
. Start the app with :lua require('dap').continue()
.
The nvim-dap plugin will warn in the nvim buffer that it is taking too long--this is because launching the Flutter app
takes a long time. Refer to the logs in $CACHE_DIR/dap.log
to verify if anything went wrong. Either your app will start
(paused) or there should be an error message in the logs. To start the Flutter app, issue :lua require('dap').continue()
(you may receive a stdin prompt in your nvim buffer indicating the program is paused but not on an exception or breakpoint,
you can enter 3 here, or restart debug adapter).
Press the +
button to trigger the _incrementCounter()
handler and hit the breakpoint.
Open the repl with :lua require('dap').repl.open()
. Attach stdin by entering insert mode in the new nvim window. You
should see the dap>
prompt, meaning you are attached to the VM repl. Enter dap> _counter
to verify its value is 1
.
Write vimscript convenience functions that assist with:
- Selecting between
dart debug_adapter
andflutter debug_adapter
- Specifying
toolArgs