diff --git a/lib/operators/input.coffee b/lib/operators/input.coffee index 73cbeceb..e856be3c 100644 --- a/lib/operators/input.coffee +++ b/lib/operators/input.coffee @@ -68,8 +68,9 @@ class InsertAtBeginningOfLine extends Insert class InsertAboveWithNewline extends Insert execute: (count=1) -> @vimState.setInsertionCheckpoint() unless @typingCompleted - @editor.insertNewlineAbove() - @editor.getLastCursor().skipLeadingWhitespace() + @editor.transact Infinity, => + @editor.insertNewlineAbove() + @editor.getLastCursor().skipLeadingWhitespace() if @typingCompleted # We'll have captured the inserted newline, but we want to do that @@ -83,8 +84,9 @@ class InsertAboveWithNewline extends Insert class InsertBelowWithNewline extends Insert execute: (count=1) -> @vimState.setInsertionCheckpoint() unless @typingCompleted - @editor.insertNewlineBelow() - @editor.getLastCursor().skipLeadingWhitespace() + @editor.transact Infinity, => + @editor.insertNewlineBelow() + @editor.getLastCursor().skipLeadingWhitespace() if @typingCompleted # We'll have captured the inserted newline, but we want to do that @@ -116,17 +118,18 @@ class Change extends Insert # undo transactions are already handled. @vimState.setInsertionCheckpoint() unless @typingCompleted - @setTextRegister(@register, @editor.getSelectedText()) - if @motion.isLinewise?() and not @typingCompleted - for selection in @editor.getSelections() - if selection.getBufferRange().end.row is 0 + @editor.transact Infinity, => + @setTextRegister(@register, @editor.getSelectedText()) + if @motion.isLinewise?() and not @typingCompleted + for selection in @editor.getSelections() + if selection.getBufferRange().end.row is 0 + selection.deleteSelectedText() + else + selection.insertText("\n", autoIndent: true) + selection.cursor.moveLeft() + else + for selection in @editor.getSelections() selection.deleteSelectedText() - else - selection.insertText("\n", autoIndent: true) - selection.cursor.moveLeft() - else - for selection in @editor.getSelections() - selection.deleteSelectedText() return super if @typingCompleted diff --git a/lib/vim-state.coffee b/lib/vim-state.coffee index 758e9aa0..5b82f15f 100644 --- a/lib/vim-state.coffee +++ b/lib/vim-state.coffee @@ -461,7 +461,10 @@ class VimState return unless @mode in [null, 'insert'] @editorElement.component.setInputEnabled(false) @editorElement.classList.remove('replace-mode') - @editor.groupChangesSinceCheckpoint(@insertionCheckpoint) + + # this empty transaction with 0 grouping interval makes sure undo doesn't group changes across here + @editor.transact 0, -> + changes = getChangesSinceCheckpoint(@editor.buffer, @insertionCheckpoint) item = @inputOperator(@history[0]) @insertionCheckpoint = null diff --git a/spec/operators-spec.coffee b/spec/operators-spec.coffee index bd8ae915..655c397b 100644 --- a/spec/operators-spec.coffee +++ b/spec/operators-spec.coffee @@ -249,7 +249,7 @@ describe "Operators", -> editor.setCursorScreenPosition([0, 0]) keydown('3') keydown('s') - editor.insertText("ab") + editor.insertText("ab", groupUndo: true) keydown('escape') expect(editor.getText()).toBe 'ab345' keydown('u') @@ -292,7 +292,7 @@ describe "Operators", -> it "is undoable", -> keydown('S', shift: true) - editor.insertText("abc") + editor.insertText("abc", groupUndo: true) keydown 'escape' expect(editor.getText()).toBe "12345\nabc\nABCDE" keydown 'u' @@ -620,13 +620,38 @@ describe "Operators", -> it "is undoable", -> keydown('c') keydown('c') - editor.insertText("abc") + editor.insertText("def", groupUndo: true) keydown 'escape' - expect(editor.getText()).toBe "12345\n abc\nABCDE" + expect(editor.getText()).toBe "12345\n def\nABCDE" keydown 'u' expect(editor.getText()).toBe "12345\n abcde\nABCDE" expect(editor.getSelectedText()).toBe '' + describe "with simulated slow typing", -> + beforeEach -> + spyOn(Date, "now").andCallFake -> window.now + atom.config.set('editor.undoGroupingInterval', 300) + + it "uses Atom undo grouping", -> + keydown('c') + keydown('c') + advanceClock 1000 + editor.insertText("d", groupUndo: true) + advanceClock 100 + editor.insertText("e", groupUndo: true) + advanceClock 500 + editor.insertText("f", groupUndo: true) + keydown 'escape' + expect(editor.getText()).toBe "12345\n def\nABCDE" + keydown 'u' + expect(editor.getText()).toBe "12345\n de\nABCDE" + # FIXME: if TextBuffer allows Infinity for special case groupingInterval, + # the following undo will undo both changes, so the immediate two lines below will go + keydown 'u' + expect(editor.getText()).toBe "12345\n \nABCDE" + keydown 'u' + expect(editor.getText()).toBe "12345\n abcde\nABCDE" + describe "when the cursor is on the last line", -> it "deletes the line's content and enters insert mode on the last line", -> editor.setCursorScreenPosition([2, 1]) @@ -663,8 +688,7 @@ describe "Operators", -> expect(editor.getCursorScreenPosition()).toEqual [1, 0] expect(editorElement.classList.contains('insert-mode')).toBe(true) - # Just cannot get "typing" to work correctly in test. - editor.setText("12345\nfg\nABCDE") + editor.insertText("fg", groupUndo: true) keydown('escape') expect(editorElement.classList.contains('normal-mode')).toBe(true) expect(editor.getText()).toBe "12345\nfg\nABCDE" @@ -717,7 +741,7 @@ describe "Operators", -> editor.addCursorAtScreenPosition([2, 1]) keydown('c') keydown('%') - editor.insertText('x') + editor.insertText('x', groupUndo: true) it "replaces inclusively until matching bracket", -> expect(editor.getText()).toBe("1x8\naxe\nAxBCDE") @@ -1395,7 +1419,7 @@ describe "Operators", -> it "is undoable", -> keydown('O', shift: true) - editor.insertText "def" + editor.insertText "def", groupUndo: true keydown 'escape' expect(editor.getText()).toBe " abc\n def\n 012\n" keydown 'u' @@ -1434,7 +1458,7 @@ describe "Operators", -> it "is undoable", -> keydown('o') - editor.insertText "def" + editor.insertText "def", groupUndo: true keydown 'escape' expect(editor.getText()).toBe "abc\n 012\n def\n" keydown 'u' @@ -1912,16 +1936,17 @@ describe "Operators", -> it "allows undoing an entire batch of typing", -> keydown 'i' - editor.insertText("abcXX") - editor.backspace() - editor.backspace() + editor.insertText("abcXX", groupUndo: true) + # transact to enable grouping of changes, as is done in TextEditorElement + editor.transact 300, -> editor.backspace() + editor.transact 300, -> editor.backspace() keydown 'escape' expect(editor.getText()).toBe "abc123\nabc4567" keydown 'i' - editor.insertText "d" - editor.insertText "e" - editor.insertText "f" + editor.insertText "d", groupUndo: true + editor.insertText "e", groupUndo: true + editor.insertText "f", groupUndo: true keydown 'escape' expect(editor.getText()).toBe "abdefc123\nabdefc4567"