// One-line editor. Would a female editor have been an editress long ago? // (One line of buffer, not of implementation code.) // I was curious how small a minimal text editor would be. This // supports Emacs commands ^B, ^F, ^A, ^E, and backspace. It took 26 // minutes and 66 lines of code, and compiled for amd64 with GCC 9.4.0 // and -Os, 2780 bytes of code and 640 bytes of data. The edit() // function (45 of those lines of code) compiles down to 467 bytes of // machine code (126 instructions). This seems pretty bloated but it // does pretty much work. Compiled instead with // `arm-linux-gnueabi-gcc-10 -mcpu=cortex-m4 -Os -c` it's 386 bytes of // code; with `riscv64-linux-gnu-gcc-9 -Os -c` it's 638; after // linking, that grows to 2355 bytes of code and 684 of data. For the // AVR it's 838 bytes of code. #include #include #include #include #define CTRL(ch) ((ch) & 0x1f) void spew(char *s, int len) { int n = write(1, s, len); (void)n; } void edit() { char buf[256] = {0}; int cursor = 0, size = 0; for (;;) { int c = fgetc(stdin); switch(c) { case EOF: case CTRL('c'): case CTRL('x'): printf("\n"); return; case CTRL('h'): case 0x7f: if (cursor == 0) break; cursor--; size--; memmove(buf+cursor, buf+cursor+1, size-cursor); break; case CTRL('b'): if (cursor) cursor--; break; case CTRL('f'): if (cursor < size) cursor++; break; case CTRL('a'): cursor = 0; break; case CTRL('e'): cursor = size; break; default: if (size == sizeof(buf) || c < ' ') break; memmove(buf+cursor+1, buf+cursor, size-cursor); size++; buf[cursor++] = c; break; } spew("\r", 1); spew(buf, cursor); spew("\e[7m", 4); spew(cursor < size ? buf+cursor : " ", 1); spew("\e[0m", 4); if (cursor + 1 < size) spew(buf+cursor+1, size-cursor-1); spew(" ", 1); } } int main(int argc, char **argv) { // pretty lame since we don't restore int rv = system("stty cbreak -echo"); (void)rv; edit(); rv = system("stty sane"); (void)rv; return 0; }