github.com/aretext/aretext@v1.3.0/state/undo.go (about)

     1  package state
     2  
     3  import (
     4  	"log"
     5  
     6  	"github.com/aretext/aretext/undo"
     7  )
     8  
     9  // BeginUndoEntry begins a new undo entry.
    10  // This should be called before tracking any undo operations.
    11  func BeginUndoEntry(state *EditorState) {
    12  	if state.macroState.isReplayingUserMacro {
    13  		log.Printf("Skip begin undo entry because we're replaying a user macro\n")
    14  		return
    15  	}
    16  
    17  	log.Printf("Begin undo entry\n")
    18  	buffer := state.documentBuffer
    19  	buffer.undoLog.BeginEntry(buffer.cursor.position)
    20  }
    21  
    22  // CommitUndoEntry commits the current undo entry.
    23  // This should be called after completing an action that can be undone.
    24  func CommitUndoEntry(state *EditorState) {
    25  	if state.macroState.isReplayingUserMacro {
    26  		log.Printf("Skip commit undo entry because we're replaying a user macro\n")
    27  		return
    28  	}
    29  
    30  	log.Printf("Commit undo entry\n")
    31  	buffer := state.documentBuffer
    32  	buffer.undoLog.CommitEntry(buffer.cursor.position)
    33  }
    34  
    35  // Undo returns the document to its state at the last undo entry.
    36  func Undo(state *EditorState) {
    37  	hasEntry, undoOps, cursor := state.documentBuffer.undoLog.UndoToLastCommitted()
    38  	if !hasEntry {
    39  		return
    40  	}
    41  
    42  	for _, op := range undoOps {
    43  		log.Printf("Undo operation: %#v\n", op)
    44  		if err := applyOpFromUndoLog(state, op); err != nil {
    45  			log.Printf("Could not apply undo op %v: %v\n", op, err)
    46  			continue
    47  		}
    48  	}
    49  
    50  	MoveCursor(state, func(LocatorParams) uint64 {
    51  		return cursor
    52  	})
    53  }
    54  
    55  // Redo reverses the last undo operation.
    56  func Redo(state *EditorState) {
    57  	hasEntry, redoOps, cursor := state.documentBuffer.undoLog.RedoToNextCommitted()
    58  	if !hasEntry {
    59  		return
    60  	}
    61  
    62  	for _, op := range redoOps {
    63  		log.Printf("Redo operation: %#v\n", op)
    64  		if err := applyOpFromUndoLog(state, op); err != nil {
    65  			log.Printf("Could not apply redo op %v: %v\n", op, err)
    66  			continue
    67  		}
    68  	}
    69  
    70  	MoveCursor(state, func(LocatorParams) uint64 {
    71  		return cursor
    72  	})
    73  }
    74  
    75  func applyOpFromUndoLog(state *EditorState, op undo.Op) error {
    76  	pos := op.Position()
    77  	if s := op.TextToInsert(); len(s) > 0 {
    78  		return insertTextAtPosition(state, s, pos, false)
    79  	} else if n := op.NumRunesToDelete(); n > 0 {
    80  		deleteRunes(state, pos, uint64(n), false)
    81  	}
    82  	return nil
    83  }