I’ve started writing my own text editor. It wasn’t as much for any practical need, vim, emacs, joe, and other ones I’ve used have all been pretty positive. My main goal was to make myself work on something greater and more interesting, and not lose track of it.
Usage wise, it’s most similar to sam minus the graphical mode because gui is for losers. The structure of the code has probably been stolen from various places, I’ve focused on simplicity and making the components independent as much as possible.
It’s in a very primitive state but the most important components have taken their shape. So far the performance is questionable and it’s been sacrificed for architectural purity. It might change as development progresses.
The command language should feel familiar to someone who used sam or ed
before. A
command consists of a range specification followed by a command and its
argument(s). A range consists of 0, 1, or 2 addresses. Specifying no
addresses (i.e. specifying no range at all) means either the dot or the
whole buffer. A single address specifies the whole region that address
refers to, for example 1
selects the first line, from
beginning to end, while /re/
means the next match of the
regular expression. Two addresses select from the start of the first
address to the end of the second address. Leaving either address empty
always means the beginning / end of file.
The dot is something similar to a selection or a cursor in other
editors. It’s usually the text last manipulated. The dot can be 0 or
more bytes long, te isn’t tied conceptually to lines like
ed
.
I actually worked on this a fair bit while I didn’t touch these notes at all. I’m pretty satisfied with how far it’s gotten.
It supports all the basic editing functions, line addressing, even proper multiple buffers. I ported it to an arch linux vm and caught a few dumb bugs along the way, including one in a test for stralloc_cat or something.
The implementation of buffers is a single blob still, and most
functions think in terms of it. This model serves me well so far but it
chokes on some big files, such as /usr/share/dict/words
which interestingly ed handles just fine. I’ll need to look back at the
file reading code to see what’s the problem.
Before every change to the buffer would trigger line reindexing, now
only buffer_change()
does. All of that code is very ugly
and I’m never sure when looking at it whether it actually works or not.
Sure the tests pass, but did I write the tests right? Is there an edge
case I didn’t think of?
On the other hand, I’m happy at how it has matured. I could easily come back to it months, almost half a year after I last touched it and feel right at home. Adding more things requires very little effort. That’s really the best thing about this entire project, many of my ideeas about structuring programs turned out to be correct. The idea that with some foresight, careful thought and common sense experience one can avoid all the maintenance difficulties that apparently every program is doomed into is very unpopular these days, and te is by no means perfection in C sourcecode form. I just feel like this industry, and even some of the “hobbyists”, project their experiences of failed creations onto everything and claim that the very craft of programming is cursed by a very potent case of Murphy’s law instead of asking what decision made it go wrong and who made it.
Of course, there are things in te’s design that will need some
thinking. The build system as usual is my big holdup. It’s been very
compatible so far across mac and linux, and hopefully other bsd’s
(should there be some kind of travis ci thing? How much does that sort
of thing cost?). I’m thinking of adding regular expression support and
that is likely to introduce a new dependency into the mix, unless I go
with <regexp.h>
.
Handling SIGINT is another thing that right now just exits the program, probably the best thing all things considered.
I don’t have much time to dedicate to programming, especially not
something as ambitious as te. Next on the list is probably introducing
shell commands support, perhaps simple conditionals like sam’s
g//
command.