Debugging rust in helix

/media/images/helixforward-helix-piercing.jpg

An image search for helix produced a bunch of pictures of ears

This is cool and the existing documentation isn't super clear. I wanted to debug some unit tests in a script I was writing. Rust provides a gdb debugger with the ability to pretty print rust objects called rust-dbg. Run it from the command line like normal with:

rust-gdb target/debug/rename_files

Unfortunately unit tests like this:

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn crop_start() {
        let filename = "1234567890";
        let newfilename = crop_filename(filename, 1, 0, false).expect("failed to crop");
        assert_eq!("234567890".to_string(), newfilename);
    }

    #[test]
    fn crop_end() {

aren't normally compiled and linked into your binary but you can get a path to this binary with 'cargo test':

~/source/rust/rename_files  cargo test                                                                                   3m 51s
    Finished test [unoptimized + debuginfo] target(s) in 0.02s
     Running unittests src/main.rs (target/debug/deps/rename_files-26e38ab9001eb8c3)

running 26 tests
test capitalize::tests::single_word ... ok
test capitalize::tests::space_separated_words ... ok
test capitalize::tests::three_words_one_short ... ok
test capitalize::tests::three_words ... ok
test capitalize::tests::three_words_start_short ... ok
test capitalize::tests::two_long_words ... ok
test crop::tests::crop_end_out_of_range ... FAILED

Run rust-gdb on this path to debug your unit tests.

rust-gdb target/debug/deps/rename_files-26e38ab9001eb8c3

Unfortunately this only gives you raw gdb connection and I couldn't get -tui to work but you can do your debugging directly in the helix editor. To get started configure your system.

In my case I ran:

      sudo pacman -S lldb
      cd /usr/local/etc
sudo helix lldb_vscode_rustc_primer.py

and pasted this into that file:

import subprocess
import pathlib
import lldb

# Determine the sysroot for the active Rust interpreter
rustlib_etc = pathlib.Path(subprocess.getoutput('rustc --print sysroot')) / 'lib' / 'rustlib' / 'etc'
if not rustlib_etc.exists():
    raise RuntimeError('Unable to determine rustc sysroot')

# Load lldb_lookup.py and execute lldb_commands with the correct path
lldb.debugger.HandleCommand(f"""command script import "{rustlib_etc / 'lldb_lookup.py'}" """)
lldb.debugger.HandleCommand(f"""command source -s 0 "{rustlib_etc / 'lldb_commands'}" """)

Finally I updated my languages.toml file with:

[[language]]
name = "rust"

[language.debugger]
name = "lldb-vscode"
transport = "stdio"
command = "lldb-vscode"

[[language.debugger.templates]]
name = "binary"
request = "launch"
completion = [ { name = "binary", completion = "filename" } ]
args = { program = "{0}", initCommands = [ "command script import /usr/local/etc/lldb_vscode_rustc_primer.py" ] }

I reloaded my config with ':config-reload' and then in helix I used '<Space> g' to bring up the debugger menu and 'b' to set a breakpoint on a particular line of code (in my unit test).

Then 'l <Enter>' to tell it to run a binary in the debugger and I gave it the path to the compiled binary with linked in unit tests:

And that's it. It automatically ran the script, stopped at my breakpoint and let me inspect values. It's still primitive but having this all already built into the editor without any plugins or super weird configuration is nice.