Skip to content(if available)orjump to list(if available)

The evolution of a structural code editor

narag

This is the way. Programs are not text, there's an impedance mismatch that shows at the seams.

There're good reasons it hasn't been done more: text is good for troubleshooting, "every program should do one thing well" and maybe preventing lock-in.

But with programming tools reaching maturity, we'll see more of this. Also there's an AI-related aspect: bots can understand structure just fine.

eadmund

> But with programming tools reaching maturity, we'll see more of this.

Programming languages reached maturity 31 years ago, with the approval of X3.226-1994, which specified a language which is at once textual and structured, and easily amenable to structured editing:

  (defun square (x)
    (* x x))
The first commit to paredit was 17 years ago: https://paredit.org/cgit/paredit/commit/?id=8be6d99412d0d4a3...

Structured editing was being performed on teletypes almost 60 years ago: https://en.wikipedia.org/wiki/Interlisp

The future is here; it’s just not evenly distributed.

taeric

There are good reasons it hasn't been done more, and I don't think it is just "text is good for troubleshooting."

At large, text wins because the job of a program text is to communicate the program to a user in a way that a computer can also be made to use. Things that help include that text can have multiple interpretations and meanings. This is why most variable names are nouns. You can literally "ascii art" parts of code to help convey some ideas.

The most important part of why "text" wins, though, is that it is all visible. Yes it implies some structure underneath that the computer is going to need. The text, though, is fully visible to users. People think they want the ability to "structurally edit," and you can sometimes make that work rather nicely. Most of the time, though, you are working with structures that are not complete. And worse, completing them will not be a process that goes in the same direction as the text. You will have to start a stack in how you are processing things to complete as you go.

I'm torn on the bots comment, as I just don't know. LLMs, arguably, are leaning in on the structure that has been embedded in our symbolic text over many years. The same structure has not necessarily been developed in computer programming texts?

(Also worth paying attention to how most of these goals were pursued with symbolic programming techniques back in the day. LISP, of course, but also term rewriting techniques that used to be rather magical.)

pjc50

> Most of the time, though, you are working with structures that are not complete. And worse, completing them will not be a process that goes in the same direction as the text. You will have to start a stack in how you are processing things to complete as you go.

This is very insightful. A program that is being edited passes through all sorts of incomplete states. Non-structured editors will let you do things like paste mismatched braces .. which sometimes you definitely deliberately want to do!

Edit: someone else makes this point at greater length https://news.ycombinator.com/item?id=42612969

ok_computer

In my opinion, that’s the magic of programming languages. I type a few high level words and characters, then there is a deep stack of interpreting the strings into machine code and returning data and side effects. It is stupid simple as the end user and immensely complex chain of machinery.

SQL is an extreme example of strings parsed to make complex computer behavior. Shell scripting too.

For enforcing complete object correctness and interfaces as they are explicitly designed then low code no code seems like it has a better proposition.

Anyway, maybe structured editors fit a space between dumb strings and pointing and clicking blocks and connectors. I’m all for correct tool for the job and end user. I think that minimizing end user tooling with some LSP go-to definitions and linting in a text editor is my preference. Similar to how FIFA used to be against high tech slow mo replay for soccer matches to make the sport egalitarian / accessible for the whole world I think that analogously programming should focus on the simplicity and portability of authored documents.

LeftHandPath

It's fascinating because I came to a similar conclusion while working with very old IBM mainframe code editors (AS400 / IBM i "Source Entry Utility")

It's nearly impossible (if you read the docs) to write something with bad syntax on those machines. Columns are semantic in most of the languages (COBOL, RPG, DDL). When you write a program, if you don't know what you're doing, you can press "F4" and it will show you what each column means and when/how to use it [0]. It's not exactly a structured code editor, but it shares some similar concepts (see the link; you often write code in a "prompt" at the bottom of the screen, and the line won't insert until it's complete, though you can write it by hand if you wish).

All of that said, IBM's old SEU is still vastly inferior to modern text editors and IDEs, mostly because of the limited view window and the lack of syntax highlighting / basic modern features [1].

I think that, especially for enterprise code/development, there are some benefits to structured editing that are worth exploring. Not having a linter shout at a partially-complete line because you paused for a second or two would be nice, as well.

[0]: https://youtu.be/iw_wk5elf3Q?si=m9zVeboTyw0T8_Wu&t=635 [1]: https://youtu.be/Q3hxwcYB1Oo?si=WE9-rFdYo72A5yXz&t=404

throw-the-towel

Hell, even text is not exactly text, it also has structure. I'd love to have refactoring tools for prose.

enriquto

> Programs are not text

Wow. It's amazing to see the beast laid out so clearly before me.

As someone who grew with the mantra "a program is a piece of text", my jaw dropped when I read this post and realized that it was not written in jest. Of course the mantra is still deeply entrenched in my mind, it's too late to remove it now; but I feel as if the world is crumbling around me. What other sacred beliefs will fall? Why doesn't everybody realize that the text file is one of the finest inventions of the third millennium?

Maybe it's just another period in the eternal cycle of fashion trends... programs as free-form text files were an exhilarating liberation from the crufty, fixed-form structures of older languages. Now, we are not only going back to write our code starting at column 4 (like in punched cards), but we still want to add even more structure to it! Maybe in forty years we will go back to free-form text and cherish it again.

Reading the sentence "programs are not text" was the first time I felt old in my life.

notpushkin

Programs weren’t free-form text at any time in history (esoteric languages aside). There is still structure, it’s just enforced by the compiler (and maybe linter).

prerok

TBH, I think you are reading too much into it.

For me, json files are also just text files. Or ini files. Or md files.

They do, however, prescribe some structure, or syntax, in them, to be parseable by the interpreter/compiler/whatever. I think this has always been the case.

globular-toast

Are you aware of Lisp? In Lisp programs were never "text". They are written directly as trees which are evaluated as part of the program execution. The trees themselves can be written via text, e.g. using s-expressions which are a tiny minimal way to represent trees as text, but they could also be generated via code (called macros) or written in some other way entirely. This is fundamental to understanding Lisp and one of the reasons "programs are text" people are often put off at first.

0x1ceb00da

Then there are languages like lisp. If you ask anyone in the community who's drank the s-expression koolaid, they'll say "your editor will take care of it bro, 12 closing parenthesis are totally fine". But every once in a while you're stuck in an environment with barebone vim, you mess up some editing, the language provides completely unhelpful error messages, and you're stuck debugging a bloody syntax error for 30 minutes.

The command line interface of a language should be really good and one should be able to program without any fancy tooling. The compiler shouldn't offload any responsibility to the editor/lsp.

bigpeopleareold

Yes, this is true. At this point, I would lean to that and panic. But it's also true that one can have already setup their editor to the REPL of an environment, obviating the need for using other editors and still retaining the type of control one would have in their editor.

danielvaughn

I’m obsessed with structural editors because it feels intuitively like the right approach to creating software. However I’ve yet to come across an interface that really clicks. Still love it though. Right now I’m building a structured editor for creating UIs, so can attest to how difficult it is to get it right.

It’s a super interesting problem space.

nzach

Couldn't you implement this as a plugin in your text editor?

I think this could work reasonably well in Vim. You could have a shortcut in normal mode 'av' (add variable) which would let you create a new variable and possibly set its type and the same every other construct in the language (structs, functions...).

The AI could probably even give you better suggestions in this workflow because it would have a better understanding of what you are trying to do.

If you really think about it, a plugin like this would be a more 'strict' snippets engine. After the LLM revolution we kinda forgot about the idea of using snippets to insert text into our files. But maybe its time to bring this idea back?

danielvaughn

Possibly! Though I think one of the purported strengths of a structured editor is that it restricts the ability to create invalid syntax. What you're editing really isn't _text_, per se. But you could definitely get halfway there with what you describe. That would be pretty interesting.

crowdhailer

I'd really like to get to the point where I have a library of transformations and you can make your own interface. Already the click ui and hot keys ui call the same `insert_function` or `assign_to` functions. Adding a ui with lots of dragging or voice control should be trivial

danielvaughn

I’ve actually moved away from GUI controls and towards something resembling a keyboard command language. Similar in spirit to vim motions, but instead of applied to text, it’s applied to an AST.

I think that could be the key to making structured editing feel less “clunky”.

plagiarist

That's interesting! Do you have any of it in a public repo?

null

[deleted]

timmg

> However I’ve yet to come across an interface that really clicks.

I'm not a Mathematica user, but isn't their editor also a structural editor? I wonder if anyone has any thoughts about how well that works.

j2kun

No, it's just textual input.

cfiggers

I enjoy Lisp and Lisp-alike languages specifically because with the right editor support you can do a lot of this kind of structural editing stuff without giving up the niceties of source code as text.

klibertp

You don't need s-exps (Lisp) for this; it turns out you just need a good parsing framework. Here's the proof: https://www.masteringemacs.org/article/combobulate-structure...

mtreis86

Yeah in emacs with paredit/smartparens/parinfer or whatever, it is both text and structure. With parinfer you change the text and the structure gets modified to match. With the other two you can change the structure directly with a command that has a silly but descriptive name like slurp or barf.

0x1ceb00da

You don't need s-expressions for that. Jetbrains IDEs provide this functionality for all supported languages, even bash.

nyir

While they're very good compared to the alternatives, I wonder why they haven't pushed more into that direction, e.g. what I've wanted to put into a plugin when tinkering with the PSI was simple composable operations, similar to Vim operations, like "rotate if/else branch" (while correctly negating and simplifying the test expression), or "convert if to case/switch/..." (and back and only if it's feasible).

xigency

This is a topic I've been contemplating heavily and it's very instructive to see the iterative progress you've made here.

I think development tools like this are necessary to expand coding outside of just the desktop experience. For example, I've seen kids program some pretty impressive robotics with just a touchscreen and Blockly.

Also, from a compilers perspective, it feels almost absurd to rely on plaintext. Imagine how much harder code merging is using line diff compared to diffing syntax trees.

Thanks for sharing!

amar1729

for diffing syntax trees, I've been trying out diffsitter, and it feels pretty good so far

https://github.com/afnanenayet/diffsitter

crowdhailer

Diffing is really an interesting point. Git is quite (maybe very) good. I wonder how much better a structured approach could be but it's obviously a large amount of work that I don't yet have time for.

aiono

Plain Text diffing has some obvious drawbacks:

1. If you rearrange your functions you will see a lot of additions and deletions while semantically there is no change in the program. It's just noise.

2. If you rename a variable you don't really have any actual change in places where it is referenced but text diff will again show a lot of noise. But the code references is still the same code.

1718627440

At least to me whitespace does convey meaning and order of functions or variable renaming definitely conveys a semantic change.

ElevenLathe

Modern SmallTalks have the option to save off a hierarchy of classes to text in order to use modern version control, and also to apply these exports to a running image. This should be even easier for traditional languages with no live running environment. There's no reason whatever structure editor you use can't export a normalized text representation so that you can still use it with Git

igouy

> the option to save off a hierarchy of classes to text

And so did ancient Smalltalks.

1984 "Smalltalk-80 The Interactive Programming Environment" page 46

"Within each project, a set of changes you make to class descriptions is maintained. … Using a browser view of this set of changes, you can find out what you have been doing. Also, you can use the set of changes to create an external file containing descriptions of the modifications you have made to the system so that you can share your work with other users."

https://rmod-files.lille.inria.fr/FreeBooks/TheInteractivePr...

williamdclt

Git (or whatever does the diff under the hood) is _adequate_. Every week I see diffs that are confusing, especially during merge conflicts, it’s honestly a bit embarrassing that in this day and age we don’t have anything better for something that is so central to our job

kmoser

A structured approach would be able to easily do things like ignore when a symbol was renamed (since that wouldn't affect the tree structure). So there are good reasons for wanting to do it that way, vs. a line-based diff.

eternauta3k

You could run a parser in the diff tool without using a structured editor, though.

unshavedyak

Awesome! Glad to see more exploration in this space. I too am exploring this, though i am perhaps making it yet even more complicated. I want to represent relationships between AST nodes in a visual way. Eg, i love Node editors in Blender and if it was given a good keyboard based UX i could imagine editing structural code in it.

I still imagine the code would be visually text, but i'm imagining that you'd be able to see a series of nodes in a code flow graph for your current editing context.

I figure AST editing (to some degree) is a generally good thing, but also representing code flow somehow is also a desired thing. It's what i do in my head, so can it be visualized in a beneficial way?

Difficult to say. Keyboard first will also be a challenge as i'll need to have a lot of intelligent alignment and visual compression.

Thanks for the post! Love to see work in this space.

alexvitkov

My biggest problem with node-based programming interfaces is the absurd number of nodes required for even fairly simple expressions, e.g `b*b-4*a*c` is 9 characters in most textual languages, but it would require 9 nodes in most visual scripting systems.

I imagine you could have an arbitrary "expression" node with N inputs and a textfield, but I've never seen it done and it still feels like a bigger hassle than punching out the expression in a textual language.

unshavedyak

Well to be clear, my model (that i'm trying to make, it doesn't exist yet) is very mixed with traditional text editing.

I agree with you, which is why mine is more of a text editor augmented by nodes. Notably each node is a variable scope window into text. I'm imaging a single function, more so than individual AST elements. The node can then have multiple inputs and outputs (or relationships of varying types, as i'm imagining) similar to how Blender can have many fields, inputs and outputs.

