Quick notes on editors


I had a conversation with Chris Smoak about programming editor design.

Here are the loose notes I wrote before the meeting:

Takeaways

Chris talked about something he called stack-based editors, which basically boil down to the following principles:

You have a unified view of different files in your codebase, kinda arranged into a history (a stack of sorts). You can move between files just by moving up and down as you would if they were the same file - there's no added command needed for switching between windows.

Each file you are working is a collection of lines, there would also be key commands to zoom in and out of scopes. The editor could help by pulling up definitions to different types and so on that you need to reference. This set of stacks forms something along the lines of a history: You can jump to a definition, but there's also a back arrow so you can easily get back to the context of the file you're working on.

Additionally, it should be possible to sync references between windows. For example, if you have a file open on your monitor, you should be able to split it between both halves, so scrolling one scrolls the other.

Later on, we also moved on into discussing the ways modern programs represent source code. Right now, they're basically textual representations, with the code editor building a representation of the code behind the scenes (via a language server or the like.) Languages should be represented as ASTs first and foremost, with transformations applied to the program modifying the AST, rather than the text. In a sense, the text of the program is just a view of the AST.

Because the editor has this rich representation of ASTs as well, it's possible to define transformations that are non-trivial for text-based systems. This includes things like wrapping a function call with another (without having to track down where the closing paren should go*), and so on.

* In a sense, this is why the OOP object.method(args) style is so popular. Instead of having to wrap functions from both sides (and read them from inside out), you have to make a single insertion. a(b(c(d))) becomes d.c().b().a().

We also discussed some editor technologies, like Light Table, Pharo, and that one editor that allows for the editing of code with an x-box controller. The advantage of all these editors (even ones like scratch) - is that they allow for rich views and modifications to a programs source code. Chris also brought up this one editor that basically allowed programmers to edit code by writing macros that modified what they had writting.

So in the context of a historical, stack-based editing system, this rich AST representation would allow the editor to provide rich semantics for these various views into the files - you could easily expand the slice of a view (i.e. the number of lines in one of the files you're working on) by entire scopes at a time, or collapse items out (and replace them with their documentation, for instance).

Here's how I imagine stack based editing:

-- bar.rs // [B]
7  // add two numbers
8  fn add(a: usize, b: usize) -> usize {
9      return a + b;
10 }
--- foo.rs
456     let x = 7;
457     let something = foo(); // [A]
458     ... // [C]
--- ...
  • A jumping to the definition of foo opens the associated lines in a new stack frame directly above. Moving into bar.rs is as simple as pushing up in your keyboard.
  • B file names and such are inline for context.
  • C slices of files are shown. You can expand the scope of these views of files.

There'd also be a right navigation API, so you could move around in history.

That's the gist of it. It'd be something to approach in the future - you'd basically have to construct a rich view of the state of a codebase and its history, and apply transformations to that view rather than the textual representation itself.

The end.