Scheming on a text editor

I’ve been a user of Helix for the past year or so. It’s a great, handy, and mighty-cool-to-use text editor.

For those of you unfamiliar, Helix is a modal text editor like Vim, but straying from the Vim editing model of specifying an action to perform, then a motion to perform the action with (or simply, action-motion)—such as dw to delete a word. Helix opts to reverse that model to selection-action—meaning that first, you make a selection, and then perform an action on that selection—for example, w to select until the end of the word under the cursor, and then d to delete the selection.

This might seem like the same thing but different for the sake of being different, until you understand how selections compose. A selection does not necessarily have to be a single motion like Vim. It can be selected interactively via SELECT mode v, or you can create multiple selections by duplicating your cursor in various ways.

It is a more visual approach than Vim, and I love it for that. Having immediate visual feedback on what I’m acting upon is great, and while some motions feel a bit more clunky than Vim, I’m willing to give up that power for ease of learning and interactivity.


That being said, after having used Helix for a whole year, I do have some gripes with it. Some of these aren’t gripes that are easily fixable by contributing to the editor, and some are personal experiments I want to take just to see how they work.

Which is precisely why I’ve been thinking about creating my own text editor.

lite as a base

Now, I know how much setup work there is to creating a whole text editor from scratch,
and I mean boring stuff like displaying text on the screen,
which is why I need a solid base to work with.

I’ve heard that Emacs is pretty great, and you can morph it into literally whatever you want, but I think I’d like something a bit more lightweight, with less historical baggage, and a bit more GUI-oriented.

Enter lite, a text editor I discovered by accident some years ago, whose brilliant simplicity has stuck with me since.

lite is a text editor written in Lua, with a small C and SDL2-based core underneath. This might seem pretty unremarkable, but the technical choices in this editor are really elegant.

The magic lies in how Lua is an incredibly tight, well-designed language, featuring dynamic typing that’s just flexible enough to enable a lot of pathways for extension out of the box, without needing any additional code.

lite has a plugin system, which literally just requires your Lua files in the plugins folder. There are no special hooks or anything that you have to plug into. Rather, your plugins can require the core editor’s modules, and overwrite any core functionality to do whatever else you may want to do.

A great, visual example is the motiontrail plugin. It takes lite’s document view, in particular its draw function, and adds a bit of additional logic to the end, to draw a trail between the cursor’s last position and its current position.

-- snip --

local draw = DocView.draw

function DocView:draw(...)
	draw(self, ...) -- <---
	if self ~= core.active_view then return end

	local x, y, w, h = get_caret_rect(self)

	if last_view == self and (x ~= last_x or y ~= last_y) then
		local lx = x
		for i = 0, 1, 1 / config.motiontrail_steps do
			local ix = lerp(x, last_x, i)
			local iy = lerp(y, last_y, i)
			local iw = math.max(w, math.ceil(math.abs(ix - lx)))
			renderer.draw_rect(ix, iy, iw, h, style.caret)
			lx = ix
		end
		core.redraw = true
	end

	last_view, last_x, last_y = self, x, y
end

You don’t really have to read too much into the source code (especially because it’s abridged). Just note the basic technique of saving an existing function, overwriting it, and then calling back into the original.

Anyways…

lite’s editing model

Going back from that tangent—lite is great and all, but internally sports an editing model that wouldn’t really work well for something Helix-like. There is only one selection per document (not even document view!), and Helix’s editing paradigm needs multiple selections to work well.

I actually think this model of binding a single selection to the entire document is the one major design flaw of lite.

It’s annoying during normal usage when using splits—a feature I use constantly—because each split has to share one cursor. Therefore, you edit something in one split, try to focus another split, and the cursor jumps back to where it used to be. This was so annoying I think I had a plugin that fixed it by saving and restoring the cursor position when switching between views.

And now it’s biting me again, with it being a single selection, document-bound—whereas I want multiple selections, view-bound.

This basically means I have to rewrite all the editing commands from scratch, which is a bit annoying, but feels like it’ll be a fun exercise. Feels like I’d need to do that anyways, to recreate a lot of Helix’s behaviours regarding cursor movement, selection, etc.

UI

The editing model is fun and all, but the main reason why I want to create my own text editor is to improve on Helix’s UI.

