diff --git a/demo/kitchen-sink/dev_util.js b/demo/kitchen-sink/dev_util.js index 4580d9be..ae9200b7 100644 --- a/demo/kitchen-sink/dev_util.js +++ b/demo/kitchen-sink/dev_util.js @@ -91,53 +91,58 @@ exports.addGlobals = function() { window.EditSession = require("ace/edit_session").EditSession; window.MockRenderer = require("ace/test/mockrenderer").MockRenderer; window.EventEmitter = require("ace/lib/event_emitter").EventEmitter; + + window.getSelection = getSelection; + window.setSelection = setSelection; + window.testSelection = testSelection; }; +function getSelection(editor) { + var data = editor.multiSelect.toJSON(); + if (!data.length) data = [data]; + data = data.map(function(x) { + var a, c; + if (x.isBackwards) { + a = x.end; + c = x.start; + } else { + c = x.end; + a = x.start; + } + return Range.comparePoints(a, c) + ? [a.row, a.column, c.row, c.column] + : [a.row, a.column]; + }); + return data.length > 1 ? data : data[0]; +} +function setSelection(editor, data) { + if (typeof data[0] == "number") + data = [data]; + editor.selection.fromJSON(data.map(function(x) { + var start = {row: x[0], column: x[1]}; + var end = x.length == 2 ? start : {row: x[2], column: x[3]}; + var isBackwards = Range.comparePoints(start, end) > 0; + return isBackwards ? { + start: end, + end: start, + isBackwards: true + } : { + start: start, + end: end, + isBackwards: true + }; + })); +} +function testSelection(editor, data) { + assert.equal(getSelection(editor) + "", data + ""); +} + exports.recordTestCase = function() { exports.addGlobals(); var editor = window.editor; var testcase = window.testcase = []; var assert; - function getSelection(editor) { - var data = editor.multiSelect.toJSON(); - if (!data.length) data = [data]; - data = data.map(function(x) { - var a, c; - if (x.isBackwards) { - a = x.end; - c = x.start; - } else { - c = x.end; - a = x.start; - } - return Range.comparePoints(a, c) - ? [a.row, a.column, c.row, c.column] - : [a.row, a.column]; - }); - return data.length > 1 ? data : data[0]; - } - function setSelection(editor, data) { - if (typeof data[0] == "number") - data = [data]; - editor.selection.fromJSON(data.map(function(x) { - var start = {row: x[0], column: x[1]}; - var end = x.length == 2 ? start : {row: x[2], column: x[3]}; - var isBackwards = Range.comparePoints(start, end) > 0; - return isBackwards ? { - start: end, - end: start, - isBackwards: true - } : { - start: start, - end: end, - isBackwards: true - }; - })); - } - function testSelection(editor, data) { - assert.equal(getSelection(editor) + "", data + ""); - } - + testcase.push({ type: "setValue", data: editor.getValue() diff --git a/kitchen-sink.html b/kitchen-sink.html index 65fe2a2a..a8e1fb7b 100644 --- a/kitchen-sink.html +++ b/kitchen-sink.html @@ -257,7 +257,9 @@ - +
tests +
diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 78c7c18d..f487b49e 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -1655,9 +1655,7 @@ var Editor = function(renderer, session) { * @related EditSession.moveLinesUp **/ this.moveLinesDown = function() { - this.$moveLines(function(firstRow, lastRow) { - return this.session.moveLinesDown(firstRow, lastRow); - }); + this.$moveLines(1, false); }; /** @@ -1666,9 +1664,7 @@ var Editor = function(renderer, session) { * @related EditSession.moveLinesDown **/ this.moveLinesUp = function() { - this.$moveLines(function(firstRow, lastRow) { - return this.session.moveLinesUp(firstRow, lastRow); - }); + this.$moveLines(-1, false); }; /** @@ -1692,10 +1688,7 @@ var Editor = function(renderer, session) { * **/ this.copyLinesUp = function() { - this.$moveLines(function(firstRow, lastRow) { - this.session.duplicateLines(firstRow, lastRow); - return 0; - }); + this.$moveLines(-1, true); }; /** @@ -1705,51 +1698,61 @@ var Editor = function(renderer, session) { * **/ this.copyLinesDown = function() { - this.$moveLines(function(firstRow, lastRow) { - return this.session.duplicateLines(firstRow, lastRow); - }); + this.$moveLines(1, true); }; /** - * Executes a specific function, which can be anything that manipulates selected lines, such as copying them, duplicating them, or shifting them. - * @param {Function} mover A method to call on each selected row - * + * for internal use + * @ignore * **/ - this.$moveLines = function(mover) { + this.$moveLines = function(dir, copy) { + var rows, moved; var selection = this.selection; if (!selection.inMultiSelectMode || this.inVirtualSelectionMode) { var range = selection.toOrientedRange(); - var rows = this.$getSelectedRows(range); - var linesMoved = mover.call(this, rows.first, rows.last); - range.moveBy(linesMoved, 0); + rows = this.$getSelectedRows(range); + moved = this.session.$moveLines(rows.first, rows.last, copy ? 0 : dir); + if (copy && dir == -1) moved = 0; + range.moveBy(moved, 0); selection.fromOrientedRange(range); } else { var ranges = selection.rangeList.ranges; selection.rangeList.detach(this.session); - - for (var i = ranges.length; i--; ) { + this.inVirtualSelectionMode = true; + + var diff = 0; + var totalDiff = 0; + var l = ranges.length; + for (var i = 0; i < l; i++) { var rangeIndex = i; - var rows = ranges[i].collapseRows(); - var last = rows.end.row; - var first = rows.start.row; - while (i--) { - rows = ranges[i].collapseRows(); - if (first - rows.end.row <= 1) - first = rows.end.row; - else + ranges[i].moveBy(diff, 0); + rows = this.$getSelectedRows(ranges[i]); + var first = rows.first; + var last = rows.last; + while (++i < l) { + if (totalDiff) ranges[i].moveBy(totalDiff, 0); + var subRows = this.$getSelectedRows(ranges[i]); + if (copy && subRows.first != last) break; + else if (!copy && subRows.first > last + 1) + break; + last = subRows.last; } - i++; - - var linesMoved = mover.call(this, first, last); - while (rangeIndex >= i) { - ranges[rangeIndex].moveBy(linesMoved, 0); - rangeIndex--; + i--; + diff = this.session.$moveLines(first, last, copy ? 0 : dir); + if (copy && dir == -1) rangeIndex = i + 1; + while (rangeIndex <= i) { + ranges[rangeIndex].moveBy(diff, 0); + rangeIndex++; } + if (!copy) diff = 0; + totalDiff += diff; } + selection.fromOrientedRange(selection.ranges[0]); selection.rangeList.attach(this.session); + this.inVirtualSelectionMode = false; } }; @@ -1762,8 +1765,8 @@ var Editor = function(renderer, session) { * * @returns {Object} **/ - this.$getSelectedRows = function() { - var range = this.getSelectionRange().collapseRows(); + this.$getSelectedRows = function(range) { + range = (range || this.getSelectionRange()).collapseRows(); return { first: this.session.getRowFoldStart(range.start.row), diff --git a/lib/ace/multi_select_test.js b/lib/ace/multi_select_test.js index 2e71aefa..1eccc4ce 100644 --- a/lib/ace/multi_select_test.js +++ b/lib/ace/multi_select_test.js @@ -51,6 +51,45 @@ var exec = function(name, times, args) { var testRanges = function(str) { assert.equal(editor.selection.getAllRanges() + "", str + ""); }; +function getSelection(editor) { + var data = editor.multiSelect.toJSON(); + if (!data.length) data = [data]; + data = data.map(function(x) { + var a, c; + if (x.isBackwards) { + a = x.end; + c = x.start; + } else { + c = x.end; + a = x.start; + } + return Range.comparePoints(a, c) + ? [a.row, a.column, c.row, c.column] + : [a.row, a.column]; + }); + return data.length > 1 ? data : data[0]; +} +function testSelection(editor, data) { + assert.equal(getSelection(editor) + "", data + ""); +} +function setSelection(editor, data) { + if (typeof data[0] == "number") + data = [data]; + editor.selection.fromJSON(data.map(function(x) { + var start = {row: x[0], column: x[1]}; + var end = x.length == 2 ? start : {row: x[2], column: x[3]}; + var isBackwards = Range.comparePoints(start, end) > 0; + return isBackwards ? { + start: end, + end: start, + isBackwards: true + } : { + start: start, + end: end, + isBackwards: true + }; + })); +} module.exports = { @@ -167,6 +206,37 @@ module.exports = { editor.execCommand('insertfoo'); assert.equal('l1foo\nl2foo', editor.getValue()); }, + + "test multiselect move lines": function() { + editor = new Editor(new MockRenderer()); + + editor.setValue("l1\nl2\nl3\nl4", -1); + setSelection(editor, [[0,2],[1,2],[2,2],[3,2]]); + + exec("copylinesdown"); + assert.equal(editor.getValue(),"l1\nl1\nl2\nl2\nl3\nl3\nl4\nl4"); + testSelection(editor, [[1,2],[3,2],[5,2],[7,2]]); + exec("copylinesup"); + assert.equal(editor.getValue(),"l1\nl1\nl1\nl2\nl2\nl2\nl3\nl3\nl3\nl4\nl4\nl4"); + testSelection(editor, [[1,2],[4,2],[7,2],[10,2]]); + exec("removeline"); + assert.equal(editor.getValue(),"l1\nl1\nl2\nl2\nl3\nl3\nl4\nl4"); + testSelection(editor, [[1,0],[3,0],[5,0],[7,0]]); + + setSelection(editor, [[1,2],[1,0,1,1],[3,0,3,1],[5,0,5,1],[7,0,7,1]]); + exec("copylinesdown"); + exec("copylinesup"); + assert.equal(editor.getValue(),"l1\nl1\nl1\nl1\nl2\nl2\nl2\nl2\nl3\nl3\nl3\nl3\nl4\nl4\nl4\nl4"); + testSelection(editor, [[2,2],[2,0,2,1],[6,0,6,1],[10,0,10,1],[14,0,14,1]]); + + exec("movelinesdown", 12); + assert.equal(editor.getValue(),"l1\nl1\nl1\nl2\nl2\nl2\nl3\nl3\nl3\nl4\nl4\nl4\nl1\nl2\nl3\nl4"); + testSelection(editor, [[12,2],[12,0,12,1],[13,0,13,1],[14,0,14,1],[15,0,15,1]]); + + exec("movelinesup", 12); + assert.equal(editor.getValue(),"l1\nl2\nl3\nl4\nl1\nl1\nl1\nl2\nl2\nl2\nl3\nl3\nl3\nl4\nl4\nl4"); + testSelection(editor, [[0,2],[0,0,0,1],[1,0,1,1],[2,0,2,1],[3,0,3,1]]); + }, "test multiselect fromJSON/toJSON": function() { var doc = new EditSession(["l1", "l2"]);