Project 1: Modal Text Editor (Mini-Vim)

Build a small terminal text editor with explicit modes and state-driven input handling.

Quick Reference

Attribute Value
Difficulty Intermediate
Time Estimate 1-2 weeks
Language C
Prerequisites Terminal I/O basics, data structures
Key Topics State machines, input dispatch, invariants

1. Learning Objectives

By completing this project, you will:

  1. Model editor modes as explicit states with valid transitions.
  2. Implement an input dispatch loop that changes behavior by state.
  3. Maintain invariants (cursor bounds, buffer integrity) across transitions.
  4. Design error handling that preserves editor state.

2. Theoretical Foundation

2.1 Core Concepts

  • Explicit state: Editor mode is not implied; it is a variable that gates behavior.
  • Input dispatch: The same key means different actions depending on current state.
  • Invariant enforcement: Cursor and buffer must remain consistent after every command.

2.2 Why This Matters

Modal editors are a pure state machine. You will learn to reason about which inputs are legal in each state and how to prevent invalid transitions.

2.3 Historical Context / Background

Modal editing emerged with vi as a response to limited keyboards and bandwidth; it remains one of the clearest demonstrations of state-driven UX.

2.4 Common Misconceptions

  • “Mode can be inferred”: This leads to ambiguous behavior and bugs.
  • “All commands can be executed anytime”: Many must be rejected to preserve invariants.

3. Project Specification

3.1 What You Will Build

A terminal editor with at least three modes: NORMAL, INSERT, and COMMAND. It supports basic navigation, text insertion, and saving to a file.

3.2 Functional Requirements

  1. Mode system: Explicit state variable and transitions on i, Esc, :.
  2. Input loop: Keypress-driven actions that depend on current mode.
  3. Buffer model: Editable text buffer with cursor position.
  4. Commands: :w, :q, :wq.

3.3 Non-Functional Requirements

  • Reliability: Invalid keys must not corrupt state.
  • Usability: Visible mode indicator in status bar.
  • Performance: Efficient redraw for small files.

3.4 Example Usage / Output

NORMAL  file.txt  Ln 1, Col 1
(i) -> INSERT mode
ESC -> NORMAL mode
: -> COMMAND mode
:wq -> save and quit

3.5 Real World Outcome

You can open a file, edit text, save, and exit:

$ ./minivim notes.txt
[NORMAL] notes.txt
# press i, type text, ESC, :wq
[done] wrote notes.txt

4. Solution Architecture

4.1 High-Level Design

┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│ key input    │────▶│ state machine│────▶│ buffer ops   │
└──────────────┘     └──────────────┘     └──────────────┘

4.2 Key Components

Component Responsibility Key Decisions
State model Track editor mode Enum-based states
Input loop Dispatch by state Switch on mode
Buffer Store text and cursor Gap buffer or vector

4.3 Data Structures

typedef enum {
    MODE_NORMAL,
    MODE_INSERT,
    MODE_COMMAND
} EditorMode;

typedef struct {
    EditorMode mode;
    size_t cursor_row;
    size_t cursor_col;
} EditorState;

4.4 Algorithm Overview

Key Algorithm: Mode dispatch

  1. Read keypress.
  2. Switch on state.mode.
  3. Execute handler or reject.

Complexity Analysis:

  • Time: O(1) per keypress (excluding redraw).
  • Space: O(N) for buffer size.

5. Implementation Guide

5.1 Development Environment Setup

gcc --version

5.2 Project Structure

project-root/
├── src/
│   ├── main.c
│   ├── editor.c
│   ├── buffer.c
│   └── input.c
└── Makefile

5.3 The Core Question You’re Answering

“What state am I in, and which actions are legal right now?”

5.4 Concepts You Must Understand First

Stop and research these before coding:

  1. Terminal raw mode
    • Disable line buffering and echo
  2. State transitions
    • Mode change rules and invariants
  3. Cursor bounds
    • Prevent cursor from leaving buffer