Helix is a terminal-based text editor, with all the advantages and limitations that come with that. It’s great that I can use Helix while SSHing into my server, but Helix’s terminal UI limits what it can do severely.

In the following sections, I’ll outline some of the ideas I’ve had on what a full-blown graphical UI would improve.

Proportional fonts

Controversial opinion, but I think proportional fonts are great for code. Not most proportional fonts, mind you, but those that are made for it, such as Recursive or Input, are awesome.

This opinion stems from experiments with my own website’s design, where I switched out the font to a proportional one, and saw a significant improvement in how many characters could fit horizontally on a single line. I initially did this to save horizontal space on mobile screens, but ended up liking it so much that I enabled it on the desktop layout, too.

Since then, I’ve wanted to try programming with a proportional font, but haven’t been able to, due to limitations of the terminal. It is simply impossible to display a proportional font on a grid-based display.

A thing some people do with code comments is aligning them vertically next to code. I personally quite like how that looks with data structure definitions, which is why I have it as a feature on my website.

enum class Blend_Mode
{
	no_blend, // blending is disabled
	alpha, // mix channels together
	addition, // add channels to each other
};

Try selecting the text to see how a little bit of display: grid magic aligns the comments vertically, by adding artificial spacing in the text layout.

Features like this make me interested in what else would be possible if I gave up using monospaced fonts.

It’s just a shame I’ll have to stop using Comic Code.

Book display

As I already mentioned, I really like working with splits. They allow me look at several parts of the codebase at the same time, which is incredibly nice when you’re trying to navigate around something confusing, like someone else’s code, or a difficult bug.

At the same time, I really like seeing as many lines of code as possible. Some time ago, I tried rotating one of my displays 90°, to a vertical orientation, and ended up really liking the result. I could see more lines of code than ever!

But unfortunately, that doesn’t work as well with splits. There’s something about a horizontal side-by-side layout being more spatially local to my eyes that makes tracking where I’m reading more difficult in a vertical side-by-side configuration.

But I like the extra vertical space. Is there anything I could do to mend those two together?

Enter: the book layout.

Let’s go back to a horizontal screen orientation. Since it’s possible to fit more characters on the screen with a proportional font, it’s possible to also have more vertical splits open. So what if we displayed code in two or three columns, but those three columns were logically one view? Such that scrolling one column would also scroll the other.

You could then also lock one of those columns in place, such that it stops scrolling, and lets you see that part of code persistently, until you unlock it, and it goes back to showing the current document.

Now, this seems like a pretty crazy idea, and I have no idea how well it would work. It would be possible in a terminal editor, but I think it wouldn’t work as well without proportional fonts, and possibly also word wrapping.

Whatever comes out of it, I’m interested to try implementing it.

IME

And now for a very real frustration I have with Helix, that it probably can’t realistically fix: support for Japanese input.

Using Helix with a Japanese input method is borderline miserable. And that’s a pretty big dealbreaker to me, because if I’m learning the language, I want to be able to type it in my text editor!

INSERT mode, as expected, works pretty well. But most text editing are done in NORMAL mode—in which the input method cannot switch off to give way to keyboard shortcuts such as i or d.

As far as I know, this is a fundamental limitation of terminals. They only ever allow for inputting text, not key sequences. And that sucks, because I always end up accidentally typing in when I mean i, and then fumble my way back to an English input method, with fcitx5 often glitching the heck out and not letting me switch (perhaps a ghostty bug?)

I’d rather use a GUI text editor that can signal to the WM whenever it starts recognising text input, and whenever it starts recognising keyboard shortcuts.

Conclusion

I’ve already started working on those experiments, though I’m progressing rather slowly due to a lack of time. Expect a blog post whenever I have any major updates to share, or edits to this post whenever I have more ideas to cover.

Maybe I’ll add some screenshots or sketches in the future.


I understand that this post, being mostly just a wishlist of features, may not have been a very exciting read.

Part of why I haven’t been writing as much as of late has been Christmas / New Year, as well as some work on moving to Japan. It might take me some more time to stabilise still, so don’t expect too much of anything exciting coming from me in the coming months.

I’ll still try to write something every month though! Can’t let those skills get rusty.

For now though… I will see you up ahead.