githubEdit

21. Design Text Editor

Difficulty: Hard Topics: Data Structures (Gap Buffer/Rope), Command Pattern, Flyweight Pattern Key Concepts: Gap Buffer, Rope, Piece Table, Command Pattern.

Phase 1: Requirements Gathering

Goals

  • Design the core engine of a text editor.

  • Support efficient text manipulation and undo/redo operations.

1. Who are the actors?

  • User: Types text, moves cursor, executes commands (copy/paste).

2. What are the must-have features? (Core)

  • Edit: Insert/Delete characters at cursor position.

  • Navigation: Move cursor (Arrows, Home, End).

  • History: Unlimited Undo/Redo.

  • Selection: Highlight text (optional but implied).

3. What are the constraints?

  • Latency: Typing must be instantaneous (<16ms).

  • Memory: Handle large files (GBs) without loading everything into RAM (if possible).


Phase 2: Use Cases

UC1: User Types Character

Actor: User Flow:

  1. User presses 'A'.

  2. System creates InsertCommand('A', cursor_pos).

  3. Command is executed (Buffer modified).

  4. Cursor moves forward.

  5. Command pushed to Undo Stack. Redo Stack cleared.

UC2: Undo Action

Actor: User Flow:

  1. User presses Ctrl+Z.

  2. System pops last command from Undo Stack.

  3. System calls cmd.undo().

  4. Command pushed to Redo Stack.

  5. UI refreshes.


Phase 3: Class Diagram

Step 1: Core Entities

  • TextEditor: Facade.

  • TextBuffer: The data structure holding the text.

  • Command: Interface for actions.

  • HistoryManager: Stack wrapper.

UML Diagram

spinner

Phase 4: Design Patterns

1. Command Pattern

  • Description: Encapsulates a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.

  • Why used: Crucial for Undo/Redo. Every action (Type 'A', Backspace, Paste) is a Command object stored in a stack. To Undo, we pop the command and call its inverse() method.

2. Flyweight Pattern

  • Description: Uses sharing to support large numbers of fine-grained objects efficiently.

  • Why used: A text editor renders thousands of characters. Instead of creating a heavy object for every 'a' on screen with its own font/color data, we share Glyph instances (Intrinsic state) and pass positions (Extrinsic state) at render time.

3. Gap Buffer (Data Structure Pattern)

  • Description: A dynamic array that allows O(1) insertions and deletions at a specific "gap" position.

  • Why used: Most edits happen at the cursor. A standard array requires O(N) shifting for every keystroke. A Gap Buffer moves the "empty space" to the cursor, making typing instantaneous.


Phase 5: Code Key Methods

Java Implementation (Command Pattern + List of Lines)


Phase 6: Discussion

Data Structure Choice

Q: "Why Gap Buffer over Array?"

  • A: "Gap Buffer makes insertions/deletions at the cursor $O(1)$. Array is $O(N)$ because you shift all subsequent characters. Gap Buffer is perfect for active editing (locality of reference)."

Handling Large Files

Q: "How to handle a 10GB file?"

  • A: "Use Piece Table or Rope. Also, Memory Mapping (mmap). Load only the viewport (what user sees) + a buffer zone into RAM. Don't read whole file."

Q: "How to search efficiently?"

  • A: "KMP Algorithm for pattern matching. If using Rope, search can be parallelized across sub-nodes."


SOLID Principles Checklist

  • S (Single Responsibility): TextBuffer manages state, Command manages action logic, History manages stacks.

  • O (Open/Closed): Add PasteCommand, SelectCommand easily.

  • L (Liskov Substitution): N/A.

  • I (Interface Segregation): N/A.

  • D (Dependency Inversion): CommandHistory expects Command interface.

Last updated