GtkSourceView is getting a VIM emulator

One of the things we spent some time on early with Builder was creating built-in VIM emulation. Originally it was written in C, but then got converted to this nasty CSS for a couple of reasons. First, that keybindings in GTK 3 were largely done with CSS due to how we moved away from gtkrc in the 2.x to 3.x migration. And beyond that, CSS was the one way that’d let us share a lot of keybinding code between shortcut themes so we could support emacs, vim, sublime, etc.

One thing that didn’t work well was VIM’s “modes”. People often think of VIM as a single state (normal, insert, replace, visual, etc). In reality it’s a stack of them. Just look at the following state diagram if you’re going to actually to match things somewhat accurately. Doing this in a manner that would allow sharing between shortcut themes in Builder was simply beyond the amount of time we had to spend on it given all the other features that needed to land.

As we start to port Builder to GTK 4 this is one area that worried me the most. GTK 4 has improved so much in this regard, but we also have this giant legacy ball of tar. So recently I started looking at a new approach to providing VIM emulation in a way that would let us improve the quality and extend it’s reach.

The experiment I’ve come up with so far is to build upon GtkIMContext. This allows us to filter key presses and releases from the widget and do so in a way that allows layered input-methods (ibus, emoji, unicode, etc) to continue working.

One question that will always pop up is “why not use $some_form_of_vim” and bridge that. The answer is pretty simple, it’s a huge dependency to take on as a library. It also requires synchronizing text and across boundaries which may not even be capable in places where GtkSourceView is used. Beyond that there are a large number of impedance mismatches in how things work from a generic standpoint.

But fear not, we can actually do pretty good for the most commonly used things. We can probably even implement registers (some of it is there already) and marks for people that want it. Some day I imagine we’ll land code folding upstream, so even supporting that might be possible.

My goal is to get this into 5.4 so that we have it well tested by time Builder lands a GTK 4 port. The exposed API is very small and just the single object GtkSourceVimIMContext. By keeping the implementation private we allow ourselves quite a bit of flexibility to adapt how we implement things if and when that is necessary.

I haven’t decided yet if we would want to have a property like GtkSourceView:enable-vim to simply enable it. I’m hesitant to do that because supporting it correctly can still be somewhat involved. You need presentation of a command bar and active command state for example. To do that requires application coordination anyway, so perhaps requiring the application to add a GtkEventControllerKey with the GtkSourceVimIMContext is the better option.

If you’d like to help on any of this, feel free to send me MRs. Everyone has slightly different usage of VIM and there are lots of missing spots you can fill in.

git clone
cd gtksourceview
git checkout wip/chergert/vim
meson build
cd build
hack and repeat

As always, I usually leave screenshots and videos for people here if you can handle my other mindless dribble.