โ Final Challenge
โบ duck โ a Terminal Text Editor
100 ptsAssembly time. Every layer you've built converges into one program โ
call it duck โ that opens a file in a terminal, edits it, and
saves it back. The layering you'll wire together, bottom to top:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
output โโโโค editor_render frame -> escape sequences โ
โ editor_scroll viewport invariant โ
โ cx_to_rx tabs -> screen columns โ
โ format_status_bar โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
state โ struct editor lines, cursor, dirty โ
โ insert/delete/newline/move/open/save โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
input โโโบโ editor_feed_input bytes -> keys -> actions โ
โ key_decode escape-sequence grammar โ
โ editor_handle_key dispatch โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
The starter provides the editing core and file I/O (reference versions of your earlier work โ swap in your own; they're yours now) plus the abuf. You bring three of your solutions and write two integration functions:
Paste in (from your previous challenges): key_decode
(parse-keys), editor_handle_key (main-loop-impl),
format_status_bar (status-line-impl).
Write new:
editor_render(e, ab) โ serialize one complete frame into the
abuf, exactly this recipe:
- Call
editor_scroll(e)(also yours to write โ the two-axis invariant from the scrolling challenge, using render columns). \x1b[?25l\x1b[Hโ hide cursor, home.- For each of the
screen_rowstext rows: the visible slice of file rowrowoff + iโ render columns[coloff, coloff + screen_cols)with tabs expanded toTABSTOP-column stops โ or a single~for rows past the end of the file; then\x1b[Kand\r\n. - The status bar:
\x1b[7m, thenformat_status_bar(...)at exactlyscreen_colswide, then\x1b[m. - Park the terminal cursor on the editor cursor:
\x1b[<cursor_row - rowoff + 1>;<rx - coloff + 1>H(1-based;rxfromcx_to_rx). \x1b[?25hโ show cursor.
editor_feed_input(e, buf, len) โ drain a chunk of raw input:
loop key_decode over the buffer; for each event, dispatch through
editor_handle_key; execute the actions (ED_SAVE โ
editor_save(e, e->filename); ED_FIND โ ignore here; ED_QUIT โ
stop processing and return ED_QUIT). When key_decode returns 0
(incomplete trailing sequence) or the buffer runs out, return
ED_CONTINUE. (A real loop buffers the incomplete tail and applies
the ESC timeout โ the DEMO main does; the graded function may
discard it.)
The tests run your editor headless through a full scripted session:
load a file from disk, page and arrow around it (checking the
rendered frames: viewport contents, ~ filler, status bar, cursor
parking), type into it, save with Ctrl+S, verify the bytes that
landed on disk, and quit with the dirty-buffer confirmation dance.
If the previous challenges pass, most of your work here is careful
plumbing โ which is the point: systems are assembled from parts
that were designed to be assembled.
When it's green, run the real thing:
cc -std=c17 -Wall -DDEMO solution.c -o duck
./duck some_file.txt
Raw mode, alternate screen, arrows, editing, Ctrl+S, Ctrl+Q. A
terminal program you built from read(2) up. Take the moment โ
then go read kilo's source and see how close you landed, and the
extended-reading list for where to go next (windows! syntax
highlighting! a pty of your own with a shell inside!).
Log in to submit a solution and earn points.