5.5 Questions to Guide Your Design

  1. How will you display the current mode?
  2. How do you handle invalid keys in each mode?
  3. How will you implement file save in COMMAND mode?

5.6 Thinking Exercise

Design a new VISUAL mode. Which transitions are valid, and how does it change key behavior?

5.7 The Interview Questions They’ll Ask

  1. Why should modes be explicit state?
  2. What are the invariants in a text editor?
  3. How do you prevent invalid transitions?

5.8 Hints in Layers

Hint 1: Start with NORMAL only

  • Implement cursor movement first.

Hint 2: Add INSERT

  • Switch on i and Esc.

Hint 3: Add COMMAND

  • Parse :w, :q, :wq.

5.9 Books That Will Help

Topic Book Chapter
State machines “Design Patterns” State pattern
Terminal I/O “The Linux Programming Interface” Terminal chapters

5.10 Implementation Phases

Phase 1: Foundation (3-4 days)

Goals:

  • Create basic input loop and NORMAL mode.

Tasks:

  1. Raw terminal mode.
  2. Cursor movement.

Checkpoint: Arrow keys move cursor safely.

Phase 2: Core Functionality (4-5 days)

Goals:

  • Add INSERT and COMMAND modes.

Tasks:

  1. Insert text into buffer.
  2. Parse simple commands.

Checkpoint: Can edit and save a file.

Phase 3: Polish & Edge Cases (2-3 days)

Goals:

  • Robustness and UI clarity.

Tasks:

  1. Status bar with mode.
  2. Reject invalid commands safely.

Checkpoint: No crashes on random input.

5.11 Key Implementation Decisions

Decision Options Recommendation Rationale
Buffer type Gap buffer vs vector Vector first Simplicity
Mode handling Flags vs enum Enum Clear transitions

6. Testing Strategy

6.1 Test Categories

Category Purpose Examples
Mode transitions Valid/invalid keys i, ESC, :
Buffer integrity No corruption Insert/delete cycle
File I/O Save correctness :w writes file

6.2 Critical Test Cases

  1. i enters INSERT, Esc returns NORMAL.
  2. :wq saves and exits.
  3. Cursor never leaves buffer bounds.

6.3 Test Data

Short file, 3 lines

7. Common Pitfalls & Debugging

7.1 Frequent Mistakes

Pitfall Symptom Solution
No raw mode Input delayed Use termios
Missing bounds Cursor wraps incorrectly Clamp values
Mode confusion Wrong actions Centralize dispatch

7.2 Debugging Strategies

  • Log mode changes to stderr.
  • Add assertions for cursor bounds.

7.3 Performance Traps

Full screen redraw on every key can flicker; optimize later if needed.


8. Extensions & Challenges

8.1 Beginner Extensions

  • Add line numbers.

8.2 Intermediate Extensions

  • Implement search /.

8.3 Advanced Extensions

  • Add VISUAL selection mode.

9. Real-World Connections

9.1 Industry Applications

  • Text editors and IDEs are complex state machines.
  • Terminals rely on precise input state handling.
  • kilo: Minimal C text editor.
  • vim: Canonical modal editor.

9.3 Interview Relevance

  • Shows explicit state handling and control flow discipline.

10. Resources

10.1 Essential Reading

  • kilo tutorial for minimal editor architecture.
  • termios docs for raw input.

10.2 Video Resources

  • Search: “build a text editor in C”.

10.3 Tools & Documentation

  • termios: man termios.

11. Self-Assessment Checklist

11.1 Understanding

  • I can explain why mode is explicit state.
  • I can describe valid transitions.

11.2 Implementation

  • All modes work as designed.
  • File saves are correct.

11.3 Growth

  • I can apply state machines to other UIs.

12. Submission / Completion Criteria

Minimum Viable Completion:

  • NORMAL and INSERT modes with file save.

Full Completion:

  • COMMAND mode with :w, :q, :wq.

Excellence (Going Above & Beyond):

  • Add VISUAL mode and search.

This guide was generated from SPRINT_3_CONTROL_FLOW_STATE_PROJECTS.md. For the complete learning path, see the parent directory README.