sc-im
What it is
Section titled “What it is”sc-im (the spreadsheet calculator, improved — a modern fork of the venerable sc) is a full vim-keyboard spreadsheet that lives in the terminal. It renders a grid up to 65,536 rows × 702 columns (expandable to ~1M rows) with column-letter / row-number headers and AB12-style cell addressing, an undo/redo stack, and a command-line input line at the bottom of the screen (the : line) that is the canonical “do something structural” affordance. It is C-cored and ncurses-rendered, with the parser generated by bison/yacc. Crucially, it embeds Lua as a scripting layer that can read and write cells, define new functions, and fire on cell read/write triggers.
For KN-86 this is the most architecturally instructive entry in the cluster: it shows, in a real shipping C codebase, exactly how an embedded interpreter is bolted onto a cell-grid runtime — which is the precise shape of the KN-86 problem (Fe VM bolted onto a cell runtime per the nOSh/cartridge architecture).
Deckline relevance
Section titled “Deckline relevance”- The grid as a foundation primitive. sc-im’s column-header / row-number / cell-address layout is the canonical spreadsheet grid, and it’s the IA reference for any KN-86 cart that wants addressable cells. The 80×25 KN-86 grid (per CLAUDE.md Canonical Hardware Specification) is far smaller than sc-im’s 702-column field, so the lesson isn’t the scale — it’s the addressing model: every cell has a stable
colrowcoordinate, and the scripting layer reaches cells by coordinate. KN-86’s Lisp paradigm cell model is conceptually adjacent (cells as addressable, scriptable units). - The command-line buffer pattern (the
:line). sc-im reserves the bottom screen line for command entry —:opens it, you type a structural command, Enter executes. This is the single most-borrowable UI idea here for KN-86: it’s exactly the REPL + Row-24 advertisement pattern the runtime already commits to. The KN-86 TERM key opening a bottom-of-screen command line is the sc-im:line in a different costume. Validates the existing Row-24-as-command-surface decision against a mature precedent. - Vim cell navigation.
hjklto move,goab12to jump to a named cell,yy/pyank/paste,vto select a range withhjkl,e/Eto edit numeric/string,ir/ic/dr/dcto insert/delete rows/columns. The “type a cell address to teleport the cursor” idiom (go+ address) is a good fit for KN-86’s small key budget — addressing by name beats arrow-key marathons across a grid. - Undo/redo stack as a first-class subsystem. sc-im’s
u/Ctrl+rundo/redo is a genuine command-history stack, not a single-level undo. For KN-86 carts that mutate deck/cart state interactively (any editor-grade cart, nEmacs), a real undo stack is the right model. The nEmacs structural editor (ADR-0008) should treat sc-im’s undo as the floor, not the ceiling. - GNUPlot bridge as the “escape to a richer renderer” pattern. sc-im shells out to GNUPlot for charts rather than rendering them itself. Not directly portable (KN-86 is self-contained, single-display, no external plotter), but the principle — a grid app delegating visualization to a specialized renderer — is worth noting; on KN-86 the “specialized renderer” would be a NoshAPI sparkline/bar primitive (see logradar) the cart calls, not an external process.
Single-color adaptation
Section titled “Single-color adaptation”sc-im ships 256-color cells and RGB cell formatting (bold/italic/underline + custom colors via the scimrc config), and that’s the part that does not survive the KN-86 monochrome reframe. What carries the structure is everything else:
- Cell selection / cursor → inversion, exactly as in csvlens. The current cell and any
v-selected range render inverted (black-on-amber). - Cell emphasis (was color/bold) → glyph weight + brackets. Where sc-im uses a colored or bold cell to flag a value, KN-86 substitutes the box-drawing/density vocabulary: a bracketed
[ ]cell, an inverted cell, or — for magnitude — a block-character bar inside the cell (▁▂▃▄▅▆▇█) rather than a hue. This is the general single-color move: color-as-category becomes glyph-as-category; color-as-magnitude becomes block-density-as-magnitude. - Column/row headers → positional + box-drawing. Headers are already positional (top row, left column) and don’t depend on color; a
│/─box-drawing frame separates header from body. The current-column/current-row header can invert to show cursor position. - The
:command line → Row 24. Already monochrome by nature — it’s a text line.
The grid structure (addressing, headers, selection, command line) is entirely color-independent in sc-im; only the cell decoration layer leans on color, and that layer maps cleanly onto KN-86’s inversion + block-density + box-drawing toolkit.
LISP-integration angle — the centerpiece of this entry
Section titled “LISP-integration angle — the centerpiece of this entry”sc-im’s Lua embedding is a near-perfect analog for KN-86’s Fe-VM-drives-the-cart architecture, and the API surface is worth studying directly:
- Script invocation from a cell:
@lua("{script}", {i})runs a Lua script; the integer flag controls whether the cell joins the dependency graph (i.e. whether it recomputes when its inputs change). Two globals{r}/{c}are auto-injected so the script knows which cell called it. This is the exact shape of a Fe-VM FFI call from cart Lisp — a cell handler invoking a VM function with context injected. - The cell-access API the interpreter is handed:
sc.lgetnum(c,r)/sc.lsetnum(c,r,val)(read/write numbers),sc.lgetstr/sc.lsetstr(strings),sc.lsetform(c,r,str)(set a formula),sc.sc(str)(send a raw command to the parser),sc.a2colrow("c5")/sc.colrow2a(c,r)(address↔coordinate conversion),sc.maxcols()/sc.maxrows()/sc.curcol()/sc.currow()(grid introspection). This is a tight, well-scoped FFI: the interpreter never touches ncurses or the render loop — it only reads/writes the model and asks the parser to do things. This is precisely the discipline KN-86’s NoshAPI FFI (ADR-0005, 54 primitives) already follows — Lisp carts touch the model and call render primitives, never the C render loop directly. sc-im is external validation that this split is the right one. - Triggers — events that fire scripts:
:trigger a5 "mode=R type=LUA file=trg.lua function=trg"registerstrg()to run whenever cella5is read (mode=R), written (W), or both (B). This is a clean cell-as-event-source model: the grid runtime fires named handlers on cell lifecycle events, and the handler is a script function. KN-86’s cell handler dispatch (the tagged union of C-fnptr-or-Lisp-lambda described in the emulator architecture) is the same idea — sc-im’s trigger system is a concrete reference for registering Lisp handlers against cell read/write events.
The single takeaway: sc-im proves the embedded-interpreter-drives-a-grid pattern in production, with a model-only FFI and event-triggered handlers — map @lua→Fe FFI call, sc.l* cell API→NoshAPI cell primitives, and :trigger→Lisp-lambda cell handlers. It’s the strongest architectural precedent in Batch 8 for the cart runtime.
- Batch 8. The cluster’s architecture anchor — read this one for the Fe-VM integration lesson even if no spreadsheet cart ever ships.
- Cross-link csvlens.md — the read-only viewer counterpart (sc-im edits, csvlens views).
- Cross-link sheetsui.md — a Rust console spreadsheet explicitly inspired by sc-im + vim; the modern restatement of this entry’s UI.
- Cross-link fe.md — the KN-86 VM that plays Lua’s role here; sc-im’s
sc.l*API is the model for what Fe carts get handed. - Cross-link l123.md / visicalc-archive.md for the spreadsheet lineage sc-im descends from.