refactor
This commit is contained in:
parent
2227a9bfea
commit
98180d5b07
5 changed files with 770 additions and 492 deletions
111
lib/ace/commands/multi_select_commands.js
Normal file
111
lib/ace/commands/multi_select_commands.js
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
// add multiSelectAction annotations to default commands
|
||||
require("./default_commands").commands.forEach(function(command) {
|
||||
var single = RegExp(["selectall"].join("|"), "");
|
||||
var mapOver = RegExp(["backspace", "del",
|
||||
"golinedown", "golineup", "gotoend", "gotoleft", "gotolineend", "gotolinestart",
|
||||
"gotoright", "gotostart", "gotowordleft", "gotowordright",
|
||||
"indent", "insertstring", "inserttext", "jumptomatching", "outdent",
|
||||
"removetolineend", "removetolinestart", "removewordleft", "removewordright",
|
||||
"selectdown", "selectleft", "selectlineend", "selectlinestart", "selectright",
|
||||
"selecttoend", "selecttolineend", "selecttolinestart", "selecttostart",
|
||||
"selectup", "selectwordleft", "selectwordright",
|
||||
"splitline", "tolowercase", "touppercase"].join("|"), "");
|
||||
|
||||
if (single.test(command.name))
|
||||
command.multiSelectAction = "single";
|
||||
else if (mapOver.test(command.name))
|
||||
command.multiSelectAction = "forEach";
|
||||
else if (command.name == "transposeletters")
|
||||
command.multiSelectAction = function(editor) {editor.transposeSelections(1); }
|
||||
});
|
||||
|
||||
// commands to enter multiselect mode
|
||||
exports.defaultCommands = [{
|
||||
name: "addCursorAbove",
|
||||
exec: function(editor) { editor.selectMoreLines(-1); },
|
||||
bindKey: {win: "Ctrl-Alt-Up", mac: "Ctrl-Alt-Up"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "addCursorBelow",
|
||||
exec: function(editor) { editor.selectMoreLines(1); },
|
||||
bindKey: {win: "Ctrl-Alt-Down", mac: "Ctrl-Alt-Down"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "selectMoreBefore",
|
||||
exec: function(editor) { editor.selectMore(-1); },
|
||||
bindKey: {win: "Ctrl-Alt-Left", mac: "Ctrl-Alt-Left"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "selectMoreAfter",
|
||||
exec: function(editor) { editor.selectMore(1); },
|
||||
bindKey: {win: "Ctrl-Alt-Right", mac: "Ctrl-Alt-Right"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "selectNextBefore",
|
||||
exec: function(editor) { editor.selectMore(-1, true); },
|
||||
bindKey: {win: "Ctrl-Alt-Shift-Left", mac: "Ctrl-Alt-Shift-Left"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "selectNextAfter",
|
||||
exec: function(editor) { editor.selectMore(1, true); },
|
||||
bindKey: {win: "Ctrl-Alt-Shift-Right", mac: "Ctrl-Alt-Shift-Right"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "splitIntoLines",
|
||||
exec: function(editor) { editor.multiSelect.splitIntoLines(); },
|
||||
bindKey: {win: "Ctrl-Shift-L", mac: "Ctrl-Shift-L"},
|
||||
readonly: true
|
||||
}, ];
|
||||
|
||||
// commands active in multiselect mode
|
||||
exports.multiEditCommands = [{
|
||||
name: "singleSelection",
|
||||
bindKey: "esc",
|
||||
exec: function(editor) { editor.exitMultiSelectMode(); },
|
||||
readonly: true
|
||||
}];
|
||||
|
||||
var HashHandler = require("../keyboard/hash_handler").HashHandler;
|
||||
exports.keyboardHandler = new HashHandler(exports.multiEditCommands);
|
||||
|
||||
});
|
||||
|
|
@ -66,7 +66,7 @@ var Cursor = function(parentEl) {
|
|||
|
||||
this.addCursor = function() {
|
||||
var el = dom.createElement("div");
|
||||
var className = "ace_cursor"
|
||||
var className = "ace_cursor";
|
||||
if (!this.isVisible)
|
||||
className += " ace_hidden";
|
||||
if (this.overwrite)
|
||||
|
|
@ -81,8 +81,8 @@ var Cursor = function(parentEl) {
|
|||
this.removeCursor = function() {
|
||||
if (this.cursors.length > 1) {
|
||||
var el = this.cursors.pop();
|
||||
el.parentNode.removeChild(el)
|
||||
return el
|
||||
el.parentNode.removeChild(el);
|
||||
return el;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -141,8 +141,8 @@ var Cursor = function(parentEl) {
|
|||
this.update = function(config) {
|
||||
this.config = config;
|
||||
|
||||
if (this.session.selection.rangeCount > 1) {
|
||||
var selections = this.session.selection.getAllRanges();
|
||||
if (this.session.selectionMarkerCount > 1) {
|
||||
var selections = this.session.$selectionMarkers;
|
||||
var i = 0, sel, cursorIndex = 0;
|
||||
|
||||
for (var i = selections.length; i--; ) {
|
||||
|
|
@ -156,8 +156,8 @@ var Cursor = function(parentEl) {
|
|||
style.width = config.characterWidth + "px";
|
||||
style.height = config.lineHeight + "px";
|
||||
}
|
||||
if (this.cursors.length > 1)
|
||||
while (cursorIndex < this.cursors.length)
|
||||
if (cursorIndex > 1)
|
||||
while (this.cursors.length > cursorIndex)
|
||||
this.removeCursor();
|
||||
} else {
|
||||
var pixelPos = this.getPixelPosition(null, true);
|
||||
|
|
|
|||
173
lib/ace/mouse/multi_select_mouse_handler.js
Normal file
173
lib/ace/mouse/multi_select_mouse_handler.js
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Harutyun Amirjanyan <amirjanyan AT gmail DOT com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
var event = require("../lib/event");
|
||||
|
||||
|
||||
// mouse
|
||||
function isSamePoint(p1, p2) {
|
||||
return p1.row == p2.row && p1.column == p2.column
|
||||
}
|
||||
|
||||
function onMouseDown(e) {
|
||||
var ev = e.domEvent;
|
||||
var alt = ev.altKey;
|
||||
var shift = ev.shiftKey;
|
||||
var ctrl = ev.ctrlKey;
|
||||
var button = e.getButton();
|
||||
|
||||
if (!ctrl && !alt) {
|
||||
if (e.editor.selection.rangeCount > 1) {
|
||||
if (button == 0) {
|
||||
e.editor.exitMultiSelectMode();
|
||||
} else if (button == 2) {
|
||||
var editor = e.editor;
|
||||
var selectionEmpty = editor.selection.isEmpty();
|
||||
editor.textInput.onContextMenu({x: e.clientX, y: e.clientY}, selectionEmpty);
|
||||
event.capture(editor.container, function(){}, editor.textInput.onContextMenuClose);
|
||||
e.stop();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var editor = e.editor;
|
||||
var selection = editor.selection;
|
||||
var isMultiSelect = selection.rangeCount > 1
|
||||
var pos = e.getDocumentPosition();
|
||||
var rangeList = selection.rangeList;
|
||||
var cursor = selection.getCursor()
|
||||
var inSelection = e.inSelection() || (selection.isEmpty() && isSamePoint(pos, cursor));
|
||||
|
||||
if (ctrl && !shift && !alt && button == 0) {
|
||||
if (!isMultiSelect && inSelection)
|
||||
return // dragging
|
||||
|
||||
if (!isMultiSelect) {
|
||||
selection.addRange(selection.toOrientedRange());
|
||||
}
|
||||
if (inSelection)
|
||||
selection.clearSelection();
|
||||
|
||||
var helper = selection.toOrientedRange();
|
||||
editor.addSelectionMarker(helper);
|
||||
|
||||
var oldRange = rangeList.rangeAtPoint(pos);
|
||||
|
||||
event.capture(editor.container, function(){}, function() {
|
||||
editor.removeSelectionMarkers([helper]);
|
||||
var tmpSel = selection.toOrientedRange();
|
||||
|
||||
if (oldRange && tmpSel.isEmpty() && isSamePoint(oldRange.cursor, tmpSel.cursor)) {
|
||||
if (selection.rangeCount > 1) {
|
||||
range = editor.selection.rangeList.substractPoint(tmpSel.cursor);
|
||||
var range = editor.selection.rangeList.all[0];
|
||||
if (range)
|
||||
editor.selection.addRange(range);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
selection.addRange(tmpSel);
|
||||
});
|
||||
|
||||
//e.stop()
|
||||
} else if (!shift && alt && button == 0) {
|
||||
e.stop()
|
||||
var mouseX = e.pageX, mouseY = e.pageY;
|
||||
var onMouseSelection = function(e) {
|
||||
mouseX = event.getDocumentX(e);
|
||||
mouseY = event.getDocumentY(e);
|
||||
};
|
||||
|
||||
if (isMultiSelect && !ctrl) {
|
||||
selection.single();
|
||||
}
|
||||
selection.moveCursorToPosition(pos);
|
||||
selection.clearSelection();
|
||||
|
||||
var rectSel = [];
|
||||
var session = editor.session;
|
||||
|
||||
var onMouseSelectionEnd = function(e) {
|
||||
clearInterval(timerId);
|
||||
editor.removeSelectionMarkers(rectSel);
|
||||
for (var i = 0; i < rectSel.length; i++)
|
||||
selection.addRange(rectSel[i])
|
||||
};
|
||||
|
||||
var anchor = selection.getCursor();
|
||||
var screenAnchor = editor.renderer.pixelToScreenCoordinates(mouseX, mouseY);
|
||||
var clippedAnchor = session.documentToScreenPosition(anchor);
|
||||
var screenCursor = screenAnchor;
|
||||
|
||||
var onSelectionInterval = function() {
|
||||
var newCursor = editor.renderer.pixelToScreenCoordinates(mouseX, mouseY);
|
||||
var cursor = session.screenToDocumentPosition(newCursor.row, newCursor.column);
|
||||
|
||||
if (isSamePoint(screenCursor, newCursor)
|
||||
&& isSamePoint(cursor, selection.selectionLead))
|
||||
return;
|
||||
screenCursor = newCursor;
|
||||
|
||||
editor.selection.moveCursorToPosition(cursor);
|
||||
editor.selection.clearSelection();
|
||||
editor.renderer.scrollCursorIntoView();
|
||||
|
||||
editor.removeSelectionMarkers(rectSel);
|
||||
rectSel = selection.rectangularRangeBlock(screenCursor, screenAnchor);
|
||||
rectSel.forEach(editor.addSelectionMarker, editor);
|
||||
|
||||
editor.renderer.updateCursor();
|
||||
editor.renderer.updateBackMarkers();
|
||||
};
|
||||
|
||||
event.capture(editor.container, onMouseSelection, onMouseSelectionEnd);
|
||||
var timerId = setInterval(onSelectionInterval, 20);
|
||||
|
||||
return e.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
exports.onMouseDown = onMouseDown;
|
||||
|
||||
});
|
||||
|
|
@ -42,43 +42,445 @@ var RangeList = require("./range_list").RangeList;
|
|||
var Range = require("./range").Range;
|
||||
var Selection = require("./selection").Selection;
|
||||
var Range = require("./range").Range;
|
||||
var event = require("./lib/event");
|
||||
var onMouseDown = require("./mouse/multi_select_mouse_handler").onMouseDown;
|
||||
exports.commands = require("./commands/multi_select_commands");
|
||||
|
||||
|
||||
function forEachSelection(editor, cmd, args) {
|
||||
if (editor.session.multiSelection.inVirtualMode)
|
||||
return
|
||||
var session = editor.session
|
||||
var selection = editor.selection
|
||||
var rangeList = selection.rangeList
|
||||
var Search = require("ace/search").Search
|
||||
var search = new Search
|
||||
|
||||
var reg = selection._eventRegistry;
|
||||
selection._eventRegistry = {};
|
||||
|
||||
var sh = new Selection(session);
|
||||
editor.session.multiSelection.inVirtualMode = true;
|
||||
for (var i = rangeList.ranges.length; i--;) {
|
||||
sh.fromOrientedRange(rangeList.ranges[i])
|
||||
editor.selection = session.selection = sh
|
||||
cmd.exec(editor, args || {})
|
||||
sh.toOrientedRange(rangeList.ranges[i])
|
||||
}
|
||||
sh.detach();
|
||||
|
||||
rangeList.merge()
|
||||
editor.selection = session.selection = selection;
|
||||
editor.session.multiSelection.inVirtualMode = false;
|
||||
selection._eventRegistry = reg;
|
||||
|
||||
selection.fromOrientedRange(selection.rangeList.all[0])
|
||||
editor.renderer.updateCursor();
|
||||
editor.renderer.updateBackMarkers();
|
||||
|
||||
if (selection.rangeCount == 1 && editor.inMultiSelectMode)
|
||||
exitMultiSelectMode(editor)
|
||||
function find(session, needle, dir) {
|
||||
search.$options.wrap = true;
|
||||
search.$options.needle = needle;
|
||||
search.$options.backwards = dir == -1;
|
||||
return search.find(session)
|
||||
}
|
||||
|
||||
function exec(command, editor, args) {
|
||||
// extend EditSession
|
||||
var EditSession = require("./edit_session").EditSession;
|
||||
;(function() {
|
||||
this.getSelectionMarkers = function() {
|
||||
return this.$selectionMarkers;
|
||||
};
|
||||
}).call(EditSession.prototype);
|
||||
|
||||
// extend Selection
|
||||
;(function() {
|
||||
this.addRange = function(range) {
|
||||
if (!range.cursor)
|
||||
range.cursor = range.end;
|
||||
|
||||
if (this.rangeCount == 0) {
|
||||
var oldRange = this.toOrientedRange();
|
||||
this.rangeList.add(oldRange);
|
||||
this._emit("addRange", {range: oldRange});
|
||||
}
|
||||
|
||||
this.rangeList.add(range);
|
||||
this.rangeCount = this.rangeList.ranges.length;
|
||||
|
||||
if (this.rangeCount > 1 && !this.inMultiSelectMode) {
|
||||
this._emit("multiSelect");
|
||||
this.inMultiSelectMode = true;
|
||||
}
|
||||
|
||||
this.fromOrientedRange(range);
|
||||
if (this.rangeCount >= 1)
|
||||
this._emit("addRange", {range: range});
|
||||
};
|
||||
|
||||
this.single = function(range) {
|
||||
range = range || this.rangeList.all[0];
|
||||
this.rangeList.removeAll();
|
||||
range && this.fromOrientedRange(range);
|
||||
};
|
||||
|
||||
this.$onRemoveRange = function(e) {
|
||||
this.rangeCount = this.rangeList.ranges.length;
|
||||
this._emit("removeRange", e);
|
||||
|
||||
if (this.rangeCount <= 1 && this.inMultiSelectMode) {
|
||||
this.inMultiSelectMode = false;
|
||||
this._emit("singleSelect");
|
||||
|
||||
if (this.rangeCount == 1)
|
||||
this.single();
|
||||
}
|
||||
};
|
||||
|
||||
// adds multicursor support to selection
|
||||
this.$initRangeList = function() {
|
||||
if (this.rangeList)
|
||||
return;
|
||||
|
||||
var rangeList = new RangeList;
|
||||
// list of ranges in reverse addition order
|
||||
// rangeList.all[0] is the same as selection.getRange
|
||||
rangeList.all = [];
|
||||
rangeList.on("add", function(e) {
|
||||
rangeList.all.unshift(e.range)
|
||||
})
|
||||
rangeList.on("remove", function(e) {
|
||||
var ranges = e.ranges
|
||||
for (var i = ranges.length; i--; ) {
|
||||
var index = rangeList.all.indexOf(ranges[i]);
|
||||
rangeList.all.splice(index, 1);
|
||||
}
|
||||
});
|
||||
|
||||
this.rangeList = rangeList;
|
||||
this.cursor = this.selectionLead;
|
||||
|
||||
this.rangeCount = 1;
|
||||
this.rangeList.on("remove", this.$onRemoveRange.bind(this));
|
||||
};
|
||||
this.getAllRanges = function() {
|
||||
return this.rangeList.ranges.concat(this.secondarySelections)
|
||||
};
|
||||
|
||||
|
||||
this.splitIntoLines = function () {
|
||||
if (this.rangeCount > 1) {
|
||||
var ranges = this.rangeList.ranges;
|
||||
var lastRange = ranges[ranges.length - 1]
|
||||
var range = Range.fromPoints(ranges[0].start, lastRange.end)
|
||||
|
||||
this.single()
|
||||
this.setSelectionRange(range, lastRange.cursor == lastRange.start)
|
||||
} else {
|
||||
var cursor = this.getRange().toScreenRange();
|
||||
range
|
||||
}
|
||||
};
|
||||
|
||||
this.splitIntoLines = function () {
|
||||
if (this.rangeCount > 1) {
|
||||
var ranges = this.rangeList.ranges;
|
||||
var lastRange = ranges[ranges.length - 1]
|
||||
var range = Range.fromPoints(ranges[0].start, lastRange.end)
|
||||
|
||||
this.single()
|
||||
this.setSelectionRange(range, lastRange.cursor == lastRange.start)
|
||||
} else {
|
||||
var cursor = this.session.documentToScreenPosition(this.selectionLead);
|
||||
var anchor = this.session.documentToScreenPosition(this.selectionAnchor);
|
||||
|
||||
var rectSel = this.rectangularRangeBlock(cursor, anchor);
|
||||
rectSel.forEach(this.addRange, this);
|
||||
}
|
||||
};
|
||||
|
||||
this.rectangularRangeBlock = function(screenCursor, screenAnchor, includeEmptyLines) {
|
||||
var rectSel = [];
|
||||
|
||||
var xBackwards = screenCursor.column < screenAnchor.column;
|
||||
if (xBackwards) {
|
||||
var startColumn = screenCursor.column;
|
||||
var endColumn = screenAnchor.column;
|
||||
} else {
|
||||
var startColumn = screenAnchor.column;
|
||||
var endColumn = screenCursor.column;
|
||||
}
|
||||
|
||||
var yBackwards = screenCursor.row < screenAnchor.row;
|
||||
if (yBackwards) {
|
||||
var startRow = screenCursor.row;
|
||||
var endRow = screenAnchor.row;
|
||||
} else {
|
||||
var startRow = screenAnchor.row;
|
||||
var endRow = screenCursor.row;
|
||||
}
|
||||
|
||||
if (startColumn < 0)
|
||||
startColumn = 0;
|
||||
if (startRow < 0)
|
||||
startRow = 0;
|
||||
|
||||
if (startRow == endRow)
|
||||
includeEmptyLines = true;
|
||||
|
||||
for (var row = startRow; row <= endRow; row++) {
|
||||
var range = Range.fromPoints(
|
||||
this.session.screenToDocumentPosition(row, startColumn),
|
||||
this.session.screenToDocumentPosition(row, endColumn)
|
||||
);
|
||||
if (range.isEmpty()) {
|
||||
if (docEnd && isSamePoint(range.end, docEnd))
|
||||
break;
|
||||
var docEnd = range.end;
|
||||
}
|
||||
range.cursor = xBackwards ? range.start : range.end;
|
||||
rectSel.push(range);
|
||||
}
|
||||
if (yBackwards)
|
||||
rectSel.reverse();
|
||||
|
||||
if (!includeEmptyLines) {
|
||||
var end = rectSel.length - 1;
|
||||
while (rectSel[end].isEmpty() && end > 0)
|
||||
end--;
|
||||
if (end > 0) {
|
||||
var start = 0;
|
||||
while (rectSel[start].isEmpty())
|
||||
start++;
|
||||
}
|
||||
for (var i = end; i >= start; i--) {
|
||||
if (rectSel[i].isEmpty())
|
||||
rectSel.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return rectSel;
|
||||
};
|
||||
}).call(Selection.prototype);
|
||||
|
||||
// extend Editor
|
||||
var Editor = require("./editor").Editor;
|
||||
;(function() {
|
||||
this.addSelectionMarker = function(orientedRange) {
|
||||
if (!orientedRange.cursor)
|
||||
orientedRange.cursor = orientedRange.end;
|
||||
|
||||
var style = this.getSelectionStyle();
|
||||
orientedRange.marker = this.session.addMarker(orientedRange, "ace_selection", style);
|
||||
|
||||
this.session.$selectionMarkers.push(orientedRange);
|
||||
this.session.selectionMarkerCount = this.session.$selectionMarkers.length;
|
||||
return orientedRange
|
||||
};
|
||||
|
||||
this.removeSelectionMarkers = function(ranges) {
|
||||
for (var i = ranges.length; i--; ) {
|
||||
var range = ranges[i];
|
||||
if (!range.marker)
|
||||
continue;
|
||||
this.session.removeMarker(range.marker);
|
||||
var index = this.session.$selectionMarkers.indexOf(range);
|
||||
if (index != -1)
|
||||
this.session.$selectionMarkers.splice(index, 1)
|
||||
}
|
||||
this.session.selectionMarkerCount = this.session.$selectionMarkers.length;
|
||||
};
|
||||
|
||||
this.$onAddRange = function(e) {
|
||||
this.addSelectionMarker(e.range);
|
||||
this.renderer.updateCursor();
|
||||
this.renderer.updateBackMarkers();
|
||||
};
|
||||
this.$onRemoveRange = function(e) {
|
||||
this.removeSelectionMarkers(e.ranges);
|
||||
this.renderer.updateCursor();
|
||||
this.renderer.updateBackMarkers();
|
||||
};
|
||||
this.$onMultiSelect = function(e) {
|
||||
if (this.inMultiSelectMode)
|
||||
return;
|
||||
this.inMultiSelectMode = true;
|
||||
|
||||
this.setStyle("multiselect");
|
||||
this.keyBinding.addKeyboardHandler(exports.commands.keyboardHandler);
|
||||
// FixMe
|
||||
this.commands.__SingleSelectionExec = this.commands.exec;
|
||||
this.commands.exec = exports.exec;
|
||||
this.renderer.updateCursor();
|
||||
this.renderer.updateBackMarkers();
|
||||
|
||||
this.session.$undoSelect = false;
|
||||
this.selection.rangeList.attach(this.session);
|
||||
};
|
||||
|
||||
this.$onSingleSelect = function(e) {
|
||||
if (this.session.multiSelect.inVirtualMode)
|
||||
return;
|
||||
this.inMultiSelectMode = false;
|
||||
|
||||
this.unsetStyle("multiselect");
|
||||
this.keyBinding.removeKeyboardHandler(exports.commands.keyboardHandler);
|
||||
|
||||
this.commands.exec = this.commands.__SingleSelectionExec;
|
||||
this.renderer.updateCursor();
|
||||
this.renderer.updateBackMarkers();
|
||||
|
||||
this.session.$undoSelect = true;
|
||||
|
||||
this.selection.rangeList.detach(this.session);
|
||||
};
|
||||
|
||||
this.forEachSelection = function(cmd, args) {
|
||||
if (this.inVirtualSelectionMode)
|
||||
return;
|
||||
var session = this.session
|
||||
var selection = this.selection
|
||||
var rangeList = selection.rangeList
|
||||
|
||||
var reg = selection._eventRegistry;
|
||||
selection._eventRegistry = {};
|
||||
|
||||
var tmpSel = new Selection(session);
|
||||
this.inVirtualSelectionMode = true;
|
||||
for (var i = rangeList.ranges.length; i--;) {
|
||||
tmpSel.fromOrientedRange(rangeList.ranges[i]);
|
||||
this.selection = session.selection = tmpSel;
|
||||
cmd.exec(this, args || {});
|
||||
tmpSel.toOrientedRange(rangeList.ranges[i]);
|
||||
}
|
||||
tmpSel.detach();
|
||||
|
||||
this.selection = session.selection = selection;
|
||||
this.inVirtualSelectionMode = false;
|
||||
selection._eventRegistry = reg;
|
||||
rangeList.merge();
|
||||
|
||||
var lastRange = selection.rangeList.all[0]
|
||||
lastRange && selection.fromOrientedRange(lastRange);
|
||||
|
||||
selection._emit("changeSelection")
|
||||
selection._emit("changeCursor")
|
||||
this.renderer.updateCursor();
|
||||
this.renderer.updateBackMarkers();
|
||||
};
|
||||
|
||||
this.exitMultiSelectMode = function() {
|
||||
if (this.inVirtualSelectionMode)
|
||||
return;
|
||||
this.multiSelect.single();
|
||||
};
|
||||
|
||||
// todo route copy/cut/paste through commandmanager
|
||||
this.getCopyText = function() {
|
||||
var text = "";
|
||||
if (this.inMultiSelectMode) {
|
||||
var ranges = this.multiSelect.rangeList.ranges;
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
text += this.session.getTextRange(ranges[i]);
|
||||
}
|
||||
} else if (!this.selection.isEmpty())
|
||||
text = this.session.getTextRange(this.getSelectionRange());
|
||||
|
||||
|
||||
return text;
|
||||
};
|
||||
|
||||
this.onCut = function() {
|
||||
var cmd = {
|
||||
name: "cut",
|
||||
exec: function(editor) {
|
||||
var range = editor.getSelectionRange();
|
||||
editor._emit("cut", range);
|
||||
|
||||
if (!editor.selection.isEmpty()) {
|
||||
editor.session.remove(range);
|
||||
editor.clearSelection();
|
||||
}
|
||||
},
|
||||
readonly: true,
|
||||
multiSelectAction: "forEach"
|
||||
}
|
||||
this.commands.exec(cmd, this)
|
||||
};
|
||||
|
||||
// commands
|
||||
|
||||
this.selectMoreLines = function(dir, skip) {
|
||||
var range = this.selection.toOrientedRange();
|
||||
var isBackwards = range.cursor == range.end;
|
||||
|
||||
var screenLead = this.session.documentToScreenPosition(range.cursor);
|
||||
if (this.selection.$desiredColumn)
|
||||
screenLead.column = this.selection.$desiredColumn;
|
||||
|
||||
var lead = this.session.screenToDocumentPosition(screenLead.row + dir, screenLead.column);
|
||||
|
||||
if (!range.isEmpty()) {
|
||||
var screenAnchor = this.session.documentToScreenPosition(isBackwards ? range.end : range.start);
|
||||
var anchor = this.session.screenToDocumentPosition(screenAnchor.row + dir, screenAnchor.column);
|
||||
} else {
|
||||
var anchor = lead;
|
||||
}
|
||||
|
||||
if (isBackwards) {
|
||||
var newRange = Range.fromPoints(lead, anchor);
|
||||
newRange.cursor = newRange.start;
|
||||
} else {
|
||||
var newRange = Range.fromPoints(anchor, lead);
|
||||
newRange.cursor = newRange.end;
|
||||
}
|
||||
|
||||
newRange.desiredColumn = screenLead.column;
|
||||
if (!this.selection.inMultiSelectMode) {
|
||||
this.selection.addRange(range);
|
||||
} else {
|
||||
var allRanges = this.selection.rangeList.ranges;
|
||||
// remove range if at end
|
||||
if (skip || range.isEequal(allRanges[dir == 1 ? 0 : allRanges.length - 1]))
|
||||
var toRemove = range.cursor;
|
||||
}
|
||||
|
||||
this.selection.addRange(newRange);
|
||||
if (toRemove)
|
||||
this.selection.rangeList.substractPoint(toRemove);
|
||||
}
|
||||
|
||||
this.transposeSelections = function(dir) {
|
||||
var session = this.session;
|
||||
var sel = session.multiSelect;
|
||||
var all = sel.rangeList.all;
|
||||
|
||||
var words = [];
|
||||
for (var i = all.length; i--; ) {
|
||||
var range = all[i]
|
||||
if (range.isEmpty()) {
|
||||
var tmp = session.getWordRange(range.start.row, range.start.column)
|
||||
range.start.row = tmp.start.row;
|
||||
range.start.column = tmp.start.column;
|
||||
range.end.row = tmp.end.row;
|
||||
range.end.column = tmp.end.column;
|
||||
}
|
||||
|
||||
words.unshift(this.session.getTextRange(range));
|
||||
}
|
||||
if (dir < 0)
|
||||
words.unshift(words.pop());
|
||||
else
|
||||
words.push(words.shift());
|
||||
|
||||
for (var i = all.length; i--; ) {
|
||||
var range = all[i];
|
||||
var tmp = range.clone();
|
||||
session.replace(range, words[i]);
|
||||
range.start.row = tmp.start.row;
|
||||
range.start.column = tmp.start.column;
|
||||
}
|
||||
}
|
||||
|
||||
this.selectMore = function (dir, skip) {
|
||||
var session = this.session;
|
||||
var sel = session.multiSelect;
|
||||
var all = sel.rangeList.all;
|
||||
|
||||
var range = sel.toOrientedRange();
|
||||
if (range.isEmpty()) {
|
||||
var range = session.getWordRange(range.start.row, range.start.column)
|
||||
range.cursor = range.end;
|
||||
this.multiSelect.addRange(range);
|
||||
}
|
||||
var needle = session.getTextRange(range);
|
||||
|
||||
|
||||
var newRange = find(session, needle, dir);
|
||||
if (newRange) {
|
||||
newRange.cursor = dir == -1 ? newRange.start : newRange.end;
|
||||
this.multiSelect.addRange(newRange);
|
||||
}
|
||||
if (skip)
|
||||
this.multiSelect.rangeList.substractPoint(range.cursor);
|
||||
}
|
||||
|
||||
|
||||
}).call(Editor.prototype);
|
||||
|
||||
// Todo emit event before exec?
|
||||
exports.exec = function(command, editor, args) {
|
||||
if (typeof command === 'string')
|
||||
command = this.commands[command];
|
||||
|
||||
|
|
@ -88,481 +490,67 @@ function exec(command, editor, args) {
|
|||
if (editor && editor.$readOnly && !command.readOnly)
|
||||
return false;
|
||||
|
||||
if (!command.multiCursor) {
|
||||
if (!command.multiSelectAction) {
|
||||
command.exec(editor, args || {});
|
||||
} else if (command.multiCursor == "forEach") {
|
||||
forEachSelection(editor, command, args)
|
||||
} else if (command.multiCursor == "single") {
|
||||
exitMultiSelectMode(editor);
|
||||
} else if (command.multiSelectAction == "forEach") {
|
||||
editor.forEachSelection(command, args);
|
||||
} else if (command.multiSelectAction == "single") {
|
||||
editor.exitMultiSelectMode();
|
||||
command.exec(editor, args || {});
|
||||
} else {
|
||||
command.multiCursor(editor, args || {});
|
||||
command.multiSelectAction(editor, args || {});
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
function enterMultiSelectMode(editor) {
|
||||
if (editor.inMultiSelectMode)
|
||||
return
|
||||
editor.inMultiSelectMode = true
|
||||
editor.setStyle("multiselect")
|
||||
editor.keyBinding.addKeyboardHandler(exports.keyboardHandler);
|
||||
editor.commands.__exec = editor.commands.exec
|
||||
editor.commands.exec = exec
|
||||
|
||||
editor.session.$undoSelect = false
|
||||
editor.selection.rangeList.attach(editor.session);
|
||||
}
|
||||
function exitMultiSelectMode(editor) {
|
||||
if (editor.session.multiSelection.inVirtualMode)
|
||||
return
|
||||
editor.inMultiSelectMode = false;
|
||||
editor.selection.secondarySelections = [];
|
||||
editor.unsetStyle("multiselect");
|
||||
editor.selection.rangeList.removeAll();
|
||||
editor.keyBinding.removeKeyboardHandler(exports.keyboardHandler);
|
||||
|
||||
editor.commands.exec = editor.commands.__exec;
|
||||
editor.renderer.updateCursor();
|
||||
editor.renderer.updateBackMarkers();
|
||||
|
||||
editor.session.$undoSelect = true
|
||||
|
||||
editor.selection.rangeList.detach(editor.session);
|
||||
}
|
||||
|
||||
function initSession(session) {
|
||||
if (session.selection.rangeList)
|
||||
return
|
||||
session.multiSelection = session.selection
|
||||
|
||||
var rangeList = new RangeList;
|
||||
|
||||
rangeList.all = [];
|
||||
rangeList.on("add", function(e) {
|
||||
rangeList.all.unshift(e.range)
|
||||
})
|
||||
|
||||
rangeList.on("remove", function(e) {
|
||||
var ranges = e.ranges
|
||||
for (var i = ranges.length; i--; ) {
|
||||
var index = rangeList.all.indexOf(ranges[i]);
|
||||
rangeList.all.splice(index, 1);
|
||||
}
|
||||
});
|
||||
|
||||
session.selection.rangeList = rangeList;
|
||||
session.selection.cursor = session.selection.selectionLead;
|
||||
session.selection.secondarySelections = [];
|
||||
session.selection.getAllRanges = function() {
|
||||
return this.rangeList.ranges.concat(this.secondarySelections)
|
||||
};
|
||||
session.selection.rangeCount = 1;
|
||||
}
|
||||
|
||||
var addSelectionRange = function(editor, orientedRange) {
|
||||
if (!editor.inMultiSelectMode)
|
||||
enterMultiSelectMode(editor)
|
||||
|
||||
if (!orientedRange.cursor)
|
||||
orientedRange.cursor = orientedRange.end
|
||||
|
||||
var style = editor.getSelectionStyle();
|
||||
orientedRange.marker = editor.session.addMarker(orientedRange, "ace_selection", style);
|
||||
|
||||
// use this to not conflict with virtualSelections added by forEachSelection
|
||||
var selection = editor.session.multiSelection;
|
||||
selection.rangeList.add(orientedRange);
|
||||
selection.rangeCount = selection.rangeList.all.length + selection.secondarySelections.length;
|
||||
|
||||
selection.fromOrientedRange(orientedRange)
|
||||
editor.renderer.updateCursor();
|
||||
editor.renderer.updateBackMarkers();
|
||||
};
|
||||
|
||||
function addCursorV(editor, dir){
|
||||
var range = editor.selection.getRange()
|
||||
var isBackwards = editor.selection.isBackwards()
|
||||
range.cursor = isBackwards ? range.start : range.end;
|
||||
|
||||
var screenLead = editor.session.documentToScreenPosition(range.cursor);
|
||||
if (editor.selection.$desiredColumn)
|
||||
screenLead.column = editor.selection.$desiredColumn;
|
||||
|
||||
var lead = editor.session.screenToDocumentPosition(screenLead.row + dir, screenLead.column);
|
||||
|
||||
if (!range.isEmpty()) {
|
||||
var screenAnchor = editor.session.documentToScreenPosition(isBackwards ? range.end : range.start);
|
||||
var anchor = editor.session.screenToDocumentPosition(screenAnchor.row + dir, screenAnchor.column);
|
||||
} else {
|
||||
var anchor = lead
|
||||
}
|
||||
|
||||
if (isBackwards) {
|
||||
var newRange = Range.fromPoints(lead, anchor)
|
||||
newRange.cursor = newRange.start
|
||||
} else {
|
||||
var newRange = Range.fromPoints(anchor, lead)
|
||||
newRange.cursor = newRange.end
|
||||
}
|
||||
newRange.desiredColumn = screenLead.column;
|
||||
if (!editor.inMultiSelectMode) {
|
||||
addSelectionRange(editor, range)
|
||||
} else {
|
||||
var allRanges = editor.selection.rangeList.ranges
|
||||
// remove range if at end
|
||||
if (range.isEequal(allRanges[dir == 1 ? 0 : allRanges.length - 1]))
|
||||
var toRemove = range.cursor
|
||||
}
|
||||
addSelectionRange(editor, newRange)
|
||||
if (toRemove)
|
||||
editor.selection.rangeList.substractPoint(toRemove)
|
||||
}
|
||||
|
||||
function transposeSelections(editor, dir) {
|
||||
var session = editor.session;
|
||||
var sel = session.multiSelection;
|
||||
var all = sel.rangeList.all;
|
||||
|
||||
var words = [];
|
||||
for (var i = all.length; i--; ) {
|
||||
var range = all[i]
|
||||
if (range.isEmpty()) {
|
||||
var tmp = session.getWordRange(range.start.row, range.start.column)
|
||||
range.start.row = tmp.start.row;
|
||||
range.start.column = tmp.start.column;
|
||||
range.end.row = tmp.end.row;
|
||||
range.end.column = tmp.end.column;
|
||||
}
|
||||
|
||||
words.unshift(editor.session.getTextRange(range));
|
||||
}
|
||||
if (dir < 0)
|
||||
words.unshift(words.pop());
|
||||
else
|
||||
words.push(words.shift());
|
||||
|
||||
for (var i = all.length; i--; ) {
|
||||
var range = all[i];
|
||||
var tmp = range.clone();
|
||||
session.replace(range, words[i]);
|
||||
range.start.row = tmp.start.row;
|
||||
range.start.column = tmp.start.column;
|
||||
}
|
||||
}
|
||||
|
||||
function splitIntoLines(editor) {
|
||||
var sel = editor.session.multiSelection
|
||||
if (sel.rangeCount > 1) {
|
||||
var ranges = sel.rangeList.ranges;
|
||||
var lastRange = ranges[ranges.length - 1]
|
||||
var range = Range.fromPoints(ranges[0].start, lastRange.end)
|
||||
|
||||
exitMultiSelectMode(editor)
|
||||
sel.setSelectionRange(range, lastRange.cursor == lastRange.start)
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var Search = require("ace/search").Search
|
||||
var search = new Search
|
||||
|
||||
function find(session, needle, dir) {
|
||||
search.$options.wrap = false;
|
||||
search.$options.needle = needle;
|
||||
search.$options.backwards = dir == -1;
|
||||
return search.find(session)
|
||||
}
|
||||
function addRange(editor, dir, skip) {
|
||||
var session = editor.session;
|
||||
var sel = session.multiSelection;
|
||||
var all = sel.rangeList.all;
|
||||
|
||||
var range = sel.getRange();
|
||||
if (range.isEmpty()) {
|
||||
var tmp = session.getWordRange(range.start.row, range.start.column)
|
||||
var offset = tmp.start.column - range.start.column
|
||||
range = tmp;
|
||||
}
|
||||
var needle = session.getTextRange(range);
|
||||
|
||||
if (skip) {
|
||||
|
||||
}
|
||||
|
||||
var newRange = find(session, needle, dir);
|
||||
|
||||
newRange.cursor = dir == -1 ? newRange.start : newRange.end;
|
||||
addSelectionRange(editor, newRange)
|
||||
}
|
||||
// commands
|
||||
// add multicursor annotations to default commands
|
||||
var defaultCommands = require("./commands/default_commands").commands;
|
||||
|
||||
defaultCommands.forEach(function(command) {
|
||||
var single = RegExp(["selectall"].join("|"), "");
|
||||
var mapOverCommands = RegExp(["backspace", "del",
|
||||
"golinedown", "golineup", "gotoend", "gotoleft", "gotolineend", "gotolinestart",
|
||||
"gotoright", "gotostart", "gotowordleft", "gotowordright",
|
||||
"indent", "insertstring", "inserttext", "jumptomatching", "outdent",
|
||||
"removetolineend", "removetolinestart", "removewordleft", "removewordright",
|
||||
"selectdown", "selectleft", "selectlineend", "selectlinestart", "selectright",
|
||||
"selecttoend", "selecttolineend", "selecttolinestart", "selecttostart",
|
||||
"selectup", "selectwordleft", "selectwordright",
|
||||
"splitline", "tolowercase", "touppercase"].join("|"), "");
|
||||
|
||||
if (single.test(command.name))
|
||||
command.multiCursor = "single";
|
||||
else if (mapOverCommands.test(command.name))
|
||||
command.multiCursor = "forEach";
|
||||
else if (command.name == "transposeletters")
|
||||
command.multiCursor = transposeSelections
|
||||
});
|
||||
|
||||
// commands to to enter multicursor mode
|
||||
exports.defaultCommands = [{
|
||||
name: "addCursorAbove",
|
||||
exec: function(editor) {addCursorV(editor, -1); },
|
||||
bindKey: {win: "Alt-Shift-Up", mac: "Alt-Shift-Up"}
|
||||
}, {
|
||||
name: "addCursorBelow",
|
||||
exec: function(editor) {addCursorV(editor, 1); },
|
||||
bindKey: {win: "Alt-Shift-Down", mac: "Alt-Shift-Down"}
|
||||
}, {
|
||||
name: "selectMoreBefore",
|
||||
exec: function(editor) {addRange(editor, -1); },
|
||||
bindKey: {win: "Ctrl-Alt-Up", mac: "Ctrl-Alt-Up"}
|
||||
}, {
|
||||
name: "selectMoreAfter",
|
||||
exec: function(editor) {addRange(editor, 1); },
|
||||
bindKey: {win: "Ctrl-Alt-Down", mac: "Ctrl-Alt-Down"}
|
||||
}, {
|
||||
name: "selectNextBefore",
|
||||
exec: function(editor) {addCursorV(editor, -1, true); },
|
||||
bindKey: {win: "Ctrl-Shift-PageUp", mac: "Ctrl-Shift-PageUp"}
|
||||
}, {
|
||||
name: "selectNextAfter",
|
||||
exec: function(editor) {addCursorV(editor, 1, true); },
|
||||
bindKey: {win: "Ctrl-Shift-PageDown", mac: "Ctrl-Shift-PageDown"}
|
||||
}, {
|
||||
name: "splitIntoLines",
|
||||
exec: function(editor) {splitIntoLines(editor); },
|
||||
bindKey: {win: "Ctrl-Shift-L", mac: "Ctrl-Shift-L"}
|
||||
}, ];
|
||||
|
||||
// commands active when multiple cursors are present
|
||||
exports.multiEditCommands = [{
|
||||
name: "singleSelection",
|
||||
bindKey: "esc",
|
||||
exec: function(editor) {
|
||||
console.log(editor)
|
||||
exitMultiSelectMode(editor)
|
||||
},
|
||||
}];
|
||||
|
||||
var HashHandler = require("ace/keyboard/hash_handler").HashHandler;
|
||||
exports.keyboardHandler = new HashHandler(exports.multiEditCommands);
|
||||
|
||||
// mouse
|
||||
function isSamePoint(p1, p2) {
|
||||
return p1.row == p2.row && p1.column == p2.column
|
||||
}
|
||||
function onMouseDown(e) {
|
||||
var ev = e.domEvent;
|
||||
var alt = ev.altKey;
|
||||
var shift = ev.shiftKey;
|
||||
var ctrl = ev.ctrlKey;
|
||||
var button = e.getButton();
|
||||
|
||||
if (!ctrl && !alt) {
|
||||
if (e.editor.selection.rangeCount > 1) {
|
||||
if (button == 0) {
|
||||
exitMultiSelectMode(e.editor)
|
||||
} else if (button == 2) {
|
||||
var editor = e.editor;
|
||||
var selectionEmpty = editor.selection.isEmpty()
|
||||
editor.textInput.onContextMenu({x: e.clientX, y: e.clientY}, selectionEmpty);
|
||||
event.capture(editor.container, function(){}, editor.textInput.onContextMenuClose);
|
||||
e.stop();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
// patch
|
||||
// adds multicursor support to a session
|
||||
exports.onSessionChange = function(e) {
|
||||
var session = e.session;
|
||||
if (!session.multiSelect) {
|
||||
session.$selectionMarkers = [];
|
||||
session.selection.$initRangeList();
|
||||
session.multiSelect = session.selection;
|
||||
}
|
||||
this.multiSelect = session.multiSelect;
|
||||
|
||||
var editor = e.editor;
|
||||
var selection = editor.selection;
|
||||
var isMultiSelect = selection.rangeCount > 1
|
||||
var pos = e.getDocumentPosition();
|
||||
var rangeList = selection.rangeList;
|
||||
var cursor = selection.getCursor()
|
||||
var inSelection = e.inSelection() || (selection.isEmpty() && isSamePoint(pos, cursor));
|
||||
var oldSession = e.oldSession;
|
||||
if (oldSession) {
|
||||
// todo use events
|
||||
if (oldSession.multiSelect && oldSession.multiSelect.editor == this)
|
||||
oldSession.multiSelect.editor = null;
|
||||
|
||||
if (ctrl && !shift && !alt && button == 0) {
|
||||
if (!isMultiSelect && inSelection)
|
||||
return // dragging
|
||||
session.multiSelect.removeEventListener("addRange", this.$onAddRange);
|
||||
session.multiSelect.removeEventListener("removeRange", this.$onRemoveRange);
|
||||
session.multiSelect.removeEventListener("multiSelect", this.$onMultiSelect);
|
||||
session.multiSelect.removeEventListener("singleSelect", this.$onSingleSelect);
|
||||
}
|
||||
|
||||
if (!isMultiSelect) {
|
||||
addSelectionRange(editor, selection.toOrientedRange())
|
||||
}
|
||||
if (inSelection)
|
||||
selection.clearSelection();
|
||||
|
||||
selection.secondarySelections.push(selection)
|
||||
selection.rangeCount++
|
||||
var oldRange = rangeList.substractPoint(pos)
|
||||
|
||||
event.capture(editor.container, function(){}, function() {
|
||||
var i = selection.secondarySelections.indexOf(selection);
|
||||
if (i != -1) {
|
||||
selection.rangeCount--
|
||||
selection.secondarySelections.splice(i, 1);
|
||||
}
|
||||
|
||||
var tmpSel = selection.toOrientedRange();
|
||||
|
||||
if (oldRange && oldRange.isEmpty() && tmpSel.isEequal(oldRange)) {
|
||||
var range = selection.rangeList.all[0]
|
||||
editor.selection.rangeList._emit("remove", {ranges: []})
|
||||
selection.setSelectionRange(range, range.cursor == range.start)
|
||||
selection._emit("changeSelection");
|
||||
selection._emit("changeCursor");
|
||||
return;
|
||||
}
|
||||
|
||||
addSelectionRange(editor, tmpSel)
|
||||
});
|
||||
|
||||
//e.stop()
|
||||
} else if (!shift && alt && button == 0) {
|
||||
e.stop()
|
||||
var mouseX = e.pageX, mouseY = e.pageY;
|
||||
var onMouseSelection = function(e) {
|
||||
mouseX = event.getDocumentX(e);
|
||||
mouseY = event.getDocumentY(e);
|
||||
};
|
||||
|
||||
selection.moveCursorToPosition(pos);
|
||||
selection.clearSelection();
|
||||
if (!isMultiSelect) {
|
||||
enterMultiSelectMode(editor)
|
||||
selection.rangeCount = Infinity
|
||||
}
|
||||
|
||||
|
||||
var rectSel = []
|
||||
selection.secondarySelections = rectSel
|
||||
|
||||
var session = editor.session
|
||||
var style = editor.getSelectionStyle();
|
||||
function addMarker(range) {
|
||||
range.marker = session.addMarker(range, "ace_selection", style);
|
||||
}
|
||||
function removeMarker(range) {
|
||||
session.removeMarker(range.marker);
|
||||
}
|
||||
|
||||
|
||||
|
||||
var onMouseSelectionEnd = function(e) {
|
||||
clearInterval(timerId);
|
||||
rectSel.forEach(removeMarker)
|
||||
selection.secondarySelections = [];
|
||||
for (var i = rectSel.length; i--; )
|
||||
addSelectionRange(editor, rectSel[i])
|
||||
|
||||
if (selection.rangeCount == Infinity) {
|
||||
selection.rangeCount = selection.rangeList.all.length + selection.secondarySelections.length;
|
||||
|
||||
if (selection.rangeCount <= 1)
|
||||
exitMultiSelectMode(editor)
|
||||
}
|
||||
};
|
||||
|
||||
var anchor = selection.getCursor();
|
||||
var screenAnchor = session.documentToScreenPosition(anchor);
|
||||
var screenCursor = screenAnchor
|
||||
var screenLength = session.getScreenLength() - 1
|
||||
|
||||
var onSelectionInterval = function() {
|
||||
var newCursor = editor.renderer.pixelToScreenCoordinates(mouseX, mouseY);
|
||||
if (isSamePoint(screenCursor, newCursor))
|
||||
return
|
||||
rectSel.forEach(removeMarker)
|
||||
rectSel.splice(0, rectSel.length)
|
||||
screenCursor = newCursor
|
||||
var xBackwards = screenCursor.column < screenAnchor.column
|
||||
if (xBackwards) {
|
||||
var startColumn = screenCursor.column
|
||||
var endColumn = screenAnchor.column
|
||||
} else {
|
||||
var startColumn = screenAnchor.column
|
||||
var endColumn = screenCursor.column
|
||||
}
|
||||
var yBackwards = screenCursor.row < screenAnchor.row
|
||||
if (yBackwards) {
|
||||
var startRow = screenCursor.row
|
||||
var endRow = screenAnchor.row
|
||||
} else {
|
||||
var startRow = screenAnchor.row
|
||||
var endRow = screenCursor.row
|
||||
}
|
||||
if (startColumn < 0)
|
||||
startColumn = 0
|
||||
if (startRow < 0)
|
||||
startRow = 0
|
||||
if (endRow > screenLength)
|
||||
endRow = screenLength
|
||||
|
||||
for (var row = startRow; row <= endRow; row++) {
|
||||
var r = Range.fromPoints(
|
||||
session.screenToDocumentPosition(row, startColumn),
|
||||
session.screenToDocumentPosition(row, endColumn)
|
||||
)
|
||||
r.cursor = xBackwards ? r.start : r.end
|
||||
rectSel.push(r)
|
||||
}
|
||||
|
||||
rectSel.forEach(addMarker)
|
||||
var lastIndex = yBackwards ? 0 : rectSel.length - 1
|
||||
selection.moveCursorToPosition(rectSel[lastIndex].cursor);
|
||||
selection.clearSelection()
|
||||
editor.renderer.scrollCursorIntoView();
|
||||
|
||||
editor.renderer.updateCursor();
|
||||
editor.renderer.updateBackMarkers();
|
||||
};
|
||||
|
||||
event.capture(editor.container, onMouseSelection, onMouseSelectionEnd);
|
||||
var timerId = setInterval(onSelectionInterval, 20);
|
||||
|
||||
return e.preventDefault();
|
||||
}
|
||||
session.multiSelect.on("addRange", this.$onAddRange);
|
||||
session.multiSelect.on("removeRange", this.$onRemoveRange);
|
||||
session.multiSelect.on("multiSelect", this.$onMultiSelect);
|
||||
session.multiSelect.on("singleSelect", this.$onSingleSelect);
|
||||
}
|
||||
|
||||
// MultiCursor
|
||||
// adds multicursor support to editor instance
|
||||
function MultiSelect(editor) {
|
||||
initSession(editor.session);
|
||||
editor.on("changeSession", function(e) {
|
||||
initSession(e.session)
|
||||
}.bind(editor));
|
||||
editor.$onAddRange = editor.$onAddRange.bind(editor);
|
||||
editor.$onRemoveRange = editor.$onRemoveRange.bind(editor);
|
||||
editor.$onMultiSelect = editor.$onMultiSelect.bind(editor);
|
||||
editor.$onSingleSelect = editor.$onSingleSelect.bind(editor);
|
||||
|
||||
editor.selection.rangeList.on("remove", function(e) {
|
||||
var ranges = e.ranges;
|
||||
for (var i = ranges.length; i--; ) {
|
||||
var range = ranges[i];
|
||||
if (range.marker != null)
|
||||
this.session.removeMarker(range.marker);
|
||||
|
||||
this.rangeCount --;
|
||||
}
|
||||
|
||||
if (this.rangeCount == 1 && editor.inMultiSelectMode)
|
||||
exitMultiSelectMode(editor)
|
||||
}.bind(editor.selection));
|
||||
exports.onSessionChange.call(editor, editor);
|
||||
editor.on("changeSession", exports.onSessionChange.bind(editor));
|
||||
|
||||
editor.on("mousedown", onMouseDown);
|
||||
editor.commands.addCommands(exports.defaultCommands);
|
||||
editor.commands.addCommands(exports.commands.defaultCommands);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -85,9 +85,9 @@ var RangeList = function(startRow, startColumn, endRow, endColumn) {
|
|||
endIndex++;
|
||||
|
||||
var removed = this.ranges.splice(startIndex, endIndex - startIndex, range);
|
||||
this._emit("add", {range: range});
|
||||
if (removed.length)
|
||||
this._emit("remove", {ranges: removed});
|
||||
this._emit("add", {range: range});
|
||||
return startIndex;
|
||||
};
|
||||
|
||||
|
|
@ -143,6 +143,12 @@ var RangeList = function(startRow, startColumn, endRow, endColumn) {
|
|||
return this.pointIndex(pos) >= 0;
|
||||
};
|
||||
|
||||
this.rangeAtPoint = function(pos) {
|
||||
var i = this.pointIndex(pos);
|
||||
if (i >= 0)
|
||||
return this.ranges[i];
|
||||
};
|
||||
|
||||
|
||||
this.clipRows = function(startRow, endRow) {
|
||||
var list = this.ranges;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue