[Appendix] All Else is Not Enough
I have already laid out my position on Emacs, in detail. Hereby I address various other technologies that I didn't find to be convincingly suitable for what I want of Project Mage.
Treat this article as an appendix. I am not trying to make any general point here, just want to discuss various technologies.
Really, for any of the following sections, if you have read the preceding articles, all you have to do is ask yourself whether they possess/enable all the important qualities I have loomed about, and, more importantly: could they ever even adopt those qualities meaningfully?
So, I am not going to address something obvious, like say C++/Qt: C++ isn't image-based, and so that's that. I would simply be beating up a dead ugly iron horse, which C++ most certainly is, even though Qt isn't badly designed at all when considering what it has to ride on.
But some projects are indeed interesting, and we can learn something from them, so they are worth discussing and, sometimes, criticizing. I view all these projects in the light of what I want to get out of Project Mage and its constituents.
In advance, I apologize to all the maintainers and contributors for some of the unfavorable feedback you will find below. I apologize, even though you probably deserve it, to be honest, you motherfuckers.
If you think I have missed some important piece of argument or technology, or if something is factually wrong, then, please, let me know.
Table of Contents
- Languages
- Lisp Machines / Genera
- Browsers
- Tools for Building Graphical User Interfaces (GUIs)
- Glamorous Toolkit Smalltalk
- TeXmacs Guile
- Editors
- External Parsers
- Languages Workbenches (Eclipse Xtext, JetBrains MPS)
- Countless Note-taking Applications,
- A Few Programmable Notebooks…
- And a Long-Running Trail of Dead Software.
Languages
It's a fairly widespread sentiment to incite a rewrite/port of Emacs to some other language. Rewriting or porting Emacs would be a pointless exercise, as far as I am concerned, but picking the right language for an interactive, power-tripping experience is a necessity. And since I have already explained Why Common Lisp is a great choice, now I will address some pros and (mostly) cons of some other contenders.
Some stumbling blocks for most of these are: lack of standard (often at the cost of stability) and lack of interactivity (CL is by far #1 on that metric).
Guile
The GNU/Guile manual has a section named Supporting Multiple Languages which states the following:
Since the 2.0 release, Guile’s architecture supports compiling any language to its core virtual machine bytecode, and Scheme is just one of the supported languages. Other supported languages are Emacs Lisp, ECMAScript (commonly known as JavaScript) and Brainfuck, and work is under discussion for Lua, Ruby and Python.
Brilliant! It continues:
This means that users can program applications which use Guile in the language of their choice, rather than having the tastes of the application’s author imposed on them.
Again, brilliant! But don't you feel the sheer amounts of disingenuity emanating from that statement? Because I do! Now, in order for me to contribute to an application in the Guile ecosystem, I have to learn the language that the author of the said application has picked, effectively imposing it on me!
And, by god, imagine the rewrites from one language to another because of this, creating unnecessary competition and tension.
Thing is: nobody wants to work with a crapton of tech they don't know, because it's simply added work. What sounds a lot more reasonable, if you want to be proficient within some ecosystem, is to pay the upfront cost of learning only the technologies that are synergetic and not redundant.
And how do you think the programs in all these various languages communicate? Through the common denominator of course: the primitives of the virtual machine. So, any one given power of a language is reduced to those primitives when seen through the lens of the whole ecosystem. You can call a foreign function, but can you hack it? I doubt it.
Something that's lauded as an advantage is but an attempt to hide the fact the authors are simply trying to avoid exposing and exploiting the power of LISP (Scheme in this case).
Neither will this same strategy1 Language hoarding is at odds with homogeneity, which I discuss in The Power of Structure. do wonders for Neovim.
Tower of Babel, anyone?
—
A system is as mediocre as its most mediocre element. And, over time, things just converge to the shitful mean.
So, you need to strive to eliminate the shitty things from your system. Being happy about using them as fertilizer is not the way: you reap what you sow.
Of course, I understand, Guile VM wants to be the glue for the userspace of an operating system, or maybe even be the operating system itself, or, well, at least be the platform for Emacs to evolve onto. The distinctions are quickly fading on me.
It is certainly building towards a vision, and that vision is Unix with Scheme. Not quite a vision of a Lisp machine or a Smalltalk machine or Something that has solid values.
Smalltalk (Squeak, Pharo)
Smalltalk is a great, elegant language which pioneered many things and is especially known for OOP and message passing.
Well, less for message passing, and more for OOP, whose core idea of objects as virtual computers (inspired by biological cells) was widely misinterpreted by the mainstream languages and is now very popular in its subverted, desecrated, depraved form (and with message passing done away with).
I myself haven't programmed Smalltalk or any of its variants, but watching its demonstrations and, generally, talks by Alan Kay certainly makes for a warm feeling. I think that's something special when a language has that.
An especially interesting Smalltalk feature is its synthesis with its IDE/environment, which includes graphics, audio and other things out of the box.
Smalltalk could be a very strong contender to write Mage.
I definitely like Lisp syntax more, though.
Also, neither Squeak nor Pharo seem to be standardized (I think a standard would somewhat go against the cultural grain of Smalltalk, although there's ANSI Smalltalk too), and I think that's a downside for a project like Mage.
Scheme, Racket, Clojure
Every once in a while you see some Common Lisper switch to one of these modern lisp incarnations. Traitors! Every one of them!2 Don't worry, though, they will be coming back eventually.
These languages do have their strengths, of course.
But, if it's Scheme, it's not clear which one. And CL is just much more practical out of the box, library-wise too.
There are also some complaints about Racket's interactivity.
And Clojure, in my opinion, as elegant and pleasant as it is, would have been too opinionated for anything Mage-like. Also, JVM that it is designed for somewhat cancels out the pleasantness and elegance, so that's that.
Julia
Never touched it. But some feedback from CL people is not far too flattering.
There's no standard. They are also try-harding to replace Python. It's a noble goal, but not terribly exciting.
From the positive sides, it has a parametric type system. But CLOS/MOP will get you there as well, and, in fact, some packages do.
Python
come-on-now.jpg
No, really, come on, now, you didn't really expect anything in this section after seeing the other languages listed, did you?
Lisp Machines / Genera
Genera is a proprietary OS that ran on Lisp Machines. Both were developed by Symbolics in the 1980s, with deep roots in MIT AI Lab. The business went sour and the property rights have been subsequently reacquired. You can read more about it on their website. Apparently you can still buy and run the system (on an emulator).
There's not really much to say about it: it is an incarnation of the iconic vision for a Lisp machine! The cool ideas were those of systems-wide programming: hardware integration, coexistence of multiple Lisps, and, of course, the fact that every program ran as a part of the same hackable environment. (The latter experience may, of course, be replicated in any Lisp image.)
I discuss CLIM, a standard that grew out of Genera's GUI framework (Dynamic Windows) in a later section.
Browsers
The only advantage of building something in a web browser is that you can view websites right in them. If your task is not to display a webpage, or build a website, if CSS+HTML is not the limit of your imagination, then there's no reason to be building complex shit in the web browser!
I can see hitching a web browser ride as a ubiquitous cross-platform graphical backend (over WebGL) if you are willing to deal with all the overhead and impact on speed. But with the libraries like SDL and Skia (which browsers use), that seems kind of pointless.
Moreover, browsers are not the right way to be using web anyway. See my thought on this in the Data-Supplied Web article.
Tools for Building Graphical User Interfaces (GUIs)
Garnet Common Lisp
Garnet is a great interface toolkit developed at CMU's User Interface Software Group, headed by Brad Myers, in the period 1987-1994. Quite a few UI-building editors and projects were developed as part of it (such as an interface builder, a constraint editor), among a few other UI-exploratory applications like a spreadsheet and a plotting system.
The toolkit has been used in over 80 applications.
Otherwise, the development has halted. The group moved on to build Amulet in C++3 See Why change to C++ section here., taking (some) Garnet ideas with it. I don't suppose all the group members were all too thrilled with that.
But Garnet is in public domain, and would even work, if not for the X11-related bitrot. However, there are some more entertaining problems with Garnet than just lack of maintenance.
Interactors. Interactors aren't really general enough. They embed a very interesting idea, though: modeling interaction as a state machine. But they shouldn't have used inheritance, they should simply have been objects that you can add to a schema. I think throwing out the interactors (as some separate input-handling concept) and simply retaining the state machines for whatever purposes even other than input is the sane thing to do. That doesn't mean there shouldn't be any specialized ready-made objects for some common interaction uses, but they should have a simpler, more transparent, implementation.
Also, I find it strange that Garnet's kr uses its own type-defining construct for declaring types for type-checking purposes. Needless to say, this could have been done nicer and will be.
I also wonder if declarations really need to use the special syntax. I think defining a declaration like you would any other slot would be nicer.
Garnet uses formulas which are a one-way dataflow mechanism for kr. There's no good way to use formulas to define circular definitions (of more than two terms), or to express multi-way constraints for that matter. As was also noted by the authors of mutli-garnet, formulas can't be bundled (a formula is directly associated with the slot it controls), and this makes inheritance of related formulas across multiple slots hard to track.
Garnet's formulas are an otherwise efficient and rather powerful mechanism and has worked well for many projects. But multi-garnet is simply more general and even more powerful.
From the technical, software-engineering minded perspective, Garnet is not quite the pinnacle of quality. And it makes sense: it's was a practically-minded research project with many new ideas to test. Overall, Garnet lacks some important customization primitives, a decent abstraction for graphical objects (aggregadgets aren't quite it), and is a bit awkward and underdeveloped in a few places.
Nothing glaringly bad, though. In fact, Garnet's core abstractions are solid, and many other abstractions simply need to be iterated and improved upon.
Most importantly: it's fun to use, and was fairly easy to pick up on.
I consider Fern to be a successor of Garnet.
CLIM Common Lisp
(I had a conversation with jackdaniel, the maintainer of CLIM. I will soon update this section according to our conversation. What I learned: I have slightly misinterpreted a technicality about the mechanics of output records, but my general point still stands. Also: note about indirect-inks
, which, again, changes very little. To be updated.)
This was one of the tougher section to write, in large because I have talked to the developers and contributors of McCLIM on IRC, and they have always been very helpful and kind.
And also because it's been so fucking hard to decipher how this framework is supposed to work or even understand what's so goddamn special about it. I mean, here's Superapp from the official McCLIM website:
So aptly named that, if I were to guess, I would have said it's some kind of postmodern humor4 Means it's fucking unfunny..
Every time I have opened some McCLIM example code, here is what happens: I stare at it for a bit and then whisper to let myself know the future course of action: "Hmmm. Better open that spec/manual." Then I open that spec/manual. I read it and I feel like I understand something, but it's like there's something more to understand anyway, some sliver of knowledge that will pull everything into a coherent whole, but I don't know what that sliver might even be, and so everything stays where it is, dead in its tracks. Then I go back to keep staring at some other example, this time for about exactly three seconds, and then say to myself, calmly: "FUCK IT, I AM DONE.. MAAAN, FORGET ABOUT THIS ARCANE BULLSHIT!!!"
And then you see something like this in the manual6 Here's the version as of the day of writing.:
Many new users of CLIM have a hard time trying to understand how it works and how to use it. A large part of the problem is that many such users are used to more traditional GUI toolkits, and they try to fit CLIM into their mental model of how GUI toolkits should work.
Oh, well, look!
Stupid users are just too stupid to understand! They are simply too used to all those stupid frameworks! But it's OK because CLIM itself is just fine!
And while I agree that there are some pretty stupid GUI frameworks out there, it's pretty clear to me that they are most certainly not the reason why those users have a hard time with CLIM.
And I had a hard time with it too! But I refuse to feel like a fool, forever cast aside as someone who "just didn't get it".
So I kept at it, and now I present to you: 6 reasons why CLIM sucks7 Well, six or something like that. I didn't really count. Probably more. Certainly more.. Enjoy.
Classic OO
Taking a general outlook on CLIM, we can see that it uses CLOS, which is a very powerful OO system. A big part of CLOS flexibility comes from MetaObject Protocol, which is quite complicated, but it works. And yet, it's a classic OO system in the sense that classes and objects are separate entities.
Garnet, for instance, used KR which is a Prototype OO system. I discuss Knowledge-Representation in The Power of Structure.
If you don't have prototype OO, you will likely have kludges-by-design such as this one:
For example, a pushbutton has an "activate" callback method which is invoked when its button is pressed. For this particular callback, a method named activate-callback
is invoked by default, and a CLIM programmer can provide a specialized method to implement application-specific behavior for a subclassed button-pane
. But except in the case where the programmer needs a lot of buttons with related behavior, creating a subclass for changing a single specific callback is not economical. Hence upon gadget creation, the programmer can specify an alternative callback method for all callbacks available. By providing the :activate-callback
initarg, the programmer can change the callback to any regular or generic function.8 A Guided Tour of CLIM (2006)
CLOS subclassing is a chore, indeed.
Lack of prototypes invites a flexibility penalty and can't be easily cured.
No Dataflow
And since I have mentioned Garnet, I might as well note right away that CLIM is missing any sort of dataflow mechanism for its slots. Lack of dataflow is a major reason why so much of CLIM applications code is so imperative and riddled with setf
's and callbacks. I won't say much else about it here.
Hey, look at this gem for no reason whatsoever:
The drag-callback
method resets the background of drag-feedback-pane
and delegates its redrawing to redisplay-frame-pane
, while value-change-callback
does the same for the frame’s current color pane.8 A Guided Tour of CLIM (2006)
A very important footnote.9 At this point I am starting to feel like I am beating down on a child. Some of you may even wonder why not simply say "CLIM sucks" and be done with it. Well. I didn't find a good resource that gives CLIM a critical overview, and since it's one of the two maintained non-proprietary CL-centric GUI framework as of the day of writing, it would have been strange had I just skipped it. Since I have already started, I might as well give a shot at the rest.
[Interlude] Presentation-Based Interface
Before we continue, I want to say something actually good about CLIM. And maybe try to explain to the folks at home how it works, a little. And not that I would know how it works myself, of course, but I think I have managed to grasp a few grains of its basic working principles from all the pain of reading some of the works dedicated to it.
The good thing is that the interface in CLIM is presentation-based. Or maybe the good thing is not that it's presentation based, per se, but that it links objects on the screen to real Lisp objects.
Now, all those Lisp objects will have a type. You can then write a method of interaction for that type, and that method will apply to all objects of that type. That may be input, or modification and what have you. That's how you interact with objects in CLIM.
For instance, you may create a command that, say, takes an integer and a circle.
In the command line, you can now type the name of the command and then click on something on the screen that represents an integer (the visual representation may be anything, say a line of length 10
, which represents integer 10
), and then click on something that represents a circle, and say, the result of that operation will be that circle radius will get that much larger by that integer amount (represented by the line).
Everything you draw (via usual means) will automatically be an object that you can inspect and touch and interact with. So, visual pixels on the screen have semantics. That's pretty nice.
The way presentations are accomplished is through output records. And since presentations are about all the good things I know about CLIM, let's discuss those output records now.
Output Records
Now, if you want to create an application, you define an application frame.
Within that frame you layout your panes. A pane is where you draw stuff.
What you draw gets captured into something called output records. CLIM will do the actual rendering from those output records.
If your pane gets resized or scrolled, CLIM will automatically draw all the stuff based on these output records.
The programmer can change these records for the benefit of incremental redisplay: CLIM will only render the change (and redraw the effected surroundings for correctness).
Output records also hold all the information necessary to enable interactivity and presentations.
Output records may seem like a great idea: they enable so much!
But I think this is mistaken. Output records serve as a rather useless layer of indirection between objects and their semantic presentation on screen.
Look at it this way.
So, you have a tree of panes/gadgets within an application-frame. Well, is this tree not enough, is it somehow not powerful enough to represent itself? Why should it be duplicated as a tree of output records?
Capturing the draw operations is not necessary: you can represent all your draw output simply as a part of that tree.
Want to draw ten interactive lines and circles? Make each of them a part of the tree as gadgets.
Want to draw ten million lines? Define your own containers (which could be of rather a general nature, such as arrays) and teach those containers how to handle input. You don't have to be locked to a branch in the tree of output records.
Each branch and node can itself decide how to handle the input, how to draw itself, all in its own context and precisely how it wants to. The parent node can do the optimizing/culling part.
None of it has to be any harder or less efficient than maintaining a bizarre overgrown body-double of your original tree. In fact, it would be simpler, while yielding more control and efficiency.
Output records don't really simplify anything. Anything you can do with an output duplicate, you can obviously just as well do with a tree of your original panes/gadgets, and have more control when doing so, without any overhead.
Output records, for what they're worth, act as a caching mechanism for the element layout, and that mechanism is an ingrained fixture of CLIM experience. And one thing to know about caching: where there's caching, there's cache invalidation. You can't meaningfully bypass it because output records are coupled with the interactive capabilities of the system (i.e. a presentation is a type of an output record).
One of the two hard problems of computer science is enabled by default, and you can't bypass it. You read that right. Layouts get invalidated all the time. Programs are meant to be dynamic, especially UIs. Caching them is just not very reasonable, and when it is, it should be adjustable without having to compromise.
Output records may seem like a good abstraction, but they aren't. They prevent you from freely treating your interface tree as a data structure, taking up a part of the responsibility upon themselves. This latter point is exacerbated by the fact that there doesn't even seem to be a notion of tree node in CLIM. Let's see what it has to offer instead.
Panes, Gadgets and Application Frames
Let's take a look at a few definitions from the LispWorks CLIM Guide10 LispWorks CLIM Guide:
- Panes
- CLIM panes are similar to the gadgets or widgets of other toolkits. They can be used to compose the top-level user interface of applications as well as auxiliary components such as menus and dialogues.
- Gadgets
- Gadgets are panes that implement such common toolkit components as push buttons or scroll bars.
Say, what's the conceptual difference between panes and gadgets?
Why can't a push button be a push-button
that inherits from pane
and implements everything it needs?
Why do these entities have to have a separate name for them?
And then, apparently, there's a notion of adaptive panes:
A subset of the abstract panes, the adaptive panes, have been defined to integrate well across all CLIM operating platforms.
Since gadgets inherit from panes, does this mean there are adaptive and non-adaptive gadgets too?
Damned if I know.
Now, it would seem that an application frame would just be a window in your OS. But get this:
Frames can be displayed as either top-level windows or regions embedded within the space of the user interfaces of other applications.
- Application Frame
- An application frame, or simply a frame, is the locus of all application-specific knowledge. It is a physical, bordered object that is composed of smaller, individually functioning parts, called panes.
So, why can't a pane or gadget be the locus of all application-specific knowledge? Why does application data need to be conceptually stored within the root element of the tree, essentially making it global with respect to the nodes of that tree?
Why not have just two concepts: a gadget and a window?
My answers are: I don't know. I just don't know.
Missing Context Facilities
The customization process in CLIM relies on dynamic variables. That's not ideal.
Here's some random, fairly typical draw call from McCLIM code base (as a part of some handle-repaint
method):
(draw-line* pane x1 y1 x2 y1 :ink +dark-grey+)
To change the color, you would have to recompile the parent drawing code. Instead, we could imagine, something like this would also do the trick:
(let ((*ink* +dark-grey+)) (draw-line* pane x1 y1 x2 y1))
.
Where instead of +dark-grey+
, the class with this draw method would store a variable that the user can access. That would eliminate the need for recompilation.
But that won't really work: if you throw another shape into the mix, like a circle which you want to shade blue instead of dark grey, a shared *ink*
customization won't work.
Each shape class would need its own ink variable for something like that, and that variable would have to be picked up by the draw call automatically.
You could try walking output records and setting the colors by hand, but I don't really know if output records allow it. If they were a part of the tree gadget/pane/frame tree, it wouldn't have been a question.
Even if you can do it by directly modifying the output records, though, the point about class-specific settings still stands.
There's also no kind of advice facility, as far as I can tell (the :before and :after methods can be defined only once for a generic function).
The system is only flexible for the programmer of an application (and even then, to a degree). For the end user – not so much.
Ambition to Be Native
Sheets, grafts, windows, ports, panes, mediums, managers, streams, gadgets, frames…
All these terms have some defined meaning and purpose, but you inadvertently begin to wonder how many of them actually contribute to the utility within the realm of the problem at hand, and how many are artificial demarcations designed to make your life harder than it has to be. Of course, you can just ignore these if you don't use them. Of course…
And, of course, this terminological zoo exists not in the least thanks to CLIM's ambition to subsume native widgets of the OS's toolkit. Multiple toolkits, if possible.
CLIM supports the incorporation of toolkits written in other languages. A uniform interface provided by CLIM allows Lisp application programmers to deal only with Lisp objects and functions regardless of their operating platform.8 A Guided Tour of CLIM (2006)
So then you end up with issues like this, mentioned right in the spec:
Major issue: There is a general issue about how these menus fit in with the menus that might be provided by the underlying toolkit. For example, under what circumstances is CLIM allowed to directly use the menu facilities provided by the host? Should :leave-menu-visible t
interact with the "pushpin" facility provided by OpenLook? — SWM
Thing is: the underlying toolkit zoo is just a zoo as well, and each one is a mess, so trying to abstract them all away is going to leak. The way I figure it is: the backend should configure your menu (or what have you) through runtime addition of slots/behaviors, and that's that.
CLIM, being based on CLOS, is a hard sell for this type of trick, though.
Usability and Some Conclusive Remarks
CLIM wants to be your window manager, your desktop environment and your toolkit box for your native toolkits. A kitchen sink of sorts, and all the tap water you have is cold, and the tap itself is somehow constantly bending out of shape, away from the sink and in the general direction of your face.
It seems to actively believe the idea that a widget tree should somehow be separated from its visual presentation by some other tree, and that's a cause of quite a few ills and clumsiness. I mean, yes, I can see how tempting it may be just to "capture" what you draw and call it something very important, like a "presentation", or something, but not once you realize that you can update your tree dynamically and keep whatever information you want in it, and it will do everything you want it to do, all much simpler and more straightforward.
That's a problem. Well, that and a few other dubious abstractions. And quite honestly, I don't think I have even seen a half of it. I haven't programmed anything in CLIM. So, I can't claim to know what it's actually like.
But I am always willing to listen to people who did:
I liked the idea of McCLIM but as I use it every time I try to do something that doesn't really fit into the pattern the library seems to assume you want to stay in (a static layout or set of static layouts, all textual input/commands are through the command loop, &c.) it's super painful and I have to dig through a bunch of mixins and the spec and it still often doesn't behave how I want it to.11 Choosing from GUI Toolkits
I can't judge the validity of most comments about CLIM. But most certainly, "static" isn't a word I want to hear in the context of an interactive GUI framework for power users (or even for programmers). And, maybe, not all the negative comments are fair as some folks didn't give it a real chance (finding it too hard to get going with, for instance). But others seem to be well-informed. These comments aren't rare, and I won't list them here other than the (fairly random) one above.
Well, sometimes you will hear how someone had some sort of enlightenment about how CLIM works. I haven't had such an enlightenment myself. And I am not against any learning curve, per se.
At that, I think the existing manuals/documentation/papers aren't the problem. CLIM is not very beautiful, and it's just hard to explain well the things that aren't beautiful.
CLIM (whatever its incarnation) is not a very bad GUI manager/framework by any means. Some features like infinite drawing sheets are pretty cool. But I do think it's grossly over-engineered12 Or as they like to call it nowadays: sophisticated., and, yet, accomplishes far from everything.
Must have been an interesting experiment, I guess (and it's ongoing). I, as a programmer, can't really see myself using it, though.
Alloy Common Lisp
It looks like a neat, workman's, clean GUI kit. Nothing too fancy, and, right off the bat, I don't see any obvious blemishes with it. Would do for a simple application. But for flexibility and power use? It's just not designed with that in mind.
Glamorous Toolkit Smalltalk
Glamorous Toolkit promotes the idea of moldable development.
There's a talk on it: Tudor Gîrba - Moldable development.
The basic idea is to have multiple views and editors for any piece of data in your system (including code). Kind of interesting, but the toolkit looks and acts more like a fancy computational notebook type of environment, but without explicitly being a computational notebook.
The site on moldable development states its difference with literate programming:
They are similar in that they both promote the use of narratives for depicting systems. However, Literate Programming offers exactly a single narrative, and that narrative is tied to the definition of the code. Through Moldable Development we recognize that we always need multiple narratives, and that those narratives must be able to address any part of the system (not only static code).
And that's a sensible viewpoint. But I still see it as an advanced version of a literate programming, all done within an interactive environment.
The focus of Glamorous Toolkit seems to be on explaining a code base or a certain part of the system via presenting it via a custom tool.
But I am not too convinced with the top-level development model / workflow it assumes for you. I guess it's too narrowly-focused / opinionated.
It's also a custom fork of Pharo, so the question of long-term stability is even more unclear than that of Pharo itself.
I can't say I can compare it to Project Mage in any meaningful way, except it's also a live environment.
TeXmacs Guile
TeXmacs is an authoring environment / document editor for: text, mathematics, graphics, interactive content, slides, etc.
In terms of user experience: think Word, but sane. In that TeXmacs positions itself as a WYSIWYG solution.
Actually, we conjecture that, within five years, most mathematicians, physicists, computer scientists, etc. will use wysiwyg editors to write their documents. – TeXmacs authors, circa 200113 GNU TeXmacs: A free, structured, wysiwyg and technical text editor
I don't think this came to pass: WYSIWYG hasn't taken over the world, not in the realms of the advanced userland anyhow. But, to be fair, neither has "plain text" editing. What we see most often now is a hybrid of sorts, heavily skewed to the non-WYSIWYG side, often with a lot of skepticism and outright sneer aimed at pure WYSIWYG.
Of course, there must be a good reason why people still prefer Vim and Emacs to Word and TeXmacs even when the task is document authoring: I believe that reason is clarity. Pure WYSIWYG editors tend to defer much control to external UI elements, and those often seem like noise and can be hard to navigate. In the plain-text model, everything seems exposed and out in the open for you to change.
But once you get used to it, plain-text markup will soon become just as noisy, if not more, and you will look for ways to hide the cruft and look at the content more, preferably as it appears in the final result. This nowadays most often takes place at small scales: Emacs packages will sometimes offer you stuff like in-place formula rendering, image-embedding and text stylization. But these are mostly accomplished in some crude manner and any kind of advanced layout or interaction capabilities are very much inaccessible for the string-based editors. Just as bad: the conversion process and therefore the control over the final result is decoupled from your main editing process.
Unlike the TeXmacs authors, I don't believe that pure WYSIWYG is the answer to everything or will ever be. I think the truth is that the presentation needs to be fluid: that you have the ability to jump between the underlying presentation, and WYSIWYG as you please. And an in-between hybrid solution could be reasonable as well for certain times: the element under the cursor may take a form of a specialized text editor (for instance: a mathematical formula which uses markup). I think it's just a matter of giving the user a choice to move between all these options at will. And no solution that offers itself as pure will do well at this.
Other than for the reasons of hiding the underlying elements, I also have to note that the kind of interaction that TeXmacs offers for WYSIWYG text-editing is still subpar and could well steer many people away from using it. What I mean by that is that interacting with it doesn't feel like Emacs at all - more like Word. Just like Word, in fact.
The way I see it, Rune will be quite unopinionated on the matters of being WYSIWYG or non-WYSIWYG. All it will ask is simply for the lenses to implement text-related APIs. This would make it easy to write generic operations that work on text, give the fluidity across the whole document. But the lenses are not restricted to any sort of layout. Therefore there's a case to be made that Mage might at some point become a comfortable authoring environment, the kind which doesn't force you into some mode or way of looking at things. At that, making such an environment seems more a matter of attitude, and not so much of particular technical difficulty.
While I don't set this as a goal for the campaign, I do think that this development is foreseeable at some point. But even for the scope of the campaign, things like justification could be nice to implement (no promises on this one, though).
Speaking of typesetting engines, I think there would be a few good reasons to try to implement the layout with just the lenses themselves, each lens acting as a layout engine for its own lenses, each being contextually influenced/adjusted/created by its super lens. In other words, I am of the belief that the typical global typesetting approach of feeding the document to some engine entity is unnatural for true customizability (piecemeal or not). It just feels off. And, indeed, accessing the layout engine isn't something that you can do as a user in TeXmacs, it seems (I might be wrong). But, more so, I am not even convinced that the "feed the document into an engine and get back the layout" is the easiest way of controlling the layout to begin with.
So, to summarize:
- TeXmacs is a pure-WYSIWYG environment, and so doesn't offer suitable editing facilities for the underlying structure. It has a source-editing tool and that could give you access to specialized markup: but defining your own editors isn't something that seems possible since UI programming is not in the user's domain. You could feed a layout structure to an engine, you could tweak the existing markup, but that's about it. There's no good reason for this, and it's a big limitation, and a deadly one for true extensibility.
- TeXmacs' WYSIWYG text-editor doesn't offer anything close to Emacs-like textual capability as the elements in the document don't have a system for text-oriented interaction. This yields more mouse interaction than necessary. And to some people, myself included, this can be a deal-breaker. I mean, even for what may seem like a specialized task of document authoring, much of interaction requires or can be comfortably done via what can be recognized as general text-editing operations. And, so, you can't just forgo that and claim that you are purely WYSIWYG and that using mouse is fine and then expect not to be called Word, even if you have Emacs in your name.
- The layout logic seems to be intrinsic to the system, and not something that the user is ever expected to touch. The high-level elements are up for usage, sure, but you are still confined within a system that's given to you and is otherwise non-negotiable. In fact, a lot of things seem to be simply exposed via API, and not as primitive building blocks, which all leaves me feeling that TeXmacs is a software temple and not a power-user environment.
- WYSIWYG + typesetting is really a UI task. But I don't see how TeXmacs is a UI toolkit. So, it doesn't seem like you can build your own UI tools there.
- TeXmacs confuses presentation with data.
- It's only one more step beyond Emacs in that it offers you lists of lists (trees) in addition to strings for representing your data. The architecture seems to be hellbent on this notion.
- It imitates paper and the whole foundation for the application is specialized around this rather narrow concept.
There's however something to be learned from TeXmacs, especially what concerns the input of mathematics (done structurally), and just the general typesetting stuff. So I suspect I might be looking at this tool in the future some more.
Editors
Climacs, Lem Common Lisp
These projects are mainly aimed at improving CL development experience. They haven't walked too far away from the Emacs mindtrap: editing is not structural, they have to be using parsers. So, not terribly interesting to me as such.
Also, Climacs was written in McCLIM. Within the boundaries of this section, I am not holding this fact against it, though.
Sedit and others
One in the line of a few structural editors for Lisp.
In any case, it has a rather clunky interface. This is what people usually think of when they hear about structural editors.
Here's a demo: Lisp Editing in the 80s - Interlisp Sedit.
VsCode
Sadly unimaginative. A corporate solution for the end user.
Will die when a new shiny toy comes along in 5-10 years from now.
"Code editing. Redefined."
Hrmph? If you can tell me what exactly it has redefined besides the everchanging status quo, let me know.
Also, see Browsers.
External Parsers
LSP (Language Server Protocol)
Someone misspelled LISP and now has a mediocrity on their hands.
Basically, the history of software industry in one sentence.
LSP is great for mediocre bullshit with mediocre needs. Pretty much unsuitable for dynamic languages and image-based development.
Static? Ask some advanced C++ nerds if they like it and be surprised: nope. Not either.
Whatever is responsible for structural analysis should also be responsible for editing and all the extension capabilities.
I do recognize it as an explicable evil that has to exist for this time and age to tame some of the monstrous mess out there.
But I also don't have to like it ¯\(ツ)_/¯.
LSP was popularized by VsCode. Which figures.
Tree-Sitter
It differs from LSP by giving you access to the AST tree and by not trying to do some IDE-level stuff.
Sure, like with LSP, it's commendable that it makes people's lives easier. It's a universal solution which may be used in many editors: can't argue against reuse.
The real problem lies in the integration with the client environment. Tree-sitter is fundamentally separate from the client application. This gets questionable fast.
For example, suppose your have a source file with a comment in it. Suppose you want to edit the comment in an embedded Markdown editor. So, it figures that in Tree-Sitter, you will then want a Markdown parser for that. Suppose you can make it do structural embedding. But how are you going to control and customize the complex interaction policies between the hierarchical structures? Embedding is where outsourcing the structural knowledge fails.
Tree-Sitter doesn't let you control your editing workflow. It's just a reactionary fixture upon a string.
And, indeed, worse yet: you are still working with a string.
Languages Workbenches (Eclipse Xtext, JetBrains MPS)
Language workbenches are oriented towards AST editing for the purposes of DSL construction. They present themselves as IDEs with a projectional editor, where you can define your own building blocks.
These workbenches are interesting developments because they give you a feel for what's possible with structural/projectional editors. The projectional editor of JetBrains MPS, for instance, allows the user to edit the Abstract syntax tree (AST) representation of code in an efficient way. It can mimic the behavior of a textual editor for textual notations, a diagram editor for graphical languages, a tabular editor for editing tables and so on. The user interacts with the code through intuitive on screen visuals which they can even switch between for multiple displays of the same code.
Obviously, they are not geared for work on arbitrary data structures, let alone do things like lensing/transclusion. Even if they were written in Common Lisp, their scope would be too limiting for Rune-like applications.
Countless Note-taking Applications,
And boy, they are countless.
There has certainly been a wave of aspiration rising towards the sun of programmability and extensibility. With various degrees of success.
95% of these projects run in the browser, some of them are proprietary, and most of them don't even beat Org-mode. (I have already talked about Org-mode in the Emacs article.)
Oh, well. Some of these note-taking project, like Roam Research, are at least written in Clojure, which is a Lisp of sorts, so that's not too bad. Roam Research is very nice, indeed. Too bad its proprietary. It's also paid. But lets not be too judgmental about that, I would also be charging people if I could get something like that to work in the browser.
Oh, well.
A Few Programmable Notebooks…
Nothing terribly exciting has been happening on this horizon either.
The data scientists have been quite vocal and unequivocal about their eternal sufferings, so that's that.
And a Long-Running Trail of Dead Software.
Footnotes:
Language hoarding is at odds with homogeneity, which I discuss in The Power of Structure.
Don't worry, though, they will be coming back eventually.
Means it's fucking unfunny.
Speaking of Zeppelins, surely you have seen one near your local airship dealer joint, right? Right? Boy, let me tell you, those things do look super heavy. Not very clear on how you would operate one, oh no, they don't tell you about THAT. "Fly it and see for yourself," "RTFM," "practice makes perfect", etc. There's, apparently, a classic manuscript on dirigible building, but all it tells you about is the physics and thermodynamics of the damn thing, how it's structurally built, that type stuff. Doesn't tell you anything about the so-called quirks you have overheard about at the local steampunk club, whatever that's all about. But hey, don't get me wrong, it does look kinda cool and all. By the way, if you don't know what a dirigible is, it's an ambitious thing from the past century, which people have majorly given up upon, well, except some who still can't get over it. Enthusiasts, naturally! CLIM is a huge, experimental air-climbing mechanism, menacingly floating and even somewhat operational. But it's not exactly the future of air flight.
Well, six or something like that. I didn't really count. Probably more. Certainly more.
At this point I am starting to feel like I am beating down on a child. Some of you may even wonder why not simply say "CLIM sucks" and be done with it. Well. I didn't find a good resource that gives CLIM a critical overview, and since it's one of the two maintained non-proprietary CL-centric GUI framework as of the day of writing, it would have been strange had I just skipped it. Since I have already started, I might as well give a shot at the rest.
Or as they like to call it nowadays: sophisticated.