Hacker News new | past | comments | ask | show | jobs | submit login

> If I was 10x faster yet it would have been 10 hours. That's a long plane ride. Even with a full-time job I would still be able to squeeze in a couple of text editor sized projects every month. I would be able to learn so many new things.

I see a dilemma here. Nobody, not even 10x faster than the author, writes a full-fledged text editor in 10 hours. You can create something interesting that does text editing in 10 hours (or 100), but it's mostly going to be a learning exercise. You won't have created a piece of software that is of any value to anyone but yourself.

So the dilemma involves the tension between rapidly speeding through many interesting "efforts" that result in nothing of any use to anyone, but lots of learning value to the programmer; or spending much, much more time creating software that is genuinely useful to people who are not programmers, but risking getting stuck in a given language, problem domain or project and not learning as much.

I made my bed - I opted for 21+ years focused on a single project, but I was lucky in that it spanned everything from kernel-side stuff to hard-realtime to UX and I felt I'm still learning new stuff even today.




> I see a dilemma here. Nobody, not even 10x faster than the author, writes a full-fledged text editor in 10 hours. You can create something interesting that does text editing in 10 hours (or 100), but it's mostly going to be a learning exercise. You won't have created a piece of software that is of any value to anyone but yourself.

You could if you had enough components to assemble the text editor from.


I could stick a GtkTextView into a GtkWindow and run it inside GtkApplication, sure.

That's not what I mean, and I don't think it's what the author of TFA means, by "write a text editor".


The 1000000x solution: <textarea></textarea> (this is me agreeing with you)


hmm I prob could make something kind of like a text editor in win32 fairly quickly as I can think of about a dozen built in calls that would make it work. Would it be full featured? Not much but it would do the very basics (cut/paste/save/read/edit). But that is because I know the system pretty well. If you dropped me into some other system it would take me a decent amount of time.


What you're describing is precisely what I mean: "something that would do the very basics".

Sure, I could cook one of those up, probably in less than 10 hours. But that's all it would do, and all I'd have done is learnt a few things. If I stopped right there, that's the only outcome: me learning some stuff.

Presumably at some point, the learning needs to be applied to something that is actually useful?


Almost all projects start that way as some small learning project. You usually do not build complete applications in 1 day. You usually lean heavy on existing libs or chunks of code you already learned somewhere else. That is what that sort of thing is for. In my 26 years doing this most of what I have written has been thrown away. There may still be some bits here and there living on but I doubt it. Yet at one point all of that code had a use and did it well. That use was me using that knowledge to get things done. Those prototype projects do a lot of that sort of thing. If I wanted to make an scala version of my 'basic editor' it would probably take me at least a week of digging through docs and trying things. But in another realm I can bash it out in a couple of hours. My point was your domain knowledge is what makes you a better developer.


Ant's Editor, Anthony Howe's entry to IOCCC '91, surely took him longer than 10 hours to write; David A. Wheeler's "SLOCCount" estimates about 0.65 person-months (because it's 289 lines of code), which is roughly 120 hours. In its unobfuscated form, it's 5065 characters of C, including comments, and not including the curses implementation it runs on. It's a vi clone that's complete enough to use for real work; you could reasonably argue that it is not "of value to anyone" because there are other editors available that are more featureful that can run anywhere it runs. It lacks, for example, yank, put, and undo. But it's definitely featureful enough to use when you don't have anything else.

If you type 90 words per minute of English, which is a speed that most people reach with a little practice, you can almost certainly type C at 45 words per minute, which is 270 characters per minute, 4.5 characters per second. (Jamie's 500 characters per minute is obviously higher than this, but I think he's a faster typist than most.) That would allow you to type in the Ant's Editor program in about 20 minutes, if you were just typing, not having to figure anything out.

20 minutes is shorter than 10 hours. Like, 30 times shorter. If you had everything totally clear in your mind, you could write 30 times that much code in 10 hours.

Now, is it plausible that somebody could write a whole usable text editor without having to figure anything out, so that their typing speed was the main limitation? Maybe if they'd written a lot of text editors previously. I'm skeptical, having spent half an hour getting binary search right last week, but then, there are much better programmers than me out there. (I still find that SLOCCount systematically overestimates the effort required for things; the calculator program with a generic numerical solver I mentioned here a couple of weeks ago in another comment was 261 lines of Python and took me 12 hours, and SLOCCount estimated it at 0.59 person-months, which would be 100 hours.)

I think writing things in very high-level languages like Python instead of C helps a bit, too. Not an order of magnitude, but maybe 2-5x, especially for small projects like these. I wrote a text editor on an iPaq in Python on my honeymoon.

So, while I agree that you're almost surely not going to write a text editor that will steal users from Vim, VS Code, or Emacs in 10 hours, I do think you can write a text editor in 10 hours. You could probably write a significantly more full-featured editor than ae.

Surely the optimal amount of effort to spend on such "learning efforts", which are expected to teach you things but not produce a program for you to use, is neither 0% nor 100%.


I don't really track what's available in python (or equivalent) repositories/libraries/package managers. However, I'd wager that there isn't an efficient representation of text for editing available in the way that Emacs or vi and its cousins contain. By that I mean something where you open a 12MB file, insert a single character at 8 random places and not have the data structures fall over.

After several decades of different people working on text editing, we now have some fairly good ideas about how to do this efficiently, but they are (a) non-obvious (b) not the sort of thing I'd expect to be trivially available in high-level-language-of-the-day. My expectations have been known to be wrong, however.

And yes, missing undo in a text editor makes it effectively dead in the water.


ae just used a gap buffer, same as GNU Emacs. If you move your insertion/deletion point from one end of a 12MB file to the other, you have to copy 12 MB across the gap, which takes about 4.1 milliseconds on this laptop, which is not ideal but plenty fast enough for keystroke response. Not terribly difficult to do with Numpy, I think. But with gap buffers you have to store your undo log in the form of an edit list or something.

(If you just keep your buffer in a Python string, you incur the 4.1-millisecond cost every time you insert a character near the beginning of the 12-MB string, possibly twice, and you need enough memory for multiple copies of the buffer. The gap buffer saves you this time cost except when you're moving the insertion point or you run out of gap, and keeps your space cost limited to slightly more than enough to hold the text itself.)

In a garbage-collected language on a modern machine (meaning, lots of RAM) I'd be tempted to use ropes, since they make undo trivial. Here's an implementation of ropes I wrote in 45 minutes and 45 lines of code just now, which seems to more or less work, though I'm sure I'm overlooking a few things:

    #!/usr/bin/python3
    from collections import namedtuple
    from functools import cached_property  # 3.8 or later


    def as_rope(obj):
        return obj if isinstance(obj, Rope) else Leaf(obj)


    class Rope:
        def __add__(self, other):
            return Concat(self, as_rope(other))

        def __radd__(self, other):
            return as_rope(other) + self

        def __str__(self):
            return ''.join(self.walk())


    class Leaf(Rope, namedtuple("Leaf", ('s',))):
        def __getitem__(self, slice):
            return Leaf(self.s[slice])

        def __len__(self):
            return len(self.s)

        def walk(self):
            yield self.s


    class Concat(Rope, namedtuple("Concat", ('a', 'b'))):
        def __len__(self):
            return self.len

        @cached_property
        def len(self):
            return len(self.a) + len(self.b)

        def walk(self):
            yield from self.a.walk()
            yield from self.b.walk()

        def __getitem__(self, sl):
            if sl.start is None:
                sl = slice(0, sl.stop)

            if sl.stop is None:
                sl = slice(sl.start, len(self))

            if sl.start < 0:
                sl = slice(len(self) + sl.start, sl.stop)
            if sl.stop < 0:
                sl = slice(sl.start, len(self) + sl.stop)

            # Important special case to stop recursion:
            if sl.start == 0 and sl.stop == len(self):
                return self

            a_len = len(self.a)
            if sl.start >= a_len:
                return self.b[sl.start - a_len : sl.stop - a_len]

            if sl.stop <= a_len:
                return self.a[sl]

            # At this point we know we need part of a and part of b.
            # Since slicing a leaf creates a Rope, we can blithely just do this:
            result = self.a[sl.start:] + self.b[:sl.stop - a_len]
            # Avoid making Concat nodes for lots of tiny leaves:
            return Leaf(str(result)) if len(result) < 32 else result
So then inserting a character, for example, is buf[:point] + c + buf[point:], which just creates a couple of Concat nodes and a Leaf to hold c (plus slicing existing nodes if necessary); this takes about 30 microseconds, which is 150 times faster than the brute-force string-copying solution for a 12-megabyte buffer. You need slightly more code than this for a robust editor because your trees get unbalanced, a problem with many well-known solutions.

Syntax highlighting, markers that move when text is inserted, etc., do imply more effort, but, again, there are well-known solutions to these problems. And an adequate redisplay is no longer the major research effort that it was 37 years ago.

So, while it's true that the data structures you need for a reliably responsive text editor aren't trivially available in Python, or Lua, or JS, I think you can just write them. I wrote the above code at about 6 words per minute because there were a lot of things about ropes (and about Python) that I wasn't clear about and had to figure out in the process; surely I could have written it 2-5 times as fast if I knew what I were doing.

If you're interested in learning about this stuff, Finseth's book is the classic, and Raph Levien has blogged a bunch of really nice up-to-date stuff about his rope-based editor Xi, which he wrote in Rust.


https://xi-editor.io/docs/rope_science_00.html is Levien's series about ropes for use in text editors.


(The other comment about the solver was https://news.ycombinator.com/item?id=28660097.)


> I wrote a text editor on an iPaq in Python on my honeymoon.

Correction: a Zaurus.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: