Skip to content

Commit 3fa54ce

Browse files
committed
fix copyLines* for multiple selections
1 parent 852e067 commit 3fa54ce

File tree

4 files changed

+159
-79
lines changed

4 files changed

+159
-79
lines changed

demo/kitchen-sink/dev_util.js

+45-40
Original file line numberDiff line numberDiff line change
@@ -91,53 +91,58 @@ exports.addGlobals = function() {
9191
window.EditSession = require("ace/edit_session").EditSession;
9292
window.MockRenderer = require("ace/test/mockrenderer").MockRenderer;
9393
window.EventEmitter = require("ace/lib/event_emitter").EventEmitter;
94+
95+
window.getSelection = getSelection;
96+
window.setSelection = setSelection;
97+
window.testSelection = testSelection;
9498
};
9599

100+
function getSelection(editor) {
101+
var data = editor.multiSelect.toJSON();
102+
if (!data.length) data = [data];
103+
data = data.map(function(x) {
104+
var a, c;
105+
if (x.isBackwards) {
106+
a = x.end;
107+
c = x.start;
108+
} else {
109+
c = x.end;
110+
a = x.start;
111+
}
112+
return Range.comparePoints(a, c)
113+
? [a.row, a.column, c.row, c.column]
114+
: [a.row, a.column];
115+
});
116+
return data.length > 1 ? data : data[0];
117+
}
118+
function setSelection(editor, data) {
119+
if (typeof data[0] == "number")
120+
data = [data];
121+
editor.selection.fromJSON(data.map(function(x) {
122+
var start = {row: x[0], column: x[1]};
123+
var end = x.length == 2 ? start : {row: x[2], column: x[3]};
124+
var isBackwards = Range.comparePoints(start, end) > 0;
125+
return isBackwards ? {
126+
start: end,
127+
end: start,
128+
isBackwards: true
129+
} : {
130+
start: start,
131+
end: end,
132+
isBackwards: true
133+
};
134+
}));
135+
}
136+
function testSelection(editor, data) {
137+
assert.equal(getSelection(editor) + "", data + "");
138+
}
139+
96140
exports.recordTestCase = function() {
97141
exports.addGlobals();
98142
var editor = window.editor;
99143
var testcase = window.testcase = [];
100144
var assert;
101-
function getSelection(editor) {
102-
var data = editor.multiSelect.toJSON();
103-
if (!data.length) data = [data];
104-
data = data.map(function(x) {
105-
var a, c;
106-
if (x.isBackwards) {
107-
a = x.end;
108-
c = x.start;
109-
} else {
110-
c = x.end;
111-
a = x.start;
112-
}
113-
return Range.comparePoints(a, c)
114-
? [a.row, a.column, c.row, c.column]
115-
: [a.row, a.column];
116-
});
117-
return data.length > 1 ? data : data[0];
118-
}
119-
function setSelection(editor, data) {
120-
if (typeof data[0] == "number")
121-
data = [data];
122-
editor.selection.fromJSON(data.map(function(x) {
123-
var start = {row: x[0], column: x[1]};
124-
var end = x.length == 2 ? start : {row: x[2], column: x[3]};
125-
var isBackwards = Range.comparePoints(start, end) > 0;
126-
return isBackwards ? {
127-
start: end,
128-
end: start,
129-
isBackwards: true
130-
} : {
131-
start: start,
132-
end: end,
133-
isBackwards: true
134-
};
135-
}));
136-
}
137-
function testSelection(editor, data) {
138-
assert.equal(getSelection(editor) + "", data + "");
139-
}
140-
145+
141146
testcase.push({
142147
type: "setValue",
143148
data: editor.getValue()

kitchen-sink.html

+3-1
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,9 @@
257257
<a href="http://ace.c9.io">
258258
<img id="ace-logo" src="doc/site/images/ace-logo.png" style="width: 134px;margin: 46px 0px 4px 66px;">
259259
</a>
260-
260+
<div><a target="_test" href="./lib/ace/test/tests.html"
261+
style="color: whitesmoke; text-align: left; padding: 1em;">tests</a>
262+
</div>
261263
</div>
262264
</div>
263265
</div>

lib/ace/editor.js

+41-38
Original file line numberDiff line numberDiff line change
@@ -1655,9 +1655,7 @@ var Editor = function(renderer, session) {
16551655
* @related EditSession.moveLinesUp
16561656
**/
16571657
this.moveLinesDown = function() {
1658-
this.$moveLines(function(firstRow, lastRow) {
1659-
return this.session.moveLinesDown(firstRow, lastRow);
1660-
});
1658+
this.$moveLines(1, false);
16611659
};
16621660

16631661
/**
@@ -1666,9 +1664,7 @@ var Editor = function(renderer, session) {
16661664
* @related EditSession.moveLinesDown
16671665
**/
16681666
this.moveLinesUp = function() {
1669-
this.$moveLines(function(firstRow, lastRow) {
1670-
return this.session.moveLinesUp(firstRow, lastRow);
1671-
});
1667+
this.$moveLines(-1, false);
16721668
};
16731669

16741670
/**
@@ -1692,10 +1688,7 @@ var Editor = function(renderer, session) {
16921688
*
16931689
**/
16941690
this.copyLinesUp = function() {
1695-
this.$moveLines(function(firstRow, lastRow) {
1696-
this.session.duplicateLines(firstRow, lastRow);
1697-
return 0;
1698-
});
1691+
this.$moveLines(-1, true);
16991692
};
17001693

17011694
/**
@@ -1705,51 +1698,61 @@ var Editor = function(renderer, session) {
17051698
*
17061699
**/
17071700
this.copyLinesDown = function() {
1708-
this.$moveLines(function(firstRow, lastRow) {
1709-
return this.session.duplicateLines(firstRow, lastRow);
1710-
});
1701+
this.$moveLines(1, true);
17111702
};
17121703

17131704
/**
1714-
* Executes a specific function, which can be anything that manipulates selected lines, such as copying them, duplicating them, or shifting them.
1715-
* @param {Function} mover A method to call on each selected row
1716-
*
1705+
* for internal use
1706+
* @ignore
17171707
*
17181708
**/
1719-
this.$moveLines = function(mover) {
1709+
this.$moveLines = function(dir, copy) {
1710+
var rows, moved;
17201711
var selection = this.selection;
17211712
if (!selection.inMultiSelectMode || this.inVirtualSelectionMode) {
17221713
var range = selection.toOrientedRange();
1723-
var rows = this.$getSelectedRows(range);
1724-
var linesMoved = mover.call(this, rows.first, rows.last);
1725-
range.moveBy(linesMoved, 0);
1714+
rows = this.$getSelectedRows(range);
1715+
moved = this.session.$moveLines(rows.first, rows.last, copy ? 0 : dir);
1716+
if (copy && dir == -1) moved = 0;
1717+
range.moveBy(moved, 0);
17261718
selection.fromOrientedRange(range);
17271719
} else {
17281720
var ranges = selection.rangeList.ranges;
17291721
selection.rangeList.detach(this.session);
1730-
1731-
for (var i = ranges.length; i--; ) {
1722+
this.inVirtualSelectionMode = true;
1723+
1724+
var diff = 0;
1725+
var totalDiff = 0;
1726+
var l = ranges.length;
1727+
for (var i = 0; i < l; i++) {
17321728
var rangeIndex = i;
1733-
var rows = ranges[i].collapseRows();
1734-
var last = rows.end.row;
1735-
var first = rows.start.row;
1736-
while (i--) {
1737-
rows = ranges[i].collapseRows();
1738-
if (first - rows.end.row <= 1)
1739-
first = rows.end.row;
1740-
else
1729+
ranges[i].moveBy(diff, 0);
1730+
rows = this.$getSelectedRows(ranges[i]);
1731+
var first = rows.first;
1732+
var last = rows.last;
1733+
while (++i < l) {
1734+
if (totalDiff) ranges[i].moveBy(totalDiff, 0);
1735+
var subRows = this.$getSelectedRows(ranges[i]);
1736+
if (copy && subRows.first != last)
1737+
break;
1738+
else if (!copy && subRows.first > last + 1)
17411739
break;
1740+
last = subRows.last;
17421741
}
1743-
i++;
1744-
1745-
var linesMoved = mover.call(this, first, last);
1746-
while (rangeIndex >= i) {
1747-
ranges[rangeIndex].moveBy(linesMoved, 0);
1748-
rangeIndex--;
1742+
i--;
1743+
diff = this.session.$moveLines(first, last, copy ? 0 : dir);
1744+
if (copy && dir == -1) rangeIndex = i + 1;
1745+
while (rangeIndex <= i) {
1746+
ranges[rangeIndex].moveBy(diff, 0);
1747+
rangeIndex++;
17491748
}
1749+
if (!copy) diff = 0;
1750+
totalDiff += diff;
17501751
}
1752+
17511753
selection.fromOrientedRange(selection.ranges[0]);
17521754
selection.rangeList.attach(this.session);
1755+
this.inVirtualSelectionMode = false;
17531756
}
17541757
};
17551758

@@ -1762,8 +1765,8 @@ var Editor = function(renderer, session) {
17621765
*
17631766
* @returns {Object}
17641767
**/
1765-
this.$getSelectedRows = function() {
1766-
var range = this.getSelectionRange().collapseRows();
1768+
this.$getSelectedRows = function(range) {
1769+
range = (range || this.getSelectionRange()).collapseRows();
17671770

17681771
return {
17691772
first: this.session.getRowFoldStart(range.start.row),

lib/ace/multi_select_test.js

+70
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,45 @@ var exec = function(name, times, args) {
5151
var testRanges = function(str) {
5252
assert.equal(editor.selection.getAllRanges() + "", str + "");
5353
};
54+
function getSelection(editor) {
55+
var data = editor.multiSelect.toJSON();
56+
if (!data.length) data = [data];
57+
data = data.map(function(x) {
58+
var a, c;
59+
if (x.isBackwards) {
60+
a = x.end;
61+
c = x.start;
62+
} else {
63+
c = x.end;
64+
a = x.start;
65+
}
66+
return Range.comparePoints(a, c)
67+
? [a.row, a.column, c.row, c.column]
68+
: [a.row, a.column];
69+
});
70+
return data.length > 1 ? data : data[0];
71+
}
72+
function testSelection(editor, data) {
73+
assert.equal(getSelection(editor) + "", data + "");
74+
}
75+
function setSelection(editor, data) {
76+
if (typeof data[0] == "number")
77+
data = [data];
78+
editor.selection.fromJSON(data.map(function(x) {
79+
var start = {row: x[0], column: x[1]};
80+
var end = x.length == 2 ? start : {row: x[2], column: x[3]};
81+
var isBackwards = Range.comparePoints(start, end) > 0;
82+
return isBackwards ? {
83+
start: end,
84+
end: start,
85+
isBackwards: true
86+
} : {
87+
start: start,
88+
end: end,
89+
isBackwards: true
90+
};
91+
}));
92+
}
5493

5594
module.exports = {
5695

@@ -167,6 +206,37 @@ module.exports = {
167206
editor.execCommand('insertfoo');
168207
assert.equal('l1foo\nl2foo', editor.getValue());
169208
},
209+
210+
"test multiselect move lines": function() {
211+
editor = new Editor(new MockRenderer());
212+
213+
editor.setValue("l1\nl2\nl3\nl4", -1);
214+
setSelection(editor, [[0,2],[1,2],[2,2],[3,2]]);
215+
216+
exec("copylinesdown");
217+
assert.equal(editor.getValue(),"l1\nl1\nl2\nl2\nl3\nl3\nl4\nl4");
218+
testSelection(editor, [[1,2],[3,2],[5,2],[7,2]]);
219+
exec("copylinesup");
220+
assert.equal(editor.getValue(),"l1\nl1\nl1\nl2\nl2\nl2\nl3\nl3\nl3\nl4\nl4\nl4");
221+
testSelection(editor, [[1,2],[4,2],[7,2],[10,2]]);
222+
exec("removeline");
223+
assert.equal(editor.getValue(),"l1\nl1\nl2\nl2\nl3\nl3\nl4\nl4");
224+
testSelection(editor, [[1,0],[3,0],[5,0],[7,0]]);
225+
226+
setSelection(editor, [[1,2],[1,0,1,1],[3,0,3,1],[5,0,5,1],[7,0,7,1]]);
227+
exec("copylinesdown");
228+
exec("copylinesup");
229+
assert.equal(editor.getValue(),"l1\nl1\nl1\nl1\nl2\nl2\nl2\nl2\nl3\nl3\nl3\nl3\nl4\nl4\nl4\nl4");
230+
testSelection(editor, [[2,2],[2,0,2,1],[6,0,6,1],[10,0,10,1],[14,0,14,1]]);
231+
232+
exec("movelinesdown", 12);
233+
assert.equal(editor.getValue(),"l1\nl1\nl1\nl2\nl2\nl2\nl3\nl3\nl3\nl4\nl4\nl4\nl1\nl2\nl3\nl4");
234+
testSelection(editor, [[12,2],[12,0,12,1],[13,0,13,1],[14,0,14,1],[15,0,15,1]]);
235+
236+
exec("movelinesup", 12);
237+
assert.equal(editor.getValue(),"l1\nl2\nl3\nl4\nl1\nl1\nl1\nl2\nl2\nl2\nl3\nl3\nl3\nl4\nl4\nl4");
238+
testSelection(editor, [[0,2],[0,0,0,1],[1,0,1,1],[2,0,2,1],[3,0,3,1]]);
239+
},
170240

171241
"test multiselect fromJSON/toJSON": function() {
172242
var doc = new EditSession(["l1", "l2"]);

0 commit comments

Comments
 (0)