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.
Since my last post in July I've made the jump to helix as my primary editor for code. They still haven't addressed most of the things that bothered me last year but I've been writing more rust code and the rust-analyzer support in helix is just better than neovim.
Unfortunately it took hours to get this working. As it turned out:
helix --health
lies. It told me I was all good to go but rust-analyzer wasn't actually installed. I still needed to run:
rustup component add rust-analyzer
On my main system I also needed to remove an old version of rust-analyzer that was in my ~/.local/bin/ (found with 'which rust-analyzer' and 'rustup which rust-analyzer').
Before I discovered the missing rust-analyzer I went through every configuration option to make sure I didn't miss an enable switch and I revisited my theme to make sure it was working but the text wasn't visible. There was also conflicting information on whether I needed to add stuff to the language.toml file. The changes I'd made were for older versions of helix and were no longer necessary. You can see my final helix configuration in my dotfiles repo here.)
Now I'm attempting to train my fingers to use this new editor. My config.toml file has the list of aliases I'm trying to remember:
# na's muscle memory
# https://cheatography.com/hiddenmonkey/cheat-sheets/helix/
# https://github.com/helix-editor/helix/wiki/Migrating-from-Vim
# x selects the current line - delete it with xd
# d deletes the current character
# :e # use :o
# reload from disk with :reload
# * # be*n (or preferably Alt+o*n)
# \c # use Ctrl+c
# m is now a jumplist # use Ctrl+s to save and Ctrl+o to return, space+j to view
# :%s/word/replacement/g<ret> # use %sword<ret>creplacement<esc>
# % # use mm instead!
# 0 = "goto_line_start" # use gh instead!
# "$" = "goto_line_end" # use gl instead!
# G = "goto_file_end" # use ge instead!
# ,1 = goto_last_accessed_file # use ga or (Space Space) instead
# can't toggle a render so use two buttons
# can't toggle gutter contents
# can't toggle soft-wrap see languages.toml
# V (select whole line) # use xv to get started
# :reg # not possible https://www.reddit.com/r/HelixEditor/comments/130gbzy/is_it_possible_to_cycle_through_the_yank_history/?rdt=40070
# Y # use :clipboard-yank (or Space y)
# Ctrl+r (redo) # use U
# autocomplete # Ctrl+x
# q and ` # Q and q
# new stuff (multicursor)
# C - duplicate cursor down
# s - select - duplicate cursor horizontally
# ,, - cancel multiple cursors
# & - align vertical cursors
# Alt-s - select all endlines in a block
# S - split on a regex pattern
# Alt+; - put cursor on other end of selection
# ; - drop selection but keep cursors
#
# R - replace a selected word with the contents of the paste buffer
# ms( - add paranthesis around selection
# md( - remove paranthesis from within
I've found the main pain points are 'x', 'd', and 's'.
What this means is that 50+ times a day I type 'dd' to remove a line and discover it only removed two characters. Or I type 'x' to remove a character and have to stop because now the entire line is highlighted. Or I select some text and hit 's' to change it and enter a restricted selection mode.
Just now, typing that last paragraph, I literally made these mistakes six times. Extrapolate that to all the typing I did today and you can imagine the frustration.
Still it seems like the editor has some momentum. They recently added a pipe command and I've been seeing helix users abusing it to do unspeakable things like adding copilot support. And the vifm guys have instructions on how to integrate the file picker into a tmux-helix install using some frightening tmux configuration hacks.
I still use vim for my git commits (and apparently for spellcheck) and I can already tell my muscle memory is soon going to have the opposite problem and I'll start making helix mistakes in neovim. The perils of switching text editors are fraught.
I recently added a new django app to the site and took the opportunity to finally sync this code with the code that was actually running on my SBC webserver. The new code seemed to be solid but I'd made some radical changes and I wasn't confident I didn't break things. Of course this just meant the longer I delayed the more the two code bases diverged.
Of course there was an issue. It came up when I wanted to add an image to a blog entry and it crashed because I'd neglected to update the blog model to work with the new thumbnail API.
This started a frantic scramble to fix it within my development framework, a rootless podman container, but I learned that had issues too. Group permissions weren't getting propagated into the container so I didn't have write access to the database.
After some investigation I found the issue and fixed it without any way of testing it before pushing it to 'production' (by which I mean the SBC that runs this site - which no one reads). It crashed and so I was forced to temporarily turn on debug to see why.
Python was complaining that my code was trying to index a tuple with a string. This was baffling because my code wasn't working with tuples. Eventually I tracked the fault down to this block of code:
mediadict = {'type': 'image',
'thumbfilepath': Path(thumbfilepath),
'filepath': Path(newpath),
'cstring': 'center-block',
'constraint': 'width max',
'filesize': image_filesize,
'filelength': 'unknown'},
if self.resize:
mediadict['constraint'] = str(self.resize)
im = thumbnail.make_thumbnail(mediadict)
Spot the issue? Here it is in an interpreter:
[ins] In [1]: t = {'a':1, 'b':2}
[ins] In [2]: t
Out[2]: {'a': 1, 'b': 2}
[ins] In [3]: t = {'a':1, 'b':2},
[ins] In [4]: t
Out[4]: ({'a': 1, 'b': 2},)
I accidentally left a trailing comma on my dictionary instantiation so python automatically enclosed it in a tuple!
This is both surprising and horrifying. It should raise an error or, if you want to be syntactically permissive, ignore the comma altogether. I cannot imagine anyone expecting a trailing comma to automatically convert your object into a different (and unmentioned) data structure.
In fact this bug is so alarming I'm beginning to think it may be time to start edging away from the language altogether. Python is convenient for making something fast but it may be too friendly.
You can see the changes I made here.
Are your friends competitive? Athletic? Do you like shouting? Heart racing excitement? Do you and your bros watch football and UFC in splitscreen while drinking brewskies? Well I have a game for you!
In Lots of horses you and your buddies will enter the intense and immersive world of horselandia in a competition of glorious consensus!
Thrill! - at Gulliver's preference to keep napping in the barn instead of exploring a new pasture.
Quiver! - at Shilo's reluctance to hang with the rest of the herd.
Delight! - in agreeing with your buddy Spike over which horse has the 'dustiest hooves'.
Tingle! - with excitement as you determine which horse is the most courageous.
Deep Enchantment! - is what you and your fellow bros will feel as you play...
Click on this link to play lots of horses for free today!
lubins aren’t quite werewolves. “Sorrowful, dreamy and stupid spirits,” she writes, “they spend their lives chatting in an unknown language along the walls of cemeteries. In some places they are accused of breaking into the field of rest and gnawing on bones. In the latter case, they belong to the race of lycanthropes and werewolves, and must be called lupins. But in the case of lubins, manners soften with the name. They do no harm and escape at the slightest sound.
George Sand (source)