Build Undo/RedoStep 3 of 5

The Redo Stack

Step 3: The Redo Stack

Redo needs a second stack. When you undo a command, push it onto a redo stack; redo pops it back and re-executes it. The catch every editor gets right: doing a new action clears the redo history, because you have branched away from that future.

do and undo already maintain the redo stack. Implement redo.

  • redo(): pop the most recently undone command, re-execute it, and push it back onto the undo stack; no-op if there is nothing to redo
Hints
Starter code
class Document:
    def __init__(self, text=""):
        self.text = text


class Command:
    def execute(self, doc):
        raise NotImplementedError

    def undo(self, doc):
        raise NotImplementedError


class Insert(Command):
    def __init__(self, pos, text):
        self.pos = pos
        self.text = text

    def execute(self, doc):
        doc.text = doc.text[:self.pos] + self.text + doc.text[self.pos:]

    def undo(self, doc):
        doc.text = doc.text[:self.pos] + doc.text[self.pos + len(self.text):]


class Editor:
    def __init__(self, text=""):
        self.doc = Document(text)
        self._undo_stack = []
        self._redo_stack = []

    def do(self, command):
        command.execute(self.doc)
        self._undo_stack.append(command)
        self._redo_stack.clear()          # a new action invalidates the redo future

    def undo(self):
        if self._undo_stack:
            command = self._undo_stack.pop()
            command.undo(self.doc)
            self._redo_stack.append(command)

    def redo(self):
        """Re-apply the most recently undone command."""
        # TODO: mirror undo in the other direction. Take the most recently undone
        #   command off the top of self._redo_stack, run it forward against
        #   self.doc, and move it back onto self._undo_stack so it can be undone
        #   again. With an empty redo stack this does nothing at all.
        pass

    @property
    def text(self):
        return self.doc.text
Write it on a laptop

The editor and the test runner need a wide screen. Open this page on a desktop browser and your progress will be waiting.