15 - Ejemplo práctico 6: mini editor con undo/redo

15.1 Objetivo

Crear un editor de texto de consola que permita agregar líneas, borrarlas y deshacer/rehacer operaciones usando pilas. Esta práctica ilustra cómo los editores mantienen bitácoras de cambios.

15.2 Operaciones

Comandos soportados:

  • ADD <texto>: agrega una línea al final.
  • DEL: elimina la última línea.
  • UNDO: revierte la última operación.
  • REDO: reaplica la operación revertida.
  • SHOW: imprime el documento.
  • EXIT: cierra el editor.

15.3 Estructura

  • Una pila para el historial (acciones realizadas).
  • Una pila para redo.
  • Un arreglo dinámico o lista para el documento actual.

15.4 Casos especiales

  • UNDO sobre un estado limpio no hace nada.
  • REDO se limpia cuando llega un comando nuevo (distinto de REDO).
  • Las líneas se almacenan con strdup; recuerda liberar memoria en cada paso.

15.5 Implementación en Python

class Editor:
  def __init__(self):
    self.lineas = []
    self.undo = []
    self.redo = []

  def add(self, texto):
    self.lineas.append(texto)
    self.undo.append(("ADD", texto))
    self.redo.clear()

  def delete(self):
    if not self.lineas:
      return "Nada para borrar"
    texto = self.lineas.pop()
    self.undo.append(("DEL", texto))
    self.redo.clear()
    return texto

  def mostrar(self):
    print("----- Documento -----")
    for i, linea in enumerate(self.lineas, 1):
      print(f"{i}: {linea}")

  def do_undo(self):
    if not self.undo:
      return "Nada que deshacer"
    op, texto = self.undo.pop()
    if op == "ADD":
      borrado = self.lineas.pop() if self.lineas else None
      self.redo.append(("ADD", texto))
      return f"Deshecho ADD: {borrado}"
    if op == "DEL":
      self.lineas.append(texto)
      self.redo.append(("DEL", texto))
      return f"Deshecho DEL: {texto}"

  def do_redo(self):
    if not self.redo:
      return "Nada que rehacer"
    op, texto = self.redo.pop()
    if op == "ADD":
      self.lineas.append(texto)
    elif op == "DEL" and self.lineas:
      self.lineas.pop()
    self.undo.append((op, texto))
    return f"Rehecho {op}: {texto}"


if __name__ == "__main__":
  ed = Editor()
  ed.add("Linea 1")
  ed.add("Linea 2")
  ed.mostrar()
  print(ed.delete())
  print(ed.do_undo())
  print(ed.do_redo())
  ed.add("Linea 3")
  ed.mostrar()

15.6 Mejoras sugeridas

  • Persistir el documento para recuperar sesiones.
  • Agregar comandos como INSERT <posición> y REPLACE con su correspondiente historial.
  • Implementar un tope para las pilas de undo/redo, como hacen los editores reales.