From 277675525b1c09b4d4304fcca641682cfad7eb6d Mon Sep 17 00:00:00 2001 From: DanyaPostfactum Date: Fri, 14 Jun 2013 16:36:30 +1000 Subject: [PATCH] Almost working draft of basic undo coalescence --- lib/ace/edit_session.js | 5 ++-- lib/ace/editor.js | 8 +++++- lib/ace/keyboard/keybinding.js | 52 +++++++++++++++++++++++++++++++++- lib/ace/undomanager.js | 3 ++ 4 files changed, 64 insertions(+), 4 deletions(-) diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index 4f9ace1f..facc4e4e 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -406,10 +406,11 @@ var EditSession = function(text, mode) { if (self.$deltas.length > 0) { undoManager.execute({ action: "aceupdate", - args: [self.$deltas, self] + args: [self.$deltas, self], + merge: self.coalesceDeltas }); } - + self.coalesceDeltas = false; self.$deltas = []; } this.$informUndoManager = lang.delayedCall(this.$syncInformUndoManager); diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 62a4c37f..e1403414 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -701,8 +701,14 @@ var Editor = function(renderer, session) { if (this.getBehavioursEnabled()) { // Get a transform if the current mode wants one. var transform = mode.transformAction(session.getState(cursor.row), 'insertion', this, session, text); - if (transform) + if (transform) { + if (text !== transform.text) { + this.session.coalesceDeltas = false; + this.coalesceNextCommand = false; + } text = transform.text; + + } } text = text.replace("\t", this.session.getTabString()); diff --git a/lib/ace/keyboard/keybinding.js b/lib/ace/keyboard/keybinding.js index 9c54a947..a02a6346 100644 --- a/lib/ace/keyboard/keybinding.js +++ b/lib/ace/keyboard/keybinding.js @@ -105,6 +105,28 @@ var KeyBinding = function(editor) { if (toExecute.command == "null") { success = true; } else { + var mergeableCommands = ["backspace", "del"]; + var previousCommand = this.$editor.previousCommand || {}; + if ( + // previous command was the same + toExecute.command.name == previousCommand.name + // the command is mergeable + && mergeableCommands.indexOf(toExecute.command.name) !== -1 + // cursor was not moved since last command + && !this.$editor.cursorMoved + // the sequence is not too long + && (new Date()) - this.$editor.sequenceStartTime < 2000 + ) + this.$editor.session.coalesceDeltas = true + else + if (mergeableCommands.indexOf(toExecute.command.name) !== -1) + this.$editor.sequenceStartTime = new Date().getTime(); + + this.$editor.previousCommand = { + name: toExecute.command.name, + text: toExecute.command.text + } + this.$editor.cursorMoved = false; success = commands.exec(toExecute.command, this.$editor, toExecute.args, e); } // do not stop input events to not break repeating @@ -123,8 +145,36 @@ var KeyBinding = function(editor) { this.onTextInput = function(text) { var success = this.$callKeyboardHandlers(-1, text); - if (!success) + if (!success) { + if (this.$editor.coalesceNextCommand === undefined) { + this.$editor.coalesceNextCommand = true; + } + var previousCommand = this.$editor.previousCommand || {}; + if ( + // previous command was the same + "insertstring" == previousCommand.name + // cursor was not moved since last command + && !this.$editor.cursorMoved + // previous command allows to coalesce with + && this.$editor.coalesceNextCommand + // previous insertion was not a new line or a whitespace + // or this is a sequence of a new line or a whitespace insertions + && (!/ |\r\n|\r|\n/.test(text) || / |\r\n|\r|\n/.test(previousCommand.text)) + // the sequence is not too long + && (new Date()) - this.$editor.sequenceStartTime < 2000 + ) + this.$editor.session.coalesceDeltas = true; + else + this.$editor.sequenceStartTime = new Date().getTime(); + + this.$editor.previousCommand = { + name: "insertstring", + text: text + } + this.$editor.cursorMoved = false; + this.$editor.coalesceNextCommand = true; this.$editor.commands.exec("insertstring", this.$editor, text); + } }; }).call(KeyBinding.prototype); diff --git a/lib/ace/undomanager.js b/lib/ace/undomanager.js index 0a226d5e..12aaa01d 100644 --- a/lib/ace/undomanager.js +++ b/lib/ace/undomanager.js @@ -63,6 +63,9 @@ var UndoManager = function() { this.execute = function(options) { var deltas = options.args[0]; this.$doc = options.args[1]; + if (options.merge && this.hasUndo()){ + deltas = this.$undoStack.pop().concat(deltas); + } this.$undoStack.push(deltas); this.$redoStack = [];