Ask HN: How to learn about text editor architectures and implementations?
Honestly I don't understand anything. I am not able to make sense of the data flow and the architecture. I want to understand how text editors work under the hood. Also I want to understand the plugable architecture they use to extend the functionalities of the editor.
Please suggest me any articles, videos, conferences, blogs, where I can pick up the concepts. I have been troubled by this lack of knowledge and unclear path to access it.
Edit: Reasons for this quest: I am not here to create yet another text editor. But I do understand that they are one of the complex peice of software which still is under constant improvisation and developement. Also text processing is the one of the core concepts of computer science. A lot of algorithm and data structure knowledge is hidden inside it. Besides, I feel through real world projects one can learn alot about core computer science foundations.
76 comments
[ 3.4 ms ] story [ 140 ms ] threadThis is a series that I used to follow as I too wanted to implement my own text editor to learn the underlying architecture.
The Craft of Text Editing
—or—
Emacs for the Modern World
–by–
Craig A. Finseth
https://www.finseth.com/craft/
which is more of a 10,000 foot view.
Theory and practice of text editors, or, A cookbook for an Emacs
https://dspace.mit.edu/handle/1721.1/15905
https://news.ycombinator.com/item?id=11244103
It’s about data structures for editable text. Surprisingly complex!
[0] https://tldp.org/HOWTO/NCURSES-Programming-HOWTO/
Note that it’s behind a paywall (his catalog is likely worth it for a curious hacker such as yourself).
Watch his “compiler from scratch” for free to get a sense of what his casts are like: https://www.destroyallsoftware.com/screencasts/catalog/a-com...
This is written in rust and has docs about rope data structure and editor architecture.
as trying to write it yourself
and then reading about how other people do it e.g VS Code blog
https://code.visualstudio.com/blogs/2018/03/23/text-buffer-r...
Architecture-wise, you can start with an ordered list of lines, with each line stored as a string.
Features that complicate things are:
- supporting large documents and staying speedy (“replace all” is a good test case)
- supporting line wrapping or proportional fonts (makes it harder to translate between screen locations and (line, character) offsets)
- supporting Unicode (makes it harder to translate between screen locations and (line, byte position) offsets)
- syntax-colouring
- plug-ins
- regular expression based search (fairly simple for single-line search _if_ you store each line as a string; harder for custom data structures, as you can’t just use a regexp library)
- supporting larger-than-memory files (especially on systems without virtual memory, but I think that’s somewhat of a lost art)
- safely saving documents even if the disk doesn’t have space for two files (a lost art. Might not even have been fully solved, ever)
Edit: you also want to look at https://news.ycombinator.com/item?id=11244103, discussing https://ecc-comp.blogspot.com/2015/05/a-brief-glance-at-how-...
[1] DevTools hacking playlist - https://www.youtube.com/playlist?list=PLMOpZvQB55bfeIHSA71J8...
I know of The Craft of Text Editing.
https://www.finseth.com/craft/
There’s also the Racket editors, which includes a text editor control, in the Racket Graphical Interface Toolkit. It’s what is used to implement the DrRacket IDE.
https://docs.racket-lang.org/gui/editor-overview.html
https://en.wikipedia.org/wiki/Rope_(data_structure)
Has anyone used other mechanisms for large document types? It seems like an array of paragraphs, each containing a simple string could probably handle most editing tasks and might be easier to layout and manage. Curious what other data structures people have used!
The other big reason to prefer a rope is that the worst case complexity is excellent. Basically all incremental operations are O(log n). With an "array of paragraphs" you get various pathological performance cases such as a huge number of small paragraphs or one very big one.
A good rope implementation is not trivial, but when done right it hides its internal complexity from the layer above. And it's a solved problem. There are at least two or three solid rope crates for Rust (just to pick the language I'm most familiar with), and will likely be more, as people find it fun to implement.
BTW, with any of these tree-based structures (like rope) you can store other meta-data in the the headers to make a fast index. For example, I would put a newline count in the rope headers, to make find a particular line a fast operation.
https://raphlinus.github.io/xi/2020/06/27/xi-retrospective.h...
Which points to https://xi-editor.io/docs/rope_science_00.html
Gap buffer was appealing on really slow machines, where you are counting cycles on each key-press. If the gap is at the right position, the cycle count is very low. But you can probably do the same even with a tree-structure: you need to keep a pointer to the leaf in the abstract pointer used for the cursor.
Also I would tie in the undo system to the data structure if possible. Rope does this with copy-on-write. Every version of the file could be a different top-node, and most middle and leaf nodes would be shared between revisions.
[1]: http://aosabook.org/en/index.html [2]: http://aosabook.org/en/eclipse.html
https://github.com/antirez/kilo
Even I could understand this one pretty well and that's no small matter.
Fair warning though, it's a fairly hard book to read. For a lighter, more fun intro to design patterns in particular, I always recommend Game Programming Patterns [2]
[1] https://www.amazon.com/Design-Patterns-Elements-Reusable-Obj...
[2] https://gameprogrammingpatterns.com/contents.html
This made selecting text quite hard. So I gave up and just put the whole thing into an array. It made everything a lot easier.
There are a few weird design decisions especially in swing, but overall it's very easy to read and understand.
https://sourceforge.net/p/joe-editor/mercurial/ci/default/tr...
Less does almost everything an "editor" does, at least visually, except change text. It pages through text, forward and backward, line by line, it handles lines that are too long, tab expansion, it searches, even has an extended command set. (Can less do syntax coloring?)
It also handles files too big for memory. These are all editor problems. Mind its solutions may not be optimized for an editor, but it's certainly smaller.
Today, modern machines "suffer" from "too much" performance which actually frees you from not having to worry so much about the actual backing store, especially early on. Do you really intend to be editing a 2GB file? Honestly, how big is an average text file? And how many billion cycles per second does a modern CPU handle? Sucking the entire file in to RAM, and just pushing stuff around with block moves will take you very far on a modern machine. Not that you should not look at the other data structures (there are many), but you don't have to start there, depending on where your interest lies.
Also consider hunting down the book "Software Tools". There's two editions, the original and "Software Tools in Pascal". It's by Kernighan and Plauger. They go through in detail and write a version of the 'ed' line editor.
And if you really want to work on an editor, the CP/M world would love a new one. There, it's all about efficiency.
I don't know about most people, but I deal with such files (usually JSON) on a weekly basis. It's surely one of the things that makes implementing text editors tricky.
And I regulary work with JSON files the size of some MB, which already puts some editors into a real struggle.
Out of curiosity, why do you have so big files? (A whole DB as a json file?) And what editor do you use for them?
More like a whole database table as a JSON file - I split the whole database export into tables using `jq` (an export from Firebase Realtime Database). I generally use sublime text to open them, it's quite happy with anything that will fit in RAM. For very large file it just shows a load bar while it loads it.
It was vital for exploring the shape of our data during a data migration to Postgres as our data was not very regular in shape and firebase's querying capabilities are pretty limited.
I, too, have dealt with huge files. My primary large file use case for vim is as an interactive grep, opening files, then just performing iterative filters reducing the file to something "manageable". If the file is too big, I might resort to raw streaming filters to temp files before going all vim on it (even vim has issues with huge files -- huge files are issues all their own).
But it's more a matter of pragmatism as to how far one wants to take a pet project like this. There's a curve of diminishing return depending on what someone wants from such a thing.
A single RAM buffer is a bad idea, to be sure, but raw horsepower of modern systems and CPUs cover up a lot of bad ideas. Simply the idea that you COULD mmap or even malloc a 2G buffer to suck the file in, and it would WORK, is enough to make ones teeth itch. I remember long a ago an article from someone encountering an early workstation with 1G of RAM, and the worlds it opened up. We have come far from those days.
If the OP is interested in buffer mechanics, then starting with an API backed by a simple buffer goes a long way. If they're interested in screen painting, window management, etc, then the RAM buffer may be all they need. Otherwise, they can work on replacing their back end with all of the assorted structures folks have mentioned, see what they like best, as they all have tradeoffs.
They have a well architected model, including plugins to extend functionality, see https://tiptap.dev/ which is built ontop of Prosemirror
bonus: The author talks about collaborative editing here: https://marijnhaverbeke.nl/blog/collaborative-editing.html
- https://arctype.com/blog/sql-query-editor-switch/
- https://arctype.com/blog/indexeddb-localstorage/
Disclaimer: I wrote the 2nd one. My general takeaway is that it gets interesting quickly as the amount of text edited increases.