overuse of events is bad:(

This commit is contained in:
nightwing 2012-04-03 00:06:07 +04:00
commit 346ae096b3
5 changed files with 581 additions and 503 deletions

View file

@ -40,23 +40,23 @@ define(function(require, exports, module) {
// add multiSelectAction annotations to default commands // add multiSelectAction annotations to default commands
require("./default_commands").commands.forEach(function(command) { require("./default_commands").commands.forEach(function(command) {
var single = RegExp(["selectall"].join("|"), ""); var single = RegExp(["selectall"].join("|"), "");
var mapOver = RegExp(["backspace", "del", var mapOver = RegExp(["backspace", "del",
"golinedown", "golineup", "gotoend", "gotoleft", "gotolineend", "gotolinestart", "golinedown", "golineup", "gotoend", "gotoleft", "gotolineend", "gotolinestart",
"gotoright", "gotostart", "gotowordleft", "gotowordright", "gotoright", "gotostart", "gotowordleft", "gotowordright",
"indent", "insertstring", "inserttext", "jumptomatching", "outdent", "indent", "insertstring", "inserttext", "jumptomatching", "outdent",
"removetolineend", "removetolinestart", "removewordleft", "removewordright", "removetolineend", "removetolinestart", "removewordleft", "removewordright",
"selectdown", "selectleft", "selectlineend", "selectlinestart", "selectright", "selectdown", "selectleft", "selectlineend", "selectlinestart", "selectright",
"selecttoend", "selecttolineend", "selecttolinestart", "selecttostart", "selecttoend", "selecttolineend", "selecttolinestart", "selecttostart",
"selectup", "selectwordleft", "selectwordright", "selectup", "selectwordleft", "selectwordright",
"splitline", "tolowercase", "touppercase"].join("|"), ""); "splitline", "tolowercase", "touppercase"].join("|"), "");
if (single.test(command.name)) if (single.test(command.name))
command.multiSelectAction = "single"; command.multiSelectAction = "single";
else if (mapOver.test(command.name)) else if (mapOver.test(command.name))
command.multiSelectAction = "forEach"; command.multiSelectAction = "forEach";
else if (command.name == "transposeletters") else if (command.name == "transposeletters")
command.multiSelectAction = function(editor) {editor.transposeSelections(1); } command.multiSelectAction = function(editor) {editor.transposeSelections(1); }
}); });
// commands to enter multiselect mode // commands to enter multiselect mode
@ -64,37 +64,47 @@ exports.defaultCommands = [{
name: "addCursorAbove", name: "addCursorAbove",
exec: function(editor) { editor.selectMoreLines(-1); }, exec: function(editor) { editor.selectMoreLines(-1); },
bindKey: {win: "Ctrl-Alt-Up", mac: "Ctrl-Alt-Up"}, bindKey: {win: "Ctrl-Alt-Up", mac: "Ctrl-Alt-Up"},
readonly: true readonly: true
}, { }, {
name: "addCursorBelow", name: "addCursorBelow",
exec: function(editor) { editor.selectMoreLines(1); }, exec: function(editor) { editor.selectMoreLines(1); },
bindKey: {win: "Ctrl-Alt-Down", mac: "Ctrl-Alt-Down"}, bindKey: {win: "Ctrl-Alt-Down", mac: "Ctrl-Alt-Down"},
readonly: true readonly: true
}, {
name: "addCursorAboveSkipCurrent",
exec: function(editor) { editor.selectMoreLines(-1, true); },
bindKey: {win: "Ctrl-Alt-Shift-Up", mac: "Ctrl-Alt-Shift-Up"},
readonly: true
}, {
name: "addCursorBelowSkipCurrent",
exec: function(editor) { editor.selectMoreLines(1, true); },
bindKey: {win: "Ctrl-Alt-Shift-Down", mac: "Ctrl-Alt-Shift-Down"},
readonly: true
}, { }, {
name: "selectMoreBefore", name: "selectMoreBefore",
exec: function(editor) { editor.selectMore(-1); }, exec: function(editor) { editor.selectMore(-1); },
bindKey: {win: "Ctrl-Alt-Left", mac: "Ctrl-Alt-Left"}, bindKey: {win: "Ctrl-Alt-Left", mac: "Ctrl-Alt-Left"},
readonly: true readonly: true
}, { }, {
name: "selectMoreAfter", name: "selectMoreAfter",
exec: function(editor) { editor.selectMore(1); }, exec: function(editor) { editor.selectMore(1); },
bindKey: {win: "Ctrl-Alt-Right", mac: "Ctrl-Alt-Right"}, bindKey: {win: "Ctrl-Alt-Right", mac: "Ctrl-Alt-Right"},
readonly: true readonly: true
}, { }, {
name: "selectNextBefore", name: "selectNextBefore",
exec: function(editor) { editor.selectMore(-1, true); }, exec: function(editor) { editor.selectMore(-1, true); },
bindKey: {win: "Ctrl-Alt-Shift-Left", mac: "Ctrl-Alt-Shift-Left"}, bindKey: {win: "Ctrl-Alt-Shift-Left", mac: "Ctrl-Alt-Shift-Left"},
readonly: true readonly: true
}, { }, {
name: "selectNextAfter", name: "selectNextAfter",
exec: function(editor) { editor.selectMore(1, true); }, exec: function(editor) { editor.selectMore(1, true); },
bindKey: {win: "Ctrl-Alt-Shift-Right", mac: "Ctrl-Alt-Shift-Right"}, bindKey: {win: "Ctrl-Alt-Shift-Right", mac: "Ctrl-Alt-Shift-Right"},
readonly: true readonly: true
}, { }, {
name: "splitIntoLines", name: "splitIntoLines",
exec: function(editor) { editor.multiSelect.splitIntoLines(); }, exec: function(editor) { editor.multiSelect.splitIntoLines(); },
bindKey: {win: "Ctrl-Shift-L", mac: "Ctrl-Shift-L"}, bindKey: {win: "Ctrl-Shift-L", mac: "Ctrl-Shift-L"},
readonly: true readonly: true
}, ]; }, ];
// commands active in multiselect mode // commands active in multiselect mode
@ -102,7 +112,7 @@ exports.multiEditCommands = [{
name: "singleSelection", name: "singleSelection",
bindKey: "esc", bindKey: "esc",
exec: function(editor) { editor.exitMultiSelectMode(); }, exec: function(editor) { editor.exitMultiSelectMode(); },
readonly: true readonly: true
}]; }];
var HashHandler = require("../keyboard/hash_handler").HashHandler; var HashHandler = require("../keyboard/hash_handler").HashHandler;

