← Back to scenarios
ScenarioCatalog DB

Text editor undo

Wrap text insertion operations in commands that can be executed and later undone from history.

Problem

A text editor must record user operations with enough information to reverse them later without coupling the history mechanism to individual editing operations.

Related patterns

Implementations

Command

TypeScriptApplication

Command in TypeScript

Encapsulates document actions as objects so an editor can execute, queue, and undo operations without knowing their implementation details.

TypeScript
interface Command {
  execute(): void;
  undo(): void;
}

class Document {
  private content = "";

  append(text: string) {
    this.content += text;
  }

  removeLast(count: number) {
    this.content = this.content.slice(0, -count);
  }

  print() {
    console.log(this.content);
  }
}

class AppendTextCommand implements Command {
  constructor(
    private readonly document: Document,
    private readonly text: string,
  ) {}

  execute() {
    this.document.append(this.text);
  }

  undo() {
    this.document.removeLast(this.text.length);
  }
}

class Editor {
  private readonly history: Command[] = [];

  run(command: Command) {
    command.execute();
    this.history.push(command);
  }

  undo() {
    this.history.pop()?.undo();
  }
}

const document = new Document();
const editor = new Editor();

editor.run(new AppendTextCommand(document, "Hello, "));
editor.run(new AppendTextCommand(document, "world!"));

document.print();

editor.undo();
document.print();

Associated technologies