Status Update: October 2024

Published on to joshleeb's blog

G’day!

Exploration towards building Ica (a GUI code editor) has continued in October. Having figured out a rendering strategy at the end of last month, the next step has been to design a framework/engine that sits atop the rendering layer and deals in terms of element trees, event listeners, and effect observers.

At this level we don’t have to think about how primitives are drawn to the screen, nor how to create a window and receive events from user interactions. Our high level responsibility is to define the lifecycle for abstract elements and figure out how state is managed. What this boils down to is an overwhelming amount of pieces that have to fit nicely together.

No doubt writing a GUI system is difficult and complex. Writing a GUI system in Rust also adds another degree of complexity as these systems tend to build upon mutable, bi-directional trees which are non-trivial to implement with the restrictions of Rust’s borrow checker.

Thankfully there are many GUI frameworks being developed in the Rust ecosystem. Raph Levien has catalogued many of them with articles that break down their architectures and tradeoffs, such as Advice For the Next Dozen Rust GUIs. As I am going down the path of a native (i.e: non-electron), retained/hybrid mode GUI that isn’t based on the Elm architecture, the GUIs I’ve been looking at this month have been Xilem, Flutter, and GPUI.

GPUI has been of particular interest as it’s the framework being developed by Zed Industries for their Zed GUI code editor that is already released and being used in the wild.

One of the structures employed by GPUI as a solution for mutable trees is their EntityMap where references between nodes are IDs rather than smart pointers. This is similar to one of the more common approaches for trees in Rust, where all nodes are stored in a Vec and referenced through their position. What’s new to me in the EntityMap is this lease-pattern where ownership of a value is acquired by removing it from the tree. The value is then mutated and added back into their previous position. Of course this assumes single-threaded execution but within the event loop of a GUI framework that is perfectly fine.

The EntityMap, and the effect system built on top of it, are topics I might be writing about more (as my backlog of posts continues to grow). In the mean time the Zed folks discuss this approach to data flow in Ownership and Data Flow in GPUI.

Inspired by GPUI’s EntityMap, I’ve added a conceptual implementation of my own here that replicates both the EntityMap and the effect system. As with many of my concept pieces, the API and the implementation needs a lot of cleaning up but the idea is there.

Coming back to the overwhelming nature of building a GUI, part of this overwhelm is that working out the details for most subsystems depends on the details of most other subsystems. For example knowing how you’re going to dispatch keyboard events requires (for one) being able to register listeners, which depends on the effect system, which depends on how entities are stored and referenced. This was less of an issue when I was exploring rendering which is fairly isolated in this dependency graph.

So, I’ve decided to shift to a new approach in the progression towards building Ica which is to build a GUI replica of antirez’s Kilo terminal code editor. Kilo is an editor with only a few core editing features and keeping this surface area small will allow me to focus on the GUI systems rather than the editing features.

I’m going to call this project Mega as it will take much more than 1k LoC, but should be less than 1M. It’s main purpose is as a precursor to Ica that will allow me to make more mistakes with building my own GUI system and build up an intuition for avoiding them with Ica.

As a secondary goal, and depending on the complexity at the end, I hope to write a tutorial series showing how to build your own hardware-accelerated GUI code editor from scratch without Electron, without Skia, and without an established framework. I’m thinking this will be a similar style of tutorial to Build Your Own Text Editor for Kilo and Build Your Own Text Editor in Rust for Hecto.

The progression of building Mega has, so far, been very productive. At the moment I have a conceptual GUI system that glues together

Figure 1. Screengrab of the prototype of the GUI engine being developed for the Mega editor highlighting keyboard and mouse events with focused element tracking.

This concept has many of the main components required to build an editor though there are still many problems that need to be solved at the level of the GUI system such as

I’ll be flying to Sydney for a couple of weeks so all of this can wait until I’m back. I’ll start by mapping out Kilo’s features and then make a start on building Mega proper. Until then I plan to catch up on reading a bunch of articles I have saved in my Pinto reading list.

That’s all for now, see you next month!