View file

@ -50,11 +50,11 @@ function onMouseDown(e) {
var ev = e.domEvent; var ev = e.domEvent;
var alt = ev.altKey; var alt = ev.altKey;
var shift = ev.shiftKey; var shift = ev.shiftKey;
var ctrl = ev.ctrlKey; var ctrl = e.getAccelKey();
var button = e.getButton(); var button = e.getButton();
if (!ctrl && !alt) { if (!ctrl && !alt) {
if (e.editor.selection.rangeCount > 1) { if (e.editor.inMultiSelectMode) {
if (button == 0) { if (button == 0) {
e.editor.exitMultiSelectMode(); e.editor.exitMultiSelectMode();
} else if (button == 2) { } else if (button == 2) {
@ -70,12 +70,71 @@ function onMouseDown(e) {
var editor = e.editor; var editor = e.editor;
var selection = editor.selection; var selection = editor.selection;
var isMultiSelect = selection.rangeCount > 1 var isMultiSelect = editor.inMultiSelectMode;
var pos = e.getDocumentPosition(); var pos = e.getDocumentPosition();
var rangeList = selection.rangeList;
var cursor = selection.getCursor() var cursor = selection.getCursor()
var inSelection = e.inSelection() || (selection.isEmpty() && isSamePoint(pos, cursor)); var inSelection = e.inSelection() || (selection.isEmpty() && isSamePoint(pos, cursor));
var mouseX = e.pageX, mouseY = e.pageY;
var clickX = mouseX, clickY = mouseY;
var onMouseSelection = function(e) {
mouseX = event.getDocumentX(e);
mouseY = event.getDocumentY(e);
};
var blockSelect = 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.updateSelectionMarkers()
};
var normalSelect = function() {
var clickSelection
if (_self.$clickSelection) {
if (_self.$clickSelection.contains(cursor.row, cursor.column)) {
editor.selection.setSelectionRange(_self.$clickSelection);
}
else {
if (_self.$clickSelection.compare(cursor.row, cursor.column) == -1) {
anchor = _self.$clickSelection.end;
}
else {
anchor = _self.$clickSelection.start;
}
editor.selection.setSelectionAnchor(anchor.row, anchor.column);
editor.selection.selectToPosition(cursor);
}
}
else {
editor.selection.selectToPosition(cursor);
}
editor.renderer.scrollCursorIntoView();
};
var session = editor.session;
var anchor = selection.getCursor();
var screenAnchor = editor.renderer.pixelToScreenCoordinates(mouseX, mouseY);
var clippedAnchor = session.documentToScreenPosition(anchor);
var screenCursor = screenAnchor;
onSelectionInterval = blockSelect;
if (ctrl && !shift && !alt && button == 0) { if (ctrl && !shift && !alt && button == 0) {
if (!isMultiSelect && inSelection) if (!isMultiSelect && inSelection)
return // dragging return // dragging
@ -86,23 +145,23 @@ function onMouseDown(e) {
if (inSelection) if (inSelection)
selection.clearSelection(); selection.clearSelection();
var helper = selection.toOrientedRange(); var helper = selection.toOrientedRange();
editor.addSelectionMarker(helper); editor.addSelectionMarker(helper);
var oldRange = rangeList.rangeAtPoint(pos); var oldRange = selection.rangeList.rangeAtPoint(pos);
event.capture(editor.container, function(){}, function() { event.capture(editor.container, function(){}, function() {
editor.removeSelectionMarkers([helper]); editor.removeSelectionMarkers([helper]);
var tmpSel = selection.toOrientedRange(); var tmpSel = selection.toOrientedRange();
if (oldRange && tmpSel.isEmpty() && isSamePoint(oldRange.cursor, tmpSel.cursor)) { if (oldRange && tmpSel.isEmpty() && isSamePoint(oldRange.cursor, tmpSel.cursor)) {
if (selection.rangeCount > 1) { if (selection.rangeCount > 1) {
range = editor.selection.rangeList.substractPoint(tmpSel.cursor); editor.selection.substractPoint(tmpSel.cursor);
var range = editor.selection.rangeList.all[0]; var range = editor.selection.ranges[0];
if (range) if (range)
editor.selection.addRange(range); editor.selection.addRange(range);
return; return;
} }
} }
selection.addRange(tmpSel); selection.addRange(tmpSel);
@ -111,20 +170,18 @@ function onMouseDown(e) {
//e.stop() //e.stop()
} else if (!shift && alt && button == 0) { } else if (!shift && alt && button == 0) {
e.stop() 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(); if (isMultiSelect && !ctrl) {
selection.toSingleRange();
} else if (!isMultiSelect && ctrl) {
selection.addRange();
} }
selection.moveCursorToPosition(pos);
selection.clearSelection(); selection.moveCursorToPosition(pos);
selection.clearSelection();
var rectSel = []; var rectSel = [];
var session = editor.session;
var onMouseSelectionEnd = function(e) { var onMouseSelectionEnd = function(e) {
clearInterval(timerId); clearInterval(timerId);
@ -133,34 +190,12 @@ function onMouseDown(e) {
selection.addRange(rectSel[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); event.capture(editor.container, onMouseSelection, onMouseSelectionEnd);
var timerId = setInterval(onSelectionInterval, 20); var timerId = setInterval(function() {onSelectionInterval()}, 20);
return e.preventDefault(); return e.preventDefault();
} }

View file

@ -41,7 +41,7 @@ define(function(require, exports, module) {
var RangeList = require("./range_list").RangeList; var RangeList = require("./range_list").RangeList;
var Range = require("./range").Range; var Range = require("./range").Range;
var Selection = require("./selection").Selection; var Selection = require("./selection").Selection;
var onMouseDown = require("./mouse/multi_select_mouse_handler").onMouseDown; var onMouseDown = require("./mouse/multi_select_handler").onMouseDown;
exports.commands = require("./commands/multi_select_commands"); exports.commands = require("./commands/multi_select_commands");
// Todo // Todo
@ -49,292 +49,330 @@ var Search = require("ace/search").Search
var search = new Search var search = new Search
function find(session, needle, dir) { function find(session, needle, dir) {
search.$options.wrap = true; search.$options.wrap = true;
search.$options.needle = needle; search.$options.needle = needle;
search.$options.backwards = dir == -1; search.$options.backwards = dir == -1;
return search.find(session) return search.find(session)
} }
// extend EditSession // extend EditSession
var EditSession = require("./edit_session").EditSession; var EditSession = require("./edit_session").EditSession;
;(function() { ;(function() {
this.getSelectionMarkers = function() { this.getSelectionMarkers = function() {
return this.$selectionMarkers; return this.$selectionMarkers;
}; };
}).call(EditSession.prototype); }).call(EditSession.prototype);
// extend Selection // extend Selection
;(function() { ;(function() {
this.addRange = function(range) { // list of ranges in reverse addition order
if (!range.cursor) this.ranges = null;
range.cursor = range.end; // automatically sorted list of ranges
this.rangeList = null;
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; * add a range to selection entering multiselect mode if necessary
*/
if (this.rangeCount > 1 && !this.inMultiSelectMode) { this.addRange = function(range) {
this._emit("multiSelect"); if (!this.inMultiSelectMode && this.rangeCount == 0) {
this.inMultiSelectMode = true; var oldRange = this.toOrientedRange();
this.$undoSelect = false; if (!range || !range.isEqual(oldRange)) {
this.rangeList.attach(this.session); this.rangeList.add(oldRange);
} this.$onAddRange(oldRange);
}
}
this.fromOrientedRange(range); if (!range)
if (this.rangeCount >= 1) return;
this._emit("addRange", {range: range});
};
this.single = function(range) { if (!range.cursor)
range = range || this.rangeList.all[0]; range.cursor = range.end;
this.rangeList.removeAll();
range && this.fromOrientedRange(range);
};
this.$onRemoveRange = function(e) { var removed = this.rangeList.add(range);
this.rangeCount = this.rangeList.ranges.length;
this._emit("removeRange", e);
if (this.rangeCount <= 1 && this.inMultiSelectMode) { this.fromOrientedRange(range);
this.inMultiSelectMode = false; this.$onAddRange(range);
this._emit("singleSelect");
this.$undoSelect = true;
this.rangeList.detach(this.session);
if (this.rangeCount == 1) if (removed.length)
this.single(); this.$onRemoveRange(removed);
}
};
// adds multicursor support to selection if (this.rangeCount > 0 && !this.inMultiSelectMode) {
this.$initRangeList = function() { this._emit("multiSelect");
if (this.rangeList) this.inMultiSelectMode = true;
return; this.session.$undoSelect = false;
this.rangeList.attach(this.session);
}
};
var rangeList = new RangeList; this.toSingleRange = function(range) {
// list of ranges in reverse addition order range = range || this.ranges[0];
// rangeList.all[0] is the same as selection.getRange var removed = this.rangeList.removeAll();
rangeList.all = []; if (removed.length)
rangeList.on("add", function(e) { this.$onRemoveRange(removed);
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; range && this.fromOrientedRange(range);
this.cursor = this.selectionLead; };
this.rangeCount = 1; this.substractPoint = function(pos) {
this.rangeList.on("remove", this.$onRemoveRange.bind(this)); var removed = this.rangeList.substractPoint(pos);
}; if (removed) {
this.getAllRanges = function() { this.$onRemoveRange(removed);
return this.rangeList.ranges.concat() return removed[0]
}; }
};
this.splitIntoLines = function () { this.mergeOverlappingRanges = function() {
if (this.rangeCount > 1) { var removed = this.rangeList.merge();
var ranges = this.rangeList.ranges; var lastRange = this.ranges[0];
var lastRange = ranges[ranges.length - 1] if (removed.length)
var range = Range.fromPoints(ranges[0].start, lastRange.end) this.$onRemoveRange(removed);
this.single() if (lastRange)
this.setSelectionRange(range, lastRange.cursor == lastRange.start) this.fromOrientedRange(lastRange);
} 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; this.$onAddRange = function(range) {
if (xBackwards) { this.rangeCount = this.rangeList.ranges.length;
var startColumn = screenCursor.column; this.ranges.unshift(range);
var endColumn = screenAnchor.column; this._emit("addRange", {range: range});
} 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) this.$onRemoveRange = function(removed) {
includeEmptyLines = true; this.rangeCount = this.rangeList.ranges.length;
if (this.rangeCount == 1 && this.inMultiSelectMode) {
for (var row = startRow; row <= endRow; row++) { removed.push(this.rangeList.ranges.pop());
var range = Range.fromPoints( this.rangeCount = 0;
this.session.screenToDocumentPosition(row, startColumn), }
this.session.screenToDocumentPosition(row, endColumn)
); for (var i = removed.length; i--; ) {
if (range.isEmpty()) { var index = this.ranges.indexOf(removed[i]);
if (docEnd && isSamePoint(range.end, docEnd)) this.ranges.splice(index, 1);
break; }
var docEnd = range.end;
} console.log(this.ranges+'')
range.cursor = xBackwards ? range.start : range.end; this._emit("removeRange", {ranges: removed});
rectSel.push(range);
} if (this.rangeCount == 0 && this.inMultiSelectMode) {
if (yBackwards) this.inMultiSelectMode = false;
rectSel.reverse(); this._emit("singleSelect");
this.session.$undoSelect = true;
if (!includeEmptyLines) { this.rangeList.detach(this.session);
var end = rectSel.length - 1; }
while (rectSel[end].isEmpty() && end > 0) };
end--;
if (end > 0) { // adds multicursor support to selection
var start = 0; this.$initRangeList = function() {
while (rectSel[start].isEmpty()) if (this.rangeList)
start++; return;
}
for (var i = end; i >= start; i--) { this.rangeList = new RangeList;
if (rectSel[i].isEmpty()) this.ranges = [];
rectSel.splice(i, 1); this.rangeCount = 0;
} };
}
this.getAllRanges = function() {
return rectSel; return this.rangeList.ranges.concat()
}; };
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.toSingleRange()
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);
}
};
/**
* gets list of ranges composing rectangular block on the screen
* @includeEmptyLines if true includes ranges inside the block which
* are empty becuase of the clipping
*/
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); }).call(Selection.prototype);
// extend Editor // extend Editor
var Editor = require("./editor").Editor; var Editor = require("./editor").Editor;
;(function() { ;(function() {
this.addSelectionMarker = function(orientedRange) { this.updateSelectionMarkers = function(orientedRange) {
if (!orientedRange.cursor) this.renderer.updateCursor();
orientedRange.cursor = orientedRange.end; this.renderer.updateBackMarkers();
};
this.addSelectionMarker = function(orientedRange) {
if (!orientedRange.cursor)
orientedRange.cursor = orientedRange.end;
var style = this.getSelectionStyle(); var style = this.getSelectionStyle();
orientedRange.marker = this.session.addMarker(orientedRange, "ace_selection", style); orientedRange.marker = this.session.addMarker(orientedRange, "ace_selection", style);
this.session.$selectionMarkers.push(orientedRange); this.session.$selectionMarkers.push(orientedRange);
this.session.selectionMarkerCount = this.session.$selectionMarkers.length; this.session.selectionMarkerCount = this.session.$selectionMarkers.length;
return orientedRange return orientedRange;
}; };
this.removeSelectionMarkers = function(ranges) { this.removeSelectionMarkers = function(ranges) {
for (var i = ranges.length; i--; ) { for (var i = ranges.length; i--; ) {
var range = ranges[i]; var range = ranges[i];
if (!range.marker) if (!range.marker)
continue; continue;
this.session.removeMarker(range.marker); this.session.removeMarker(range.marker);
var index = this.session.$selectionMarkers.indexOf(range); var index = this.session.$selectionMarkers.indexOf(range);
if (index != -1) if (index != -1)
this.session.$selectionMarkers.splice(index, 1) this.session.$selectionMarkers.splice(index, 1)
} }
this.session.selectionMarkerCount = this.session.$selectionMarkers.length; this.session.selectionMarkerCount = this.session.$selectionMarkers.length;
}; };
this.$onAddRange = function(e) { this.$onAddRange = function(e) {
this.addSelectionMarker(e.range); this.addSelectionMarker(e.range);
this.renderer.updateCursor(); this.renderer.updateCursor();
this.renderer.updateBackMarkers(); this.renderer.updateBackMarkers();
}; };
this.$onRemoveRange = function(e) { this.$onRemoveRange = function(e) {
this.removeSelectionMarkers(e.ranges); this.removeSelectionMarkers(e.ranges);
this.renderer.updateCursor(); this.renderer.updateCursor();
this.renderer.updateBackMarkers(); this.renderer.updateBackMarkers();
}; };
this.$onMultiSelect = function(e) { this.$onMultiSelect = function(e) {
if (this.inMultiSelectMode) if (this.inMultiSelectMode)
return; return;
this.inMultiSelectMode = true; this.inMultiSelectMode = true;
this.setStyle("multiselect"); this.setStyle("multiselect");
this.keyBinding.addKeyboardHandler(exports.commands.keyboardHandler); this.keyBinding.addKeyboardHandler(exports.commands.keyboardHandler);
// FixMe // FixMe
this.commands.__SingleSelectionExec = this.commands.exec; this.commands.__SingleSelectionExec = this.commands.exec;
this.commands.exec = exports.exec; this.commands.exec = exports.exec;
this.renderer.updateCursor(); this.renderer.updateCursor();
this.renderer.updateBackMarkers(); this.renderer.updateBackMarkers();
}; };
this.$onSingleSelect = function(e) { this.$onSingleSelect = function(e) {
if (this.session.multiSelect.inVirtualMode) if (this.session.multiSelect.inVirtualMode)
return; return;
this.inMultiSelectMode = false; this.inMultiSelectMode = false;
this.unsetStyle("multiselect"); this.unsetStyle("multiselect");
this.keyBinding.removeKeyboardHandler(exports.commands.keyboardHandler); this.keyBinding.removeKeyboardHandler(exports.commands.keyboardHandler);
this.commands.exec = this.commands.__SingleSelectionExec; this.commands.exec = this.commands.__SingleSelectionExec;
this.renderer.updateCursor(); this.renderer.updateCursor();
this.renderer.updateBackMarkers(); this.renderer.updateBackMarkers();
}; };
this.forEachSelection = function(cmd, args) { this.forEachSelection = function(cmd, args) {
if (this.inVirtualSelectionMode) if (this.inVirtualSelectionMode)
return; return;
var session = this.session var session = this.session
var selection = this.selection var selection = this.selection
var rangeList = selection.rangeList var rangeList = selection.rangeList
var reg = selection._eventRegistry; var reg = selection._eventRegistry;
selection._eventRegistry = {}; selection._eventRegistry = {};
var tmpSel = new Selection(session); var tmpSel = new Selection(session);
this.inVirtualSelectionMode = true; this.inVirtualSelectionMode = true;
for (var i = rangeList.ranges.length; i--;) { for (var i = rangeList.ranges.length; i--;) {
tmpSel.fromOrientedRange(rangeList.ranges[i]); tmpSel.fromOrientedRange(rangeList.ranges[i]);
this.selection = session.selection = tmpSel; this.selection = session.selection = tmpSel;
cmd.exec(this, args || {}); cmd.exec(this, args || {});
tmpSel.toOrientedRange(rangeList.ranges[i]); tmpSel.toOrientedRange(rangeList.ranges[i]);
} }
tmpSel.detach(); tmpSel.detach();
this.selection = session.selection = selection; this.selection = session.selection = selection;
this.inVirtualSelectionMode = false; this.inVirtualSelectionMode = false;
selection._eventRegistry = reg; selection._eventRegistry = reg;
rangeList.merge(); selection.mergeOverlappingRanges();
var lastRange = selection.rangeList.all[0] this.onCursorChange();
lastRange && selection.fromOrientedRange(lastRange); this.onSelectionChange();
};
selection._emit("changeSelection") this.exitMultiSelectMode = function() {
selection._emit("changeCursor") if (this.inVirtualSelectionMode)
this.renderer.updateCursor(); return;
this.renderer.updateBackMarkers(); this.multiSelect.toSingleRange();
}; };
this.exitMultiSelectMode = function() { // todo route copy/cut/paste through commandmanager
if (this.inVirtualSelectionMode) this.getCopyText = function() {
return;
this.multiSelect.single();
};
// todo route copy/cut/paste through commandmanager
this.getCopyText = function() {
var text = ""; var text = "";
if (this.inMultiSelectMode) { if (this.inMultiSelectMode) {
var ranges = this.multiSelect.rangeList.ranges; var ranges = this.multiSelect.rangeList.ranges;
for (var i = 0; i < ranges.length; i++) { for (var i = 0; i < ranges.length; i++) {
text += this.session.getTextRange(ranges[i]); text += this.session.getTextRange(ranges[i]);
} }
} else if (!this.selection.isEmpty()) } else if (!this.selection.isEmpty())
text = this.session.getTextRange(this.getSelectionRange()); text = this.session.getTextRange(this.getSelectionRange());
@ -342,120 +380,121 @@ var Editor = require("./editor").Editor;
return text; return text;
}; };
this.onCut = function() { this.onCut = function() {
var cmd = { var cmd = {
name: "cut", name: "cut",
exec: function(editor) { exec: function(editor) {
var range = editor.getSelectionRange(); var range = editor.getSelectionRange();
editor._emit("cut", range); editor._emit("cut", range);
if (!editor.selection.isEmpty()) { if (!editor.selection.isEmpty()) {
editor.session.remove(range); editor.session.remove(range);
editor.clearSelection(); editor.clearSelection();
} }
}, },
readonly: true, readonly: true,
multiSelectAction: "forEach" multiSelectAction: "forEach"
} }
this.commands.exec(cmd, this) this.commands.exec(cmd, this)
}; };
// commands // commands
this.selectMoreLines = function(dir, skip) { this.selectMoreLines = function(dir, skip) {
var range = this.selection.toOrientedRange(); var range = this.selection.toOrientedRange();
var isBackwards = range.cursor == range.end; var isBackwards = range.cursor == range.end;
var screenLead = this.session.documentToScreenPosition(range.cursor); var screenLead = this.session.documentToScreenPosition(range.cursor);
if (this.selection.$desiredColumn) if (this.selection.$desiredColumn)
screenLead.column = this.selection.$desiredColumn; screenLead.column = this.selection.$desiredColumn;
var lead = this.session.screenToDocumentPosition(screenLead.row + dir, screenLead.column); var lead = this.session.screenToDocumentPosition(screenLead.row + dir, screenLead.column);
if (!range.isEmpty()) { if (!range.isEmpty()) {
var screenAnchor = this.session.documentToScreenPosition(isBackwards ? range.end : range.start); var screenAnchor = this.session.documentToScreenPosition(isBackwards ? range.end : range.start);
var anchor = this.session.screenToDocumentPosition(screenAnchor.row + dir, screenAnchor.column); var anchor = this.session.screenToDocumentPosition(screenAnchor.row + dir, screenAnchor.column);
} else { } else {
var anchor = lead; var anchor = lead;
} }
if (isBackwards) { if (isBackwards) {
var newRange = Range.fromPoints(lead, anchor); var newRange = Range.fromPoints(lead, anchor);
newRange.cursor = newRange.start; newRange.cursor = newRange.start;
} else { } else {
var newRange = Range.fromPoints(anchor, lead); var newRange = Range.fromPoints(anchor, lead);
newRange.cursor = newRange.end; newRange.cursor = newRange.end;
} }
newRange.desiredColumn = screenLead.column; newRange.desiredColumn = screenLead.column;
if (!this.selection.inMultiSelectMode) { if (!this.selection.inMultiSelectMode) {
this.selection.addRange(range); this.selection.addRange(range);
} else { } else {
var allRanges = this.selection.rangeList.ranges; var allRanges = this.selection.rangeList.ranges;
// remove range if at end // remove range if at end
if (skip || range.isEequal(allRanges[dir == 1 ? 0 : allRanges.length - 1])) // var atEdge = range.isEqual(allRanges[dir == 1 ? 0 : allRanges.length - 1]);
var toRemove = range.cursor; if (skip)
} var toRemove = range.cursor;
}
this.selection.addRange(newRange); this.selection.addRange(newRange);
if (toRemove) if (toRemove)
this.selection.rangeList.substractPoint(toRemove); this.selection.substractPoint(toRemove);
} }
this.transposeSelections = function(dir) { this.transposeSelections = function(dir) {
var session = this.session; var session = this.session;
var sel = session.multiSelect; var sel = session.multiSelect;
var all = sel.rangeList.all; var all = sel.ranges;
var words = []; var words = [];
for (var i = all.length; i--; ) { for (var i = all.length; i--; ) {
var range = all[i] var range = all[i]
if (range.isEmpty()) { if (range.isEmpty()) {
var tmp = session.getWordRange(range.start.row, range.start.column) var tmp = session.getWordRange(range.start.row, range.start.column)
range.start.row = tmp.start.row; range.start.row = tmp.start.row;
range.start.column = tmp.start.column; range.start.column = tmp.start.column;
range.end.row = tmp.end.row; range.end.row = tmp.end.row;
range.end.column = tmp.end.column; range.end.column = tmp.end.column;
} }
words.unshift(this.session.getTextRange(range)); words.unshift(this.session.getTextRange(range));
} }
if (dir < 0) if (dir < 0)
words.unshift(words.pop()); words.unshift(words.pop());
else else
words.push(words.shift()); words.push(words.shift());
for (var i = all.length; i--; ) { for (var i = all.length; i--; ) {
var range = all[i]; var range = all[i];
var tmp = range.clone(); var tmp = range.clone();
session.replace(range, words[i]); session.replace(range, words[i]);
range.start.row = tmp.start.row; range.start.row = tmp.start.row;
range.start.column = tmp.start.column; range.start.column = tmp.start.column;
} }
} }
this.selectMore = function (dir, skip) { this.selectMore = function (dir, skip) {
var session = this.session; var session = this.session;
var sel = session.multiSelect; var sel = session.multiSelect;
var all = sel.rangeList.all; var all = sel.ranges;
var range = sel.toOrientedRange(); var range = sel.toOrientedRange();
if (range.isEmpty()) { if (range.isEmpty()) {
var range = session.getWordRange(range.start.row, range.start.column) var range = session.getWordRange(range.start.row, range.start.column)
range.cursor = range.end; range.cursor = range.end;
this.multiSelect.addRange(range); this.multiSelect.addRange(range);
} }
var needle = session.getTextRange(range); var needle = session.getTextRange(range);
var newRange = find(session, needle, dir); var newRange = find(session, needle, dir);
if (newRange) { if (newRange) {
newRange.cursor = dir == -1 ? newRange.start : newRange.end; newRange.cursor = dir == -1 ? newRange.start : newRange.end;
this.multiSelect.addRange(newRange); this.multiSelect.addRange(newRange);
} }
if (skip) if (skip)
this.multiSelect.rangeList.substractPoint(range.cursor); this.multiSelect.substractPoint(range.cursor);
} }
}).call(Editor.prototype); }).call(Editor.prototype);
@ -476,11 +515,11 @@ exports.exec = function(command, editor, args) {
} else if (command.multiSelectAction == "forEach") { } else if (command.multiSelectAction == "forEach") {
editor.forEachSelection(command, args); editor.forEachSelection(command, args);
} else if (command.multiSelectAction == "single") { } else if (command.multiSelectAction == "single") {
editor.exitMultiSelectMode(); editor.exitMultiSelectMode();
command.exec(editor, args || {}); command.exec(editor, args || {});
} else { } else {
command.multiSelectAction(editor, args || {}); command.multiSelectAction(editor, args || {});
} }
return true; return true;
}; };
@ -494,45 +533,47 @@ function isSamePoint(p1, p2) {
// patch // patch
// adds multicursor support to a session // adds multicursor support to a session
exports.onSessionChange = function(e) { exports.onSessionChange = function(e) {
var session = e.session; var session = e.session;
if (!session.multiSelect) { if (!session.multiSelect) {
session.$selectionMarkers = []; session.$selectionMarkers = [];
session.selection.$initRangeList(); session.selection.$initRangeList();
session.multiSelect = session.selection; session.multiSelect = session.selection;
} }
this.multiSelect = session.multiSelect; this.multiSelect = session.multiSelect;
var oldSession = e.oldSession; var oldSession = e.oldSession;
if (oldSession) { if (oldSession) {
// todo use events // todo use events
if (oldSession.multiSelect && oldSession.multiSelect.editor == this) if (oldSession.multiSelect && oldSession.multiSelect.editor == this)
oldSession.multiSelect.editor = null; oldSession.multiSelect.editor = null;
session.multiSelect.removeEventListener("addRange", this.$onAddRange); session.multiSelect.removeEventListener("addRange", this.$onAddRange);
session.multiSelect.removeEventListener("removeRange", this.$onRemoveRange); session.multiSelect.removeEventListener("removeRange", this.$onRemoveRange);
session.multiSelect.removeEventListener("multiSelect", this.$onMultiSelect); session.multiSelect.removeEventListener("multiSelect", this.$onMultiSelect);
session.multiSelect.removeEventListener("singleSelect", this.$onSingleSelect); session.multiSelect.removeEventListener("singleSelect", this.$onSingleSelect);
} }
session.multiSelect.on("addRange", this.$onAddRange); session.multiSelect.on("addRange", this.$onAddRange);
session.multiSelect.on("removeRange", this.$onRemoveRange); session.multiSelect.on("removeRange", this.$onRemoveRange);
session.multiSelect.on("multiSelect", this.$onMultiSelect); session.multiSelect.on("multiSelect", this.$onMultiSelect);
session.multiSelect.on("singleSelect", this.$onSingleSelect); session.multiSelect.on("singleSelect", this.$onSingleSelect);
if (this.inMultiSelectMode != session.selection.inMultiSelectMode) { // this.$onSelectionChange = this.onSelectionChange.bind(this);
if (session.selection.inMultiSelectMode)
this.$onMultiSelect(); if (this.inMultiSelectMode != session.selection.inMultiSelectMode) {
else if (session.selection.inMultiSelectMode)
this.$onSingleSelect(); this.$onMultiSelect();
} else
this.$onSingleSelect();
}
} }
// adds multicursor support to editor instance // adds multicursor support to editor instance
function MultiSelect(editor) { function MultiSelect(editor) {
editor.$onAddRange = editor.$onAddRange.bind(editor); editor.$onAddRange = editor.$onAddRange.bind(editor);
editor.$onRemoveRange = editor.$onRemoveRange.bind(editor); editor.$onRemoveRange = editor.$onRemoveRange.bind(editor);
editor.$onMultiSelect = editor.$onMultiSelect.bind(editor); editor.$onMultiSelect = editor.$onMultiSelect.bind(editor);
editor.$onSingleSelect = editor.$onSingleSelect.bind(editor); editor.$onSingleSelect = editor.$onSingleSelect.bind(editor);
exports.onSessionChange.call(editor, editor); exports.onSessionChange.call(editor, editor);
editor.on("changeSession", exports.onSessionChange.bind(editor)); editor.on("changeSession", exports.onSessionChange.bind(editor));

View file

@ -46,8 +46,6 @@ var RangeList = function(startRow, startColumn, endRow, endColumn) {
}; };
(function() { (function() {
oop.implement(this, EventEmitter);
this.comparePoints = function(p1, p2) { this.comparePoints = function(p1, p2) {
return p1.row - p2.row || p1.column - p2.column return p1.row - p2.row || p1.column - p2.column
}; };
@ -84,25 +82,22 @@ var RangeList = function(startRow, startColumn, endRow, endColumn) {
else else
endIndex++; endIndex++;
var removed = this.ranges.splice(startIndex, endIndex - startIndex, range); return this.ranges.splice(startIndex, endIndex - startIndex, range);
if (removed.length)
this._emit("remove", {ranges: removed});
this._emit("add", {range: range});
return startIndex;
}; };
this.addList = function(list) { this.addList = function(list) {
list.forEach(this.add, this); var removed = [];
for (var i = list.length; i--; ) {
removed.push.call(removed, this.add(list[i]))
}
return removed;
}; };
this.substractPoint = function(pos) { this.substractPoint = function(pos) {
var i = this.pointIndex(pos); var i = this.pointIndex(pos);
if (i >= 0) { if (i >= 0)
var removed = this.ranges.splice(i, 1); return this.ranges.splice(i, 1);
this._emit("remove", {ranges: removed});
return removed[0]
}
}; };
// merge overlapping ranges // merge overlapping ranges
@ -131,8 +126,7 @@ var RangeList = function(startRow, startColumn, endRow, endColumn) {
i--; i--;
} }
if (removed.length) return removed;
this._emit("remove", {ranges: removed});
}; };
this.contains = function(row, column) { this.contains = function(row, column) {
@ -170,8 +164,7 @@ var RangeList = function(startRow, startColumn, endRow, endColumn) {
}; };
this.removeAll = function() { this.removeAll = function() {
if (this.ranges.length) return this.ranges.splice(0, this.ranges.length);
this._emit("remove", {ranges: this.ranges.splice(0, this.ranges.length)});
}; };
this.attach = function(session) { this.attach = function(session) {
@ -193,45 +186,45 @@ var RangeList = function(startRow, startColumn, endRow, endColumn) {
this.$onChange = function(e) { this.$onChange = function(e) {
var changeRange = e.data.range; var changeRange = e.data.range;
if (e.data.action[0] == "i"){ if (e.data.action[0] == "i"){
var start = changeRange.start; var start = changeRange.start;
var end = changeRange.end; var end = changeRange.end;
} else { } else {
var end = changeRange.start; var end = changeRange.start;
var start = changeRange.end; var start = changeRange.end;
} }
var startRow = start.row; var startRow = start.row;
var endRow = end.row; var endRow = end.row;
var lineDif = endRow - startRow; var lineDif = endRow - startRow;
var colDiff = -start.column + end.column;
var ranges = this.ranges;
for (var i=0, n = ranges.length; i < n; i++) { var colDiff = -start.column + end.column;
var r = ranges[i];
if (r.end.row < startRow)
continue;
if (r.start.row > startRow)
break;
if (r.start.row == startRow && r.start.column >= start.column ) { var ranges = this.ranges;
r.start.column += colDiff;
r.start.row += lineDif; for (var i=0, n = ranges.length; i < n; i++) {
} var r = ranges[i];
if (r.end.row == startRow && r.end.column >= start.column) { if (r.end.row < startRow)
r.end.column += colDiff; continue;
r.end.row += lineDif; if (r.start.row > startRow)
} break;
}
if (r.start.row == startRow && r.start.column >= start.column ) {
if (lineDif != 0 && i < n) { r.start.column += colDiff;
for (; i < n; i++) { r.start.row += lineDif;
var r = ranges[i]; }
r.start.row += lineDif; if (r.end.row == startRow && r.end.column >= start.column) {
r.end.row += lineDif; r.end.column += colDiff;
} r.end.row += lineDif;
} }
}
if (lineDif != 0 && i < n) {
for (; i < n; i++) {
var r = ranges[i];
r.start.row += lineDif;
r.end.row += lineDif;
}
}
}; };
}).call(RangeList.prototype); }).call(RangeList.prototype);

View file

@ -124,25 +124,24 @@ module.exports = {
new Range(8,8,9,9) new Range(8,8,9,9)
]); ]);
var removed = []; var removed = [];
rangeList.on('remove', function(e) {removed = e.ranges});
assert.equal(rangeList.ranges.length, 4); assert.equal(rangeList.ranges.length, 4);
rangeList.ranges[1].end.row = 7; rangeList.ranges[1].end.row = 7;
rangeList.merge(); removed = rangeList.merge();
assert.equal(removed.length, 1); assert.equal(removed.length, 1);
assert.range(rangeList.ranges[1], 4,2,7,7); assert.range(rangeList.ranges[1], 4,2,7,7);
assert.equal(rangeList.ranges.length, 3); assert.equal(rangeList.ranges.length, 3);
rangeList.ranges[0].end.row = 10; rangeList.ranges[0].end.row = 10;
rangeList.merge(); removed = rangeList.merge();
assert.range(rangeList.ranges[0], 1,2,10,4); assert.range(rangeList.ranges[0], 1,2,10,4);
assert.equal(removed.length, 2); assert.equal(removed.length, 2);
assert.equal(rangeList.ranges.length, 1); assert.equal(rangeList.ranges.length, 1);
rangeList.ranges.push(new Range(10,10,10,10)); rangeList.ranges.push(new Range(10,10,10,10));
rangeList.ranges.push(new Range(10,10,10,10)); rangeList.ranges.push(new Range(10,10,10,10));
rangeList.merge(); removed = rangeList.merge();
assert.equal(rangeList.ranges.length, 2); assert.equal(rangeList.ranges.length, 2);
}, },