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:
- Model editor modes as explicit states with valid transitions.
- Implement an input dispatch loop that changes behavior by state.
- Maintain invariants (cursor bounds, buffer integrity) across transitions.
- 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
- Mode system: Explicit state variable and transitions on
i,Esc,:. - Input loop: Keypress-driven actions that depend on current mode.
- Buffer model: Editable text buffer with cursor position.
- 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
- Read keypress.
- Switch on
state.mode. - 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:
- Terminal raw mode
- Disable line buffering and echo
- State transitions
- Mode change rules and invariants
- Cursor bounds
- Prevent cursor from leaving buffer
5.5 Questions to Guide Your Design
- How will you display the current mode?
- How do you handle invalid keys in each mode?
- 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
- Why should modes be explicit state?
- What are the invariants in a text editor?
- 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
iandEsc.
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:
- Raw terminal mode.
- Cursor movement.
Checkpoint: Arrow keys move cursor safely.
Phase 2: Core Functionality (4-5 days)
Goals:
- Add INSERT and COMMAND modes.
Tasks:
- Insert text into buffer.
- Parse simple commands.
Checkpoint: Can edit and save a file.
Phase 3: Polish & Edge Cases (2-3 days)
Goals:
- Robustness and UI clarity.
Tasks:
- Status bar with mode.
- 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
ienters INSERT,Escreturns NORMAL.:wqsaves and exits.- 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.
9.2 Related Open Source Projects
- 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.
10.4 Related Projects in This Series
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.