Start with an empty piece-table buffer that returns its text and end with a runnable editor that opens a file, moves and edits by keystroke, searches, saves, and undoes - all built on a real buffer technique, not an array of strings. Every lesson is one concrete spec with exact buffer, cursor, and frame values: split a piece on insert, join two lines on backspace, keep the cursor visible as you scroll, wrap a search past the last match, and undo a whole typed word in one step.
Over 40 lessons you build a working terminal text editor from scratch, on a real buffer technique rather than an array of strings. The core is a piece table: an immutable original buffer, an append-only add buffer, and a list of pieces that point into them, so every insert is a piece split and every delete is a piece trim - edits stay exact and cheap, and the same structure gives you undo for free. On top of the buffer you build a cursor model (row and column, clamped movement, word motions, and jumps to the document ends), editing operations expressed as buffer edits (insert a character, split a line on Enter, join lines on backspace and delete), a scrolling viewport that renders the visible screen as a frame string with tab expansion and a mapped on-screen cursor, file load and save with a dirty flag and a status line, incremental search that finds the next and previous match, wraps around, and replaces a match, and undo/redo built on the piece-table history with consecutive typing coalesced into a single step.
The editor state and its operations are modeled as a pure, testable core: the screen is a rendered frame string for a given size and the input is a fed keystroke sequence, so the whole editor is exercised deterministically without a real terminal. The capstone replays a full keystroke script - open a file, move around, edit, search, save - and asserts the exact final buffer and a rendered frame. The finalize pass then wraps this core in a real raw-mode terminal loop that reads keys and draws the screen, reusing the model unchanged and failing gracefully when it is not run on a terminal.
This is a teaching-grade editor built around the genuine piece-table design that editors like VS Code use: correct, cursor-accurate, and genuinely usable on a real file, but deliberately stopping short of what a production editor layers on top - syntax highlighting, multiple buffers and windows, Unicode grapheme handling, selections and clipboard, and configurable keybindings. What you finish with is the honest core all of those are built around.
Every editor is built around one thing - a buffer that holds the text you are editing. Today you create the smallest possible buffer so the surface the whole project grows on exists from day one.
Create a buffer from some initial text whose Text and Len report exactly what it holds.
A text editor is, underneath everything, a thing that holds a sequence of
characters and lets you change it. Before cursors, screens, or files matter, that
sequence has to exist as something you can construct and read back. Today the
buffer just wraps the original text it was created with, and Text() hands it
straight back.
Keeping it this simple pins the contract the rest of the project leans on: a
buffer is created from some starting text, Text() returns the whole thing, and
Len() reports how many bytes it holds. The clever internal representation - the
piece table that makes edits fast and exact - arrives next lesson, but its public
face is exactly this: give me the text, tell me how long it is.
// the whole editor grows around this typetype Buffer struct { original string }func New(text string) *Buffer { return &Buffer{original: text} }func (b *Buffer) Text() string { return b.original }func (b *Buffer) Len() int { return len(b.original) }
A real, usable terminal text editor built entirely on the piece-table model the lessons construct - it opens a file (or an empty buffer), takes keystrokes through a raw-mode loop, moves and edits with a clamped cursor, scrolls a tab-aware viewport, searches with wrap-around, saves with a dirty-flag guard, and undoes and redoes with coalesced typing, failing gracefully when it is not run on a terminal; a few edges are deliberately left thin - replace is not yet undoable, there is no live resize repaint, and word-wise and go-to-line motions are built into the model but not bound to keys.
A step-by-step booklet that builds antirez's kilo editor in C - raw mode, the refresh loop, and keypress handling. The clearest guide to the terminal layer this project defers to its finalize pass.
A complete text editor in about 1000 lines of C, no dependencies. The reference for how small a genuinely usable editor can be.
The book on editor internals: buffer representations (gap buffers, linked lines, piece tables), the redisplay problem, and command dispatch - the theory behind every chapter here.
How VS Code replaced its line-array buffer with a piece table (a balanced piece tree) for speed and memory - the modern production case for the structure this project builds.
The survey that compares the array, gap buffer, linked list, piece table, and rope for an editor buffer - why the piece table is a strong default and where each alternative wins.
A short, well-illustrated walkthrough of the piece-table structure - original and add buffers and the piece list - and how insert and delete split pieces, exactly the model chapter one builds.