github.com/aretext/aretext@v1.3.0/state/undo_test.go (about) 1 package state 2 3 import ( 4 "testing" 5 6 "github.com/stretchr/testify/assert" 7 8 "github.com/aretext/aretext/clipboard" 9 "github.com/aretext/aretext/locate" 10 "github.com/aretext/aretext/syntax" 11 ) 12 13 func TestUndoAndRedo(t *testing.T) { 14 state := NewEditorState(100, 100, nil, nil) 15 16 // Make some edits with undo checkpoints. 17 BeginUndoEntry(state) 18 InsertRune(state, 'a') 19 InsertRune(state, 'b') 20 InsertRune(state, 'c') 21 CommitUndoEntry(state) 22 23 BeginUndoEntry(state) 24 InsertNewline(state) 25 InsertRune(state, 'd') 26 CommitUndoEntry(state) 27 28 BeginUndoEntry(state) 29 DeleteToPos(state, func(params LocatorParams) uint64 { 30 return locate.PrevCharInLine(params.TextTree, 1, false, params.CursorPos) 31 }, clipboard.PageDefault) 32 CommitUndoEntry(state) 33 34 // Verify state before undo. 35 assert.Equal(t, uint64(4), state.documentBuffer.cursor.position) 36 assert.Equal(t, "abc\n", state.documentBuffer.textTree.String()) 37 38 // Undo the deletion. 39 Undo(state) 40 assert.Equal(t, uint64(5), state.documentBuffer.cursor.position) 41 assert.Equal(t, "abc\nd", state.documentBuffer.textTree.String()) 42 43 // Undo the newline and insertion of 'd' 44 Undo(state) 45 assert.Equal(t, uint64(3), state.documentBuffer.cursor.position) 46 assert.Equal(t, "abc", state.documentBuffer.textTree.String()) 47 48 // Redo the newline and insertion of 'd' 49 Redo(state) 50 assert.Equal(t, uint64(5), state.documentBuffer.cursor.position) 51 assert.Equal(t, "abc\nd", state.documentBuffer.textTree.String()) 52 53 // Undo again. 54 Undo(state) 55 assert.Equal(t, uint64(3), state.documentBuffer.cursor.position) 56 assert.Equal(t, "abc", state.documentBuffer.textTree.String()) 57 58 // Undo last change. 59 Undo(state) 60 assert.Equal(t, uint64(0), state.documentBuffer.cursor.position) 61 assert.Equal(t, "", state.documentBuffer.textTree.String()) 62 } 63 64 func TestUndoDeleteLinesWithIndentation(t *testing.T) { 65 state := NewEditorState(100, 100, nil, nil) 66 67 // Insert some lines with indentation. 68 BeginUndoEntry(state) 69 InsertTab(state) 70 InsertRune(state, 'a') 71 InsertRune(state, 'b') 72 InsertNewline(state) 73 InsertTab(state) 74 InsertRune(state, 'c') 75 InsertNewline(state) 76 InsertRune(state, 'd') 77 CommitUndoEntry(state) 78 79 // Delete second-to-last line, which is indented. 80 BeginUndoEntry(state) 81 MoveCursor(state, func(p LocatorParams) uint64 { return locate.StartOfLineNum(p.TextTree, 1) }) 82 DeleteLines(state, func(p LocatorParams) uint64 { return p.CursorPos }, false, false, clipboard.PageDefault) 83 CommitUndoEntry(state) 84 85 // Verify state before undo. 86 assert.Equal(t, uint64(4), state.documentBuffer.cursor.position) 87 assert.Equal(t, "\tab\nd", state.documentBuffer.textTree.String()) 88 89 // Undo the deletion. 90 // Expect the cursor to land on the start of the restored line AFTER indentation. 91 Undo(state) 92 assert.Equal(t, uint64(8), state.documentBuffer.cursor.position) 93 assert.Equal(t, "\tab\n\tc\nd", state.documentBuffer.textTree.String()) 94 } 95 96 func TestUndoMultiByteUnicodeWithSyntaxHighlighting(t *testing.T) { 97 state := NewEditorState(100, 100, nil, nil) 98 SetSyntax(state, syntax.LanguageGo) 99 100 // Insert multi-byte UTF-8 runes. 101 BeginUndoEntry(state) 102 for _, r := range "丂丄丅丆丏 ¢ह€한" { 103 InsertRune(state, r) 104 } 105 CommitUndoEntry(state) 106 107 // This used to trigger a panic when retokenizing because the 108 // deleted rune count was incorrect. 109 Undo(state) 110 assert.Equal(t, "", state.documentBuffer.textTree.String()) 111 112 Redo(state) 113 assert.Equal(t, "丂丄丅丆丏 ¢ह€한", state.documentBuffer.textTree.String()) 114 } 115 116 func TestUnsavedChanges(t *testing.T) { 117 state := NewEditorState(100, 100, nil, nil) 118 119 // Initially no unsaved changes. 120 assert.False(t, state.documentBuffer.undoLog.HasUnsavedChanges()) 121 122 // Make some edits with undo checkpoints. 123 BeginUndoEntry(state) 124 InsertRune(state, 'a') 125 InsertRune(state, 'b') 126 InsertRune(state, 'c') 127 CommitUndoEntry(state) 128 129 // Now there are unsaved changes. 130 assert.True(t, state.documentBuffer.undoLog.HasUnsavedChanges()) 131 }