Skip to content

Commit 68c6f31

Browse files
committed
Keep shared markers consistent when documents are linked/unlinked
Issue #2360 Conflicts: lib/codemirror.js test/doc_test.js
1 parent 03aa2bd commit 68c6f31

File tree

2 files changed

+88
-8
lines changed

2 files changed

+88
-8
lines changed

lib/codemirror.js

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3906,6 +3906,7 @@ window.CodeMirror = (function() {
39063906
}
39073907
if (cm) signalLater(cm, "markerCleared", cm, this);
39083908
if (withOp) endOperation(cm);
3909+
if (this.parent) this.parent.clear();
39093910
};
39103911

39113912
TextMarker.prototype.find = function(bothSides) {
@@ -3963,7 +3964,7 @@ window.CodeMirror = (function() {
39633964
if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type);
39643965

39653966
var marker = new TextMarker(doc, type);
3966-
if (options) copyObj(options, marker);
3967+
if (options) copyObj(options, marker, false);
39673968
if (posLess(to, from) || posEq(from, to) && marker.clearWhenEmpty !== false)
39683969
return marker;
39693970
if (marker.replacedWith) {
@@ -4023,10 +4024,8 @@ window.CodeMirror = (function() {
40234024
function SharedTextMarker(markers, primary) {
40244025
this.markers = markers;
40254026
this.primary = primary;
4026-
for (var i = 0, me = this; i < markers.length; ++i) {
4027+
for (var i = 0; i < markers.length; ++i)
40274028
markers[i].parent = this;
4028-
on(markers[i], "clear", function(){me.clear();});
4029-
}
40304029
}
40314030
CodeMirror.SharedTextMarker = SharedTextMarker;
40324031
eventMixin(SharedTextMarker);
@@ -4057,6 +4056,37 @@ window.CodeMirror = (function() {
40574056
return new SharedTextMarker(markers, primary);
40584057
}
40594058

4059+
function findSharedMarkers(doc) {
4060+
return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())),
4061+
function(m) { return m.parent; });
4062+
}
4063+
4064+
function copySharedMarkers(doc, markers) {
4065+
for (var i = 0; i < markers.length; i++) {
4066+
var marker = markers[i], pos = marker.find();
4067+
var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to);
4068+
if (cmp(mFrom, mTo)) {
4069+
var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type);
4070+
marker.markers.push(subMark);
4071+
subMark.parent = marker;
4072+
}
4073+
}
4074+
}
4075+
4076+
function detachSharedMarkers(markers) {
4077+
for (var i = 0; i < markers.length; i++) {
4078+
var marker = markers[i], linked = [marker.primary.doc];;
4079+
linkedDocs(marker.primary.doc, function(d) { linked.push(d); });
4080+
for (var j = 0; j < marker.markers.length; j++) {
4081+
var subMarker = marker.markers[j];
4082+
if (indexOf(linked, subMarker.doc) == -1) {
4083+
subMarker.parent = null;
4084+
marker.markers.splice(j--, 1);
4085+
}
4086+
}
4087+
}
4088+
}
4089+
40604090
// TEXTMARKER SPANS
40614091

40624092
function getMarkedSpanFor(spans, marker) {
@@ -5078,7 +5108,7 @@ window.CodeMirror = (function() {
50785108
}
50795109
return markers;
50805110
},
5081-
findMarks: function(from, to) {
5111+
findMarks: function(from, to, filter) {
50825112
from = clipPos(this, from); to = clipPos(this, to);
50835113
var found = [], lineNo = from.line;
50845114
this.iter(from.line, to.line + 1, function(line) {
@@ -5087,7 +5117,8 @@ window.CodeMirror = (function() {
50875117
var span = spans[i];
50885118
if (!(lineNo == from.line && from.ch > span.to ||
50895119
span.from == null && lineNo != from.line||
5090-
lineNo == to.line && span.from > to.ch))
5120+
lineNo == to.line && span.from > to.ch) &&
5121+
(!filter || filter(span.marker)))
50915122
found.push(span.marker.parent || span.marker);
50925123
}
50935124
++lineNo;
@@ -5145,6 +5176,7 @@ window.CodeMirror = (function() {
51455176
if (options.sharedHist) copy.history = this.history;
51465177
(this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});
51475178
copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];
5179+
copySharedMarkers(copy, findSharedMarkers(this));
51485180
return copy;
51495181
},
51505182
unlinkDoc: function(other) {
@@ -5154,6 +5186,7 @@ window.CodeMirror = (function() {
51545186
if (link.doc != other) continue;
51555187
this.linked.splice(i, 1);
51565188
other.unlinkDoc(this);
5189+
detachSharedMarkers(findSharedMarkers(this));
51575190
break;
51585191
}
51595192
// If the histories were shared, split them again
@@ -5634,9 +5667,11 @@ window.CodeMirror = (function() {
56345667
return inst;
56355668
}
56365669

5637-
function copyObj(obj, target) {
5670+
function copyObj(obj, target, overwrite) {
56385671
if (!target) target = {};
5639-
for (var prop in obj) if (obj.hasOwnProperty(prop)) target[prop] = obj[prop];
5672+
for (var prop in obj)
5673+
if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
5674+
target[prop] = obj[prop];
56405675
return target;
56415676
}
56425677

test/doc_test.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,51 @@
320320
eq(cleared, 1);
321321
});
322322

323+
<<<<<<< HEAD
324+
=======
325+
testDoc("sharedMarkerCopy", "A='abcde'", function(a) {
326+
var shared = a.markText(Pos(0, 1), Pos(0, 3), {shared: true});
327+
var b = a.linkedDoc();
328+
var found = b.findMarksAt(Pos(0, 2));
329+
eq(found.length, 1);
330+
eq(found[0], shared);
331+
shared.clear();
332+
eq(b.findMarksAt(Pos(0, 2)), 0);
333+
});
334+
335+
testDoc("sharedMarkerDetach", "A='abcde' B<A C<B", function(a, b, c) {
336+
var shared = a.markText(Pos(0, 1), Pos(0, 3), {shared: true});
337+
a.unlinkDoc(b);
338+
var inB = b.findMarksAt(Pos(0, 2));
339+
eq(inB.length, 1);
340+
is(inB[0] != shared);
341+
var inC = c.findMarksAt(Pos(0, 2));
342+
eq(inC.length, 1);
343+
is(inC[0] != shared);
344+
inC[0].clear();
345+
is(shared.find());
346+
});
347+
348+
testDoc("sharedBookmark", "A='ab\ncd\nef\ngh' B<A C<~A/1-2", function(a, b, c) {
349+
var mark = b.setBookmark(Pos(1, 1), {shared: true});
350+
var found = a.findMarksAt(Pos(1, 1));
351+
eq(found.length, 1);
352+
eq(found[0], mark);
353+
eq(c.findMarksAt(Pos(1, 1)).length, 1);
354+
eqPos(mark.find(), Pos(1, 1));
355+
b.replaceRange("x\ny\n", Pos(0, 0));
356+
eqPos(mark.find(), Pos(3, 1));
357+
var cleared = 0;
358+
CodeMirror.on(mark, "clear", function() {++cleared;});
359+
b.operation(function() {mark.clear();});
360+
eq(a.findMarks(Pos(0, 0), Pos(5)).length, 0);
361+
eq(b.findMarks(Pos(0, 0), Pos(5)).length, 0);
362+
eq(c.findMarks(Pos(0, 0), Pos(5)).length, 0);
363+
eq(mark.find(), null);
364+
eq(cleared, 1);
365+
});
366+
367+
>>>>>>> bc75b8f... Keep shared markers consistent when documents are linked/unlinked
323368
testDoc("undoInSubview", "A='line 0\nline 1\nline 2\nline 3\nline 4' B<A/1-4", function(a, b) {
324369
b.replaceRange("x", Pos(2, 0));
325370
a.undo();

0 commit comments

Comments
 (0)