From 90034c3a44d6da0d56feb918b6b148f04ea7af60 Mon Sep 17 00:00:00 2001 From: Robert Krahn Date: Fri, 21 Mar 2014 22:41:46 -0700 Subject: [PATCH] fixing multi selection handling for various emacs commands Conflicts: lib/ace/keyboard/emacs.js --- lib/ace/keyboard/emacs.js | 65 ++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/lib/ace/keyboard/emacs.js b/lib/ace/keyboard/emacs.js index ab4471b2..fd533f1d 100644 --- a/lib/ace/keyboard/emacs.js +++ b/lib/ace/keyboard/emacs.js @@ -318,7 +318,8 @@ exports.handler.handleKeyboard = function(data, hashId, key, keyCode) { exec: function(editor, args) { for (var i = 0; i < count; i++) command.exec(editor, args); - } + }, + multiSelectAction: command.multiSelectAction } }; } else { @@ -439,37 +440,39 @@ exports.handler.addCommands({ // selection modification commands. That is, // "goto" commands become "select" commands. // Any insertion or mouse click resets mark-mode. - // setMark twice in a row at the same place resets markmode + // setMark twice in a row at the same place resets markmode. + // in multi select mode, ea selection is handled individually + if (args && args.count) { - var mark = editor.popEmacsMark(); - mark && editor.selection.moveCursorToPosition(mark); + function moveToMark() { + var mark = editor.popEmacsMark(); + mark && editor.moveCursorToPosition(mark); + } + if (editor.inMultiSelectMode) editor.forEachSelection({exec: moveToMark}); + else moveToMark(); return; } var mark = editor.emacsMark(), - transientMarkModeActive = true; - + ranges = editor.selection.getAllRanges(), + rangePositions = ranges.map(function(r) { return {row: r.start.row, column: r.start.column}; }), + transientMarkModeActive = true, + hasNoSelection = ranges.every(function(range) { return range.isEmpty(); }); // if transientMarkModeActive then mark behavior is a little // different. Deactivate the mark when setMark is run with active // mark - if (transientMarkModeActive && (mark || !editor.selection.isEmpty())) { - editor.pushEmacsMark(); - editor.clearSelection(); + if (transientMarkModeActive && (mark || !hasNoSelection)) { + if (editor.inMultiSelectMode) editor.forEachSelection({exec: editor.clearSelection.bind(editor)}) + else editor.clearSelection(); + if (mark) editor.pushEmacsMark(null); return; } - if (mark) { - var cp = editor.getCursorPosition(); - if (editor.selection.isEmpty() && - mark.row == cp.row && mark.column == cp.column) { - editor.pushEmacsMark(); - return; - } + if (!mark) { + rangePositions.slice(0,-1).forEach(function(pos) { editor.pushEmacsMark(pos); }); + editor.setEmacsMark(rangePositions[rangePositions.length-1]); + return; } - // turn on mark mode - mark = editor.getCursorPosition(); - editor.setEmacsMark(mark); - editor.selection.setSelectionAnchor(mark.row, mark.column); }, readOnly: true, handlesCount: true, @@ -544,6 +547,7 @@ exports.handler.addCommands({ if (editor.keyBinding.$data.lastCommand != "yank") return; editor.undo(); + editor.session.$emacsMarkRing.pop(); // also undo recording mark editor.onPaste(exports.killRing.rotate()); editor.keyBinding.$data.lastCommand = "yank"; }, @@ -557,12 +561,25 @@ exports.handler.addCommands({ }, killRingSave: { exec: function(editor) { + // copy text and deselect. will save marks for starts of the + // selection(s) + + editor.$handlesEmacsOnCopy = true; + var marks = editor.session.$emacsMarkRing.slice(), + deselectedMarks = []; exports.killRing.add(editor.getCopyText()); + setTimeout(function() { - var sel = editor.selection, - range = sel.getRange(); - editor.pushEmacsMark(sel.isBackwards() ? range.end : range.start); - sel.clearSelection(); + function deselect() { + var sel = editor.selection, range = sel.getRange(), + pos = sel.isBackwards() ? range.end : range.start; + deselectedMarks.push({row: pos.row, column: pos.column}); + sel.clearSelection(); + } + editor.$handlesEmacsOnCopy = false; + if (editor.inMultiSelectMode) editor.forEachSelection({exec: deselect}); + else deselect(); + editor.session.$emacsMarkRing = marks.concat(deselectedMarks.reverse()); }, 0); }, readOnly: true