The variable scoping would mean you can make a single node as large or as small as you need. Including a whole file, or a single expression within a single function, etc. The goal of this would be to visually reduce unrelated clutter, such that relationships should be clear and not dizzying.

I want the nodes to visually represent how i normally work. Which is to say i have a text editor open and often i'm only looking at a single function in the file. Then i jump in and out of the function to related functions. Similarly those are text editor nodes as well, and so the chain continues.

I should stress, i really enjoy my text editor (Helix). I'm trying to add onto that UX ultimately, rather than replace it entirely. Reduce the things i think/hope i don't care about -- ie unrelated functions in a file -- and add things like visual relationships. Imagine an aggressive traditional text editor setting which folds all code you're not using. But with a slightly different representation which hopefully adds to the experience.

Sidenote, another motivation for me is to leave the Terminal. I've been in Terminal for 20 years now but just leaving it is not alone worth it. I want to toy with graphical representations that would be difficult in a Terminal. Something to justify it's existence when compared to something as easy and flexible as the Terminal is.

narag

Indeed, a hybrid approach seems better.

unshavedyak

Oh, related in this space: https://mbuffett.com/posts/structured-editing-syntax/

I thought this blog post had an interesting idea too. Basically that a structural editor which truly knew the underlying AST could then alter the visual representation of the code entirely. Eg changing it to look like Python, or whatever insane thing.

Not advocating for that of course, but the idea that the editor could be effectively transpiling the code in real time is an interesting area to explore too. I imagine not for the purpose of "Write Python that becomes Rust" or w/e, but just in general customizing the experience. Perhaps reducing clutter, /shrug

Slackwise

> Glad to see more exploration in this space.

I mean.... ParEdit [1] and ParInfer [2] have been around for a long time now. Structural editing is basically ancient. Lispers have been doing this for a long while, `slurp`ing and `barf`ing their parens.

[1]: https://paredit.org/

[2]: https://shaunlebron.github.io/parinfer/

jerf

I have no problem with anyone jousting with the windmills; I have a problem when they don't realize they are windmills. Hundreds and probably thousands of programmers have taken a crack at this problem. That doesn't prove it's a bad idea but it is effective proof until shown otherwise that if it is a good idea it is not such a good idea that it can instantly catch up to the decades of work in text editing. And the way some people talk about it, it's clear that a lot of programmers think that it should be that good.

This is up there with "everything would be solved with visual programming" and "hey, what if we could put down different syntax on top of the ASTs?". If your mental model is that it must just be because nobody has put any effort into the question, update your model, because in fact tons of effort has been expended and I'd suggest anyone interested in adding to the pile and actually solving the problems (as opposed to playing about, anyone can play with anything they like) is best served by examining the large pile of previous efforts and figuring out what they will do better than before.

Creating a language designed for being manipulated this way is at least a bit more rare than just declaring structural editing is the way forward in a general sense. Still, I'm skeptical. The existence of a textual serialization of programming language concepts is not the problem, nor is the usage of said serialization. Every serious tool already immediately deserializes the text into an AST, and when you really get down to the nitty-gritty of how one represents these things in memory, it is not at all clear that there is necessary a "better" way to serialize these structures, or one that is really very different in the ways that matter. There's a number of well-known (by those who look) pitfalls built into the idea of structural editing and it is not clear at all that the fundamental disadvantages can be overcome. Maybe they can. But the evidence at this point is effectively proof it's going to take more than waving "structural editing!" and some excitement at the problem.

kagevf

> Creating a language designed for being manipulated this way

AFAIK, Lisp wasn't created for structural editing, it was just a "happy accident" that it lends itself so well to the technique. Even without the paredit and parinfer plugins, emacs already has good support for structural editing built-in. It reminds me of VIM text objects, but geared directly for Lisp syntax, ie. symbolic expressions.

like_any_other

For structural code editors to thrive, what is needed is a universal, simple, minimal, txt-like format for the AST, so that AST-editors are not locked to a single programming language each.

crowdhailer

What requires the format to be text-like? I'm not sure I agree with this assertion. I think structural editors need to be language specific so that they can offer higher value edits that might only make sense for specific languages.

like_any_other

"Text-like" meaning easy to parse and universally understood. With language-specific (or indeed, all) AST/generic tree attributes serialized in a uniform way that does not entirely break parsing if an editor does not understand one of them. I.e. I can edit code even if my editor doesn't understand the language and doesn't give me syntax highlighting and completion. More, that that 'understanding' can be factored out of the editor core, as is done with language servers today.

zellyn

You might enjoy reading up on EYG and/or listening to podcast appearances of the creator…

WillAdams

Do you mean:

https://eyg.run/

Is this typo on the web page or in the language?

>type missmatch given: Integer expected: String

or is this an intentional phrasing to match the following text?

penteract

Having made my own forays into making a structural editor, I'd like to sing the praises of plain text: storing something that has been created by pressing buttons at a keyboard as something very close to the sequence of buttons that have been pressed is a great idea.

The magical ability of plain text is to go back in time and ask "what if I pressed a different button a minute ago/yesterday/last year?". This lets you see and fix mistaken keypresses, and even shapes the kind of mistakes you can make in a moment of confusion into ones that are quickly fixable.

The direct representation of buttons pressed also really helps with teaching/learning: With plain text, for mechanical questions on the level of "What buttons do I press to make a program that looks like that?", the answer is obvious for anyone who knows how to type. Try the editor discussed in the article to appreciate how different answering that question can be in a structural editor. Seeing and explaining how someone got where they did is also straightforward ("you missed a semicolon", "you misspelt a variable name"). Ideally, those are problems that don't happen in a structural editor, but people who press a slightly wrong sequence of buttons will probably still exist.

These arguments get much weaker when you aren't using a physical keyboard; I think this is the reason the article starts by talking about writing programs on a phone and a TV. In those environments structural editing has much more to offer.

WillAdams

I've tried to use LEO (Literate Editor with Outlines) a couple of times, but have never found it comfortable enough to stick with.

That said, the concept of Literate Programming has been one which resonated with me, and which addresses some of the same problems in a fashion which matches the way I work.

marhee

A mature (and very effective) structural editor is the FLUID user-interface designer, part of the FLTK UI framework (C++). It outputs C++ and works very well.

I remember dismissing it as a toy back when starting to work professionally with FLTK. Soon I realised I was mistaken; it is excellent to create UI's with for C++/FLKT.

dominicrose

For some reason this reminds me of semantic highlighting. A constant is not just an identifier - like a variable - it's a constant. There's more semantic in the text than the usual syntax highlighters highlight.

Some code formatters are good and exist for json or edn (extensible data notation) or even full programming languages like smalltalk or even more complex ones like typescript.

In a team it's true that code can be chaotic because not everybody uses a formatter and obviously we all have different coding style, even if the tooling made it more structured.

So yes it would help to enforce more structure in a seamless way so we can focus on the important stuff without creating huge diffs in pull requests.

eternityforest

I was able to use this without reading the manual, so I suppose it passes my favorite test of UI!

But I do wish it was more clear what you have selected, and what things are selectable.

andrewl

I’m always glad to see new work on tools, and amplifications to our capabilities of any sort.

I played with Smalltalk, and later Pharo, a bit, but it was years ago. As I recall the editor was always aware of the state of the system. And I think it was at a level beyond what any current IDE can do. While I do not remember if it allowed you to enter invalid code, it was definitely an interesting approach.

So I will be following Eyg for sure.

xkriva11

In Pharo, the method needs to be syntactically valid to be saved.

igouy

Generally, in Smalltalk, ...