Harrison Stephan
All work

Systems Programming / Developer Tool

Terminal C IDE

A command-centric terminal editor and IDE built in C without ncurses, editor frameworks, or async and JSON libraries.

Proof of C systems work across terminal I/O, rendering, editor state, process execution, and tests.

01 / Problem

The project explores what an editor requires below the visible text surface: terminal input, rendering, buffers, commands, process capture, and diagnostics.

02 / What I built

Built a macOS-first C11 editor core with raw terminal input, virtual-screen rendering, editing, search, undo/redo, multi-buffer workspace state, sessions, build/run tasks, and diagnostic parsing.

System boundary

How the pieces connect.

Input becomes commands that mutate an active editor and buffer; a virtual screen captures the final frame before ANSI serialization writes it to the terminal.

  1. 01Raw input
  2. 02Commands
  3. 03Workspace / buffer
  4. 04Virtual screen
  5. 05ANSI serialization
  6. 06Terminal output

Engineering decision

Owning the rendering and state boundaries makes every editor behavior inspectable.

Tradeoff

Avoiding foundational editor and terminal libraries creates more implementation work and a macOS-first scope, but preserves direct control and learning value.

What happens next

Continue the documented Workbench milestone without presenting the project as a complete or cross-platform IDE.

Implemented proof

What can be evaluated today.

The repository proves an implemented editor core and workbench features, with CTest plus optional address and undefined-behavior sanitizers.

  1. 01

    Implements editing, C syntax highlighting, search, undo, redo, save, and reload.

  2. 02

    Maintains a multi-buffer workspace and deduplicates already-open paths.

  3. 03

    Runs build tasks through the host shell and captures output for diagnostic navigation.

Source proof

A decision visible in code.

Terminal C IDE / Csrc/workspace.c
  1. if (find_open_path(workspace, path, &existing)) {
  2. workspace->current = existing;
  3. return TIDE_OK;
  4. }
Line 2One path, one open buffer.

Opening an existing path selects its current buffer instead of creating a duplicate.

Next case study

Room Run Shooter