codemirror-rails 4.8 → 4.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +24 -6
- data/lib/codemirror/rails/version.rb +2 -2
- data/vendor/assets/javascripts/codemirror.js +289 -184
- data/vendor/assets/javascripts/codemirror/addons/dialog/dialog.js +1 -1
- data/vendor/assets/javascripts/codemirror/addons/display/panel.js +94 -0
- data/vendor/assets/javascripts/codemirror/addons/edit/continuelist.js +4 -4
- data/vendor/assets/javascripts/codemirror/addons/hint/anyword-hint.js +1 -2
- data/vendor/assets/javascripts/codemirror/addons/hint/css-hint.js +1 -1
- data/vendor/assets/javascripts/codemirror/addons/hint/html-hint.js +1 -1
- data/vendor/assets/javascripts/codemirror/addons/hint/javascript-hint.js +8 -3
- data/vendor/assets/javascripts/codemirror/addons/hint/show-hint.js +1 -1
- data/vendor/assets/javascripts/codemirror/addons/hint/sql-hint.js +7 -4
- data/vendor/assets/javascripts/codemirror/addons/hint/xml-hint.js +3 -4
- data/vendor/assets/javascripts/codemirror/addons/merge/merge.js +170 -63
- data/vendor/assets/javascripts/codemirror/addons/mode/simple.js +11 -8
- data/vendor/assets/javascripts/codemirror/addons/scroll/annotatescrollbar.js +76 -0
- data/vendor/assets/javascripts/codemirror/addons/scroll/simplescrollbars.js +139 -0
- data/vendor/assets/javascripts/codemirror/addons/search/matchesonscrollbar.js +90 -0
- data/vendor/assets/javascripts/codemirror/addons/search/search.js +9 -4
- data/vendor/assets/javascripts/codemirror/addons/tern/tern.js +5 -3
- data/vendor/assets/javascripts/codemirror/keymaps/emacs.js +25 -7
- data/vendor/assets/javascripts/codemirror/keymaps/vim.js +181 -109
- data/vendor/assets/javascripts/codemirror/modes/coffeescript.js +2 -2
- data/vendor/assets/javascripts/codemirror/modes/commonlisp.js +5 -3
- data/vendor/assets/javascripts/codemirror/modes/cypher.js +1 -1
- data/vendor/assets/javascripts/codemirror/modes/dart.js +50 -0
- data/vendor/assets/javascripts/codemirror/modes/dockerfile.js +5 -9
- data/vendor/assets/javascripts/codemirror/modes/ebnf.js +195 -0
- data/vendor/assets/javascripts/codemirror/modes/javascript.js +2 -0
- data/vendor/assets/javascripts/codemirror/modes/markdown.js +3 -3
- data/vendor/assets/javascripts/codemirror/modes/puppet.js +2 -2
- data/vendor/assets/javascripts/codemirror/modes/shell.js +2 -1
- data/vendor/assets/javascripts/codemirror/modes/soy.js +198 -0
- data/vendor/assets/javascripts/codemirror/modes/spreadsheet.js +109 -0
- data/vendor/assets/javascripts/codemirror/modes/stex.js +4 -6
- data/vendor/assets/javascripts/codemirror/modes/textile.js +392 -476
- data/vendor/assets/javascripts/codemirror/modes/turtle.js +3 -1
- data/vendor/assets/stylesheets/codemirror.css +2 -11
- data/vendor/assets/stylesheets/codemirror/addons/merge/merge.css +14 -0
- data/vendor/assets/stylesheets/codemirror/addons/scroll/simplescrollbars.css +66 -0
- data/vendor/assets/stylesheets/codemirror/addons/search/matchesonscrollbar.css +8 -0
- data/vendor/assets/stylesheets/codemirror/themes/tomorrow-night-bright.css +35 -0
- data/vendor/assets/stylesheets/codemirror/themes/zenburn.css +37 -0
- metadata +14 -3
- data/vendor/assets/javascripts/codemirror/addons/hint/python-hint.js +0 -102
@@ -0,0 +1,94 @@
|
|
1
|
+
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
2
|
+
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
3
|
+
|
4
|
+
(function(mod) {
|
5
|
+
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
6
|
+
mod(require("../../lib/codemirror"));
|
7
|
+
else if (typeof define == "function" && define.amd) // AMD
|
8
|
+
define(["../../lib/codemirror"], mod);
|
9
|
+
else // Plain browser env
|
10
|
+
mod(CodeMirror);
|
11
|
+
})(function(CodeMirror) {
|
12
|
+
CodeMirror.defineExtension("addPanel", function(node, options) {
|
13
|
+
if (!this.state.panels) initPanels(this);
|
14
|
+
|
15
|
+
var info = this.state.panels;
|
16
|
+
if (options && options.position == "bottom")
|
17
|
+
info.wrapper.appendChild(node);
|
18
|
+
else
|
19
|
+
info.wrapper.insertBefore(node, info.wrapper.firstChild);
|
20
|
+
var height = (options && options.height) || node.offsetHeight;
|
21
|
+
this._setSize(null, info.heightLeft -= height);
|
22
|
+
info.panels++;
|
23
|
+
return new Panel(this, node, options, height);
|
24
|
+
});
|
25
|
+
|
26
|
+
function Panel(cm, node, options, height) {
|
27
|
+
this.cm = cm;
|
28
|
+
this.node = node;
|
29
|
+
this.options = options;
|
30
|
+
this.height = height;
|
31
|
+
this.cleared = false;
|
32
|
+
}
|
33
|
+
|
34
|
+
Panel.prototype.clear = function() {
|
35
|
+
if (this.cleared) return;
|
36
|
+
this.cleared = true;
|
37
|
+
var info = this.cm.state.panels;
|
38
|
+
this.cm._setSize(null, info.heightLeft += this.height);
|
39
|
+
info.wrapper.removeChild(this.node);
|
40
|
+
if (--info.panels == 0) removePanels(this.cm);
|
41
|
+
};
|
42
|
+
|
43
|
+
Panel.prototype.changed = function(height) {
|
44
|
+
var newHeight = height == null ? this.node.offsetHeight : height;
|
45
|
+
var info = this.cm.state.panels;
|
46
|
+
this.cm._setSize(null, info.height += (newHeight - this.height));
|
47
|
+
this.height = newHeight;
|
48
|
+
};
|
49
|
+
|
50
|
+
function initPanels(cm) {
|
51
|
+
var wrap = cm.getWrapperElement();
|
52
|
+
var style = window.getComputedStyle ? window.getComputedStyle(wrap) : wrap.currentStyle;
|
53
|
+
var height = parseInt(style.height);
|
54
|
+
var info = cm.state.panels = {
|
55
|
+
setHeight: wrap.style.height,
|
56
|
+
heightLeft: height,
|
57
|
+
panels: 0,
|
58
|
+
wrapper: document.createElement("div")
|
59
|
+
};
|
60
|
+
wrap.parentNode.insertBefore(info.wrapper, wrap);
|
61
|
+
var hasFocus = cm.hasFocus();
|
62
|
+
info.wrapper.appendChild(wrap);
|
63
|
+
if (hasFocus) cm.focus();
|
64
|
+
|
65
|
+
cm._setSize = cm.setSize;
|
66
|
+
if (height != null) cm.setSize = function(width, newHeight) {
|
67
|
+
if (newHeight == null) return this._setSize(width, newHeight);
|
68
|
+
info.setHeight = newHeight;
|
69
|
+
if (typeof newHeight != "number") {
|
70
|
+
var px = /^(\d+\.?\d*)px$/.exec(newHeight);
|
71
|
+
if (px) {
|
72
|
+
newHeight = Number(px[1]);
|
73
|
+
} else {
|
74
|
+
info.wrapper.style.height = newHeight;
|
75
|
+
newHeight = info.wrapper.offsetHeight;
|
76
|
+
info.wrapper.style.height = "";
|
77
|
+
}
|
78
|
+
}
|
79
|
+
cm._setSize(width, info.heightLeft += (newHeight - height));
|
80
|
+
height = newHeight;
|
81
|
+
};
|
82
|
+
}
|
83
|
+
|
84
|
+
function removePanels(cm) {
|
85
|
+
var info = cm.state.panels;
|
86
|
+
cm.state.panels = null;
|
87
|
+
|
88
|
+
var wrap = cm.getWrapperElement();
|
89
|
+
info.wrapper.parentNode.replaceChild(wrap, info.wrapper);
|
90
|
+
wrap.style.height = info.setHeight;
|
91
|
+
cm.setSize = cm._setSize;
|
92
|
+
cm.setSize();
|
93
|
+
}
|
94
|
+
});
|
@@ -11,9 +11,9 @@
|
|
11
11
|
})(function(CodeMirror) {
|
12
12
|
"use strict";
|
13
13
|
|
14
|
-
var listRE = /^(\s*)([> ]
|
15
|
-
emptyListRE = /^(\s*)([> ]
|
16
|
-
|
14
|
+
var listRE = /^(\s*)(>[> ]*|[*+-]\s|(\d+)\.)(\s*)/,
|
15
|
+
emptyListRE = /^(\s*)(>[> ]*|[*+-]|(\d+)\.)(\s*)$/,
|
16
|
+
unorderedListRE = /[*+-]\s/;
|
17
17
|
|
18
18
|
CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) {
|
19
19
|
if (cm.getOption("disableInput")) return CodeMirror.Pass;
|
@@ -38,7 +38,7 @@
|
|
38
38
|
|
39
39
|
} else {
|
40
40
|
var indent = match[1], after = match[4];
|
41
|
-
var bullet =
|
41
|
+
var bullet = unorderedListRE.test(match[2]) || match[2].indexOf(">") >= 0
|
42
42
|
? match[2]
|
43
43
|
: (parseInt(match[3], 10) + 1) + ".";
|
44
44
|
|
@@ -17,8 +17,7 @@
|
|
17
17
|
var word = options && options.word || WORD;
|
18
18
|
var range = options && options.range || RANGE;
|
19
19
|
var cur = editor.getCursor(), curLine = editor.getLine(cur.line);
|
20
|
-
var
|
21
|
-
while (end < curLine.length && word.test(curLine.charAt(end))) ++end;
|
20
|
+
var end = cur.ch, start = end;
|
22
21
|
while (start && word.test(curLine.charAt(start - 1))) --start;
|
23
22
|
var curWord = start != end && curLine.slice(start, end);
|
24
23
|
|
@@ -20,7 +20,7 @@
|
|
20
20
|
var inner = CodeMirror.innerMode(cm.getMode(), token.state);
|
21
21
|
if (inner.mode.name != "css") return;
|
22
22
|
|
23
|
-
var
|
23
|
+
var start = token.start, end = cur.ch, word = token.string.slice(0, end - start);
|
24
24
|
if (/[^\w$_-]/.test(word)) {
|
25
25
|
word = ""; start = end = cur.ch;
|
26
26
|
}
|
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
(function(mod) {
|
5
5
|
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
6
|
-
mod(require("../../lib/codemirror", "./xml-hint"));
|
6
|
+
mod(require("../../lib/codemirror"), require("./xml-hint"));
|
7
7
|
else if (typeof define == "function" && define.amd) // AMD
|
8
8
|
define(["../../lib/codemirror", "./xml-hint"], mod);
|
9
9
|
else // Plain browser env
|
@@ -30,15 +30,20 @@
|
|
30
30
|
|
31
31
|
function scriptHint(editor, keywords, getToken, options) {
|
32
32
|
// Find the token at the cursor
|
33
|
-
var cur = editor.getCursor(), token = getToken(editor, cur)
|
33
|
+
var cur = editor.getCursor(), token = getToken(editor, cur);
|
34
34
|
if (/\b(?:string|comment)\b/.test(token.type)) return;
|
35
35
|
token.state = CodeMirror.innerMode(editor.getMode(), token.state).state;
|
36
36
|
|
37
37
|
// If it's not a 'word-style' token, ignore the token.
|
38
38
|
if (!/^[\w$_]*$/.test(token.string)) {
|
39
|
-
token =
|
40
|
-
|
39
|
+
token = {start: cur.ch, end: cur.ch, string: "", state: token.state,
|
40
|
+
type: token.string == "." ? "property" : null};
|
41
|
+
} else if (token.end > cur.ch) {
|
42
|
+
token.end = cur.ch;
|
43
|
+
token.string = token.string.slice(0, cur.ch - token.start);
|
41
44
|
}
|
45
|
+
|
46
|
+
var tprop = token;
|
42
47
|
// If it is a property, find out what it is a property of.
|
43
48
|
while (tprop.type == "property") {
|
44
49
|
tprop = getToken(editor, Pos(cur.line, tprop.start));
|
@@ -44,9 +44,7 @@
|
|
44
44
|
}
|
45
45
|
}
|
46
46
|
|
47
|
-
function nameCompletion(result, editor) {
|
48
|
-
var cur = editor.getCursor();
|
49
|
-
var token = editor.getTokenAt(cur);
|
47
|
+
function nameCompletion(cur, token, result, editor) {
|
50
48
|
var useBacktick = (token.string.charAt(0) == "`");
|
51
49
|
var string = token.string.substr(1);
|
52
50
|
var prevToken = editor.getTokenAt(Pos(cur.line, token.start));
|
@@ -173,6 +171,11 @@
|
|
173
171
|
var cur = editor.getCursor();
|
174
172
|
var result = [];
|
175
173
|
var token = editor.getTokenAt(cur), start, end, search;
|
174
|
+
if (token.end > cur.ch) {
|
175
|
+
token.end = cur.ch;
|
176
|
+
token.string = token.string.slice(0, cur.ch - token.start);
|
177
|
+
}
|
178
|
+
|
176
179
|
if (token.string.match(/^[.`\w@]\w*$/)) {
|
177
180
|
search = token.string;
|
178
181
|
start = token.start;
|
@@ -182,7 +185,7 @@
|
|
182
185
|
search = "";
|
183
186
|
}
|
184
187
|
if (search.charAt(0) == "." || search.charAt(0) == "`") {
|
185
|
-
nameCompletion(result, editor);
|
188
|
+
nameCompletion(cur, token, result, editor);
|
186
189
|
} else {
|
187
190
|
addMatches(result, search, tables, function(w) {return w;});
|
188
191
|
addMatches(result, search, defaultTable, function(w) {return w;});
|
@@ -18,10 +18,9 @@
|
|
18
18
|
var quote = (options && options.quoteChar) || '"';
|
19
19
|
if (!tags) return;
|
20
20
|
var cur = cm.getCursor(), token = cm.getTokenAt(cur);
|
21
|
-
if (
|
22
|
-
|
23
|
-
|
24
|
-
token = nextToken;
|
21
|
+
if (token.end > cur.ch) {
|
22
|
+
token.end = cur.ch;
|
23
|
+
token.string = token.string.slice(0, cur.ch - token.start);
|
25
24
|
}
|
26
25
|
var inner = CodeMirror.innerMode(cm.getMode(), token.state);
|
27
26
|
if (inner.mode.name != "xml") return;
|
@@ -31,6 +31,8 @@
|
|
31
31
|
insert: "CodeMirror-merge-r-inserted",
|
32
32
|
del: "CodeMirror-merge-r-deleted",
|
33
33
|
connect: "CodeMirror-merge-r-connect"};
|
34
|
+
if (mv.options.connect == "align")
|
35
|
+
this.aligners = [];
|
34
36
|
}
|
35
37
|
|
36
38
|
DiffView.prototype = {
|
@@ -81,7 +83,7 @@
|
|
81
83
|
updateMarks(dv.edit, dv.diff, edit, DIFF_INSERT, dv.classes);
|
82
84
|
updateMarks(dv.orig, dv.diff, orig, DIFF_DELETE, dv.classes);
|
83
85
|
}
|
84
|
-
|
86
|
+
makeConnections(dv);
|
85
87
|
}
|
86
88
|
function set(slow) {
|
87
89
|
clearTimeout(debounceChange);
|
@@ -108,10 +110,10 @@
|
|
108
110
|
|
109
111
|
function registerScroll(dv) {
|
110
112
|
dv.edit.on("scroll", function() {
|
111
|
-
syncScroll(dv, DIFF_INSERT) &&
|
113
|
+
syncScroll(dv, DIFF_INSERT) && makeConnections(dv);
|
112
114
|
});
|
113
115
|
dv.orig.on("scroll", function() {
|
114
|
-
syncScroll(dv, DIFF_DELETE) &&
|
116
|
+
syncScroll(dv, DIFF_DELETE) && makeConnections(dv);
|
115
117
|
});
|
116
118
|
}
|
117
119
|
|
@@ -126,24 +128,29 @@
|
|
126
128
|
// (to prevent feedback loops)
|
127
129
|
if (editor.state.scrollSetBy == dv && (editor.state.scrollSetAt || 0) + 50 > now) return false;
|
128
130
|
|
129
|
-
var sInfo = editor.getScrollInfo()
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
131
|
+
var sInfo = editor.getScrollInfo();
|
132
|
+
if (dv.mv.options.connect == "align") {
|
133
|
+
targetPos = sInfo.top;
|
134
|
+
} else {
|
135
|
+
var halfScreen = .5 * sInfo.clientHeight, midY = sInfo.top + halfScreen;
|
136
|
+
var mid = editor.lineAtHeight(midY, "local");
|
137
|
+
var around = chunkBoundariesAround(dv.diff, mid, type == DIFF_INSERT);
|
138
|
+
var off = getOffsets(editor, type == DIFF_INSERT ? around.edit : around.orig);
|
139
|
+
var offOther = getOffsets(other, type == DIFF_INSERT ? around.orig : around.edit);
|
140
|
+
var ratio = (midY - off.top) / (off.bot - off.top);
|
141
|
+
var targetPos = (offOther.top - halfScreen) + ratio * (offOther.bot - offOther.top);
|
142
|
+
|
143
|
+
var botDist, mix;
|
144
|
+
// Some careful tweaking to make sure no space is left out of view
|
145
|
+
// when scrolling to top or bottom.
|
146
|
+
if (targetPos > sInfo.top && (mix = sInfo.top / halfScreen) < 1) {
|
147
|
+
targetPos = targetPos * mix + sInfo.top * (1 - mix);
|
148
|
+
} else if ((botDist = sInfo.height - sInfo.clientHeight - sInfo.top) < halfScreen) {
|
149
|
+
var otherInfo = other.getScrollInfo();
|
150
|
+
var botDistOther = otherInfo.height - otherInfo.clientHeight - targetPos;
|
151
|
+
if (botDistOther > botDist && (mix = botDist / halfScreen) < 1)
|
152
|
+
targetPos = targetPos * mix + (otherInfo.height - otherInfo.clientHeight - botDist) * (1 - mix);
|
153
|
+
}
|
147
154
|
}
|
148
155
|
|
149
156
|
other.scrollTo(sInfo.left, targetPos);
|
@@ -161,7 +168,7 @@
|
|
161
168
|
|
162
169
|
function setScrollLock(dv, val, action) {
|
163
170
|
dv.lockScroll = val;
|
164
|
-
if (val && action != false) syncScroll(dv, DIFF_INSERT) &&
|
171
|
+
if (val && action != false) syncScroll(dv, DIFF_INSERT) && makeConnections(dv);
|
165
172
|
dv.lockButton.innerHTML = val ? "\u21db\u21da" : "\u21db \u21da";
|
166
173
|
}
|
167
174
|
|
@@ -249,9 +256,20 @@
|
|
249
256
|
|
250
257
|
// Updating the gap between editor and original
|
251
258
|
|
252
|
-
function
|
259
|
+
function makeConnections(dv) {
|
253
260
|
if (!dv.showDifferences) return;
|
254
261
|
|
262
|
+
var align = dv.mv.options.connect == "align";
|
263
|
+
if (align) {
|
264
|
+
if (!dv.orig.curOp) return dv.orig.operation(function() {
|
265
|
+
makeConnections(dv);
|
266
|
+
});
|
267
|
+
for (var i = 0; i < dv.aligners.length; i++)
|
268
|
+
dv.aligners[i].clear();
|
269
|
+
dv.aligners.length = 0;
|
270
|
+
var extraSpaceAbove = {edit: 0, orig: 0};
|
271
|
+
}
|
272
|
+
|
255
273
|
if (dv.svg) {
|
256
274
|
clear(dv.svg);
|
257
275
|
var w = dv.gap.offsetWidth;
|
@@ -259,45 +277,82 @@
|
|
259
277
|
}
|
260
278
|
if (dv.copyButtons) clear(dv.copyButtons);
|
261
279
|
|
262
|
-
var flip = dv.type == "left";
|
263
280
|
var vpEdit = dv.edit.getViewport(), vpOrig = dv.orig.getViewport();
|
264
281
|
var sTopEdit = dv.edit.getScrollInfo().top, sTopOrig = dv.orig.getScrollInfo().top;
|
265
282
|
iterateChunks(dv.diff, function(topOrig, botOrig, topEdit, botEdit) {
|
266
|
-
if (topEdit
|
267
|
-
topOrig
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
if (flip) { var tmp = topLpx; topLpx = topRpx; topRpx = tmp; }
|
273
|
-
var botLpx = dv.orig.heightAtLine(botOrig, "local") - sTopOrig;
|
274
|
-
var botRpx = dv.edit.heightAtLine(botEdit, "local") - sTopEdit;
|
275
|
-
if (flip) { var tmp = botLpx; botLpx = botRpx; botRpx = tmp; }
|
276
|
-
var curveTop = " C " + w/2 + " " + topRpx + " " + w/2 + " " + topLpx + " " + (w + 2) + " " + topLpx;
|
277
|
-
var curveBot = " C " + w/2 + " " + botLpx + " " + w/2 + " " + botRpx + " -1 " + botRpx;
|
278
|
-
attrs(dv.svg.appendChild(document.createElementNS(svgNS, "path")),
|
279
|
-
"d", "M -1 " + topRpx + curveTop + " L " + (w + 2) + " " + botLpx + curveBot + " z",
|
280
|
-
"class", dv.classes.connect);
|
281
|
-
}
|
282
|
-
if (dv.copyButtons) {
|
283
|
-
var copy = dv.copyButtons.appendChild(elt("div", dv.type == "left" ? "\u21dd" : "\u21dc",
|
284
|
-
"CodeMirror-merge-copy"));
|
285
|
-
var editOriginals = dv.mv.options.allowEditingOriginals;
|
286
|
-
copy.title = editOriginals ? "Push to left" : "Revert chunk";
|
287
|
-
copy.chunk = {topEdit: topEdit, botEdit: botEdit, topOrig: topOrig, botOrig: botOrig};
|
288
|
-
copy.style.top = top + "px";
|
289
|
-
|
290
|
-
if (editOriginals) {
|
291
|
-
var topReverse = dv.orig.heightAtLine(topEdit, "local") - sTopEdit;
|
292
|
-
var copyReverse = dv.copyButtons.appendChild(elt("div", dv.type == "right" ? "\u21dd" : "\u21dc",
|
293
|
-
"CodeMirror-merge-copy-reverse"));
|
294
|
-
copyReverse.title = "Push to right";
|
295
|
-
copyReverse.chunk = {topEdit: topOrig, botEdit: botOrig, topOrig: topEdit, botOrig: botEdit};
|
296
|
-
copyReverse.style.top = topReverse + "px";
|
297
|
-
dv.type == "right" ? copyReverse.style.left = "2px" : copyReverse.style.right = "2px";
|
298
|
-
}
|
283
|
+
if (topEdit <= vpEdit.to && botEdit >= vpEdit.from &&
|
284
|
+
topOrig <= vpOrig.to && botOrig >= vpOrig.from)
|
285
|
+
drawConnectorsForChunk(dv, topOrig, botOrig, topEdit, botEdit, sTopOrig, sTopEdit, w);
|
286
|
+
if (align && (topEdit <= vpEdit.to || topOrig <= vpOrig.to)) {
|
287
|
+
var above = (botEdit < vpEdit.from && botOrig < vpOrig.from);
|
288
|
+
alignChunks(dv, topOrig, botOrig, topEdit, botEdit, above && extraSpaceAbove);
|
299
289
|
}
|
300
290
|
});
|
291
|
+
if (align) {
|
292
|
+
if (extraSpaceAbove.edit)
|
293
|
+
dv.aligners.push(padBelow(dv.edit, 0, extraSpaceAbove.edit));
|
294
|
+
if (extraSpaceAbove.orig)
|
295
|
+
dv.aligners.push(padBelow(dv.orig, 0, extraSpaceAbove.orig));
|
296
|
+
}
|
297
|
+
}
|
298
|
+
|
299
|
+
function drawConnectorsForChunk(dv, topOrig, botOrig, topEdit, botEdit, sTopOrig, sTopEdit, w) {
|
300
|
+
var flip = dv.type == "left";
|
301
|
+
var top = dv.orig.heightAtLine(topOrig, "local") - sTopOrig;
|
302
|
+
if (dv.svg) {
|
303
|
+
var topLpx = top;
|
304
|
+
var topRpx = dv.edit.heightAtLine(topEdit, "local") - sTopEdit;
|
305
|
+
if (flip) { var tmp = topLpx; topLpx = topRpx; topRpx = tmp; }
|
306
|
+
var botLpx = dv.orig.heightAtLine(botOrig, "local") - sTopOrig;
|
307
|
+
var botRpx = dv.edit.heightAtLine(botEdit, "local") - sTopEdit;
|
308
|
+
if (flip) { var tmp = botLpx; botLpx = botRpx; botRpx = tmp; }
|
309
|
+
var curveTop = " C " + w/2 + " " + topRpx + " " + w/2 + " " + topLpx + " " + (w + 2) + " " + topLpx;
|
310
|
+
var curveBot = " C " + w/2 + " " + botLpx + " " + w/2 + " " + botRpx + " -1 " + botRpx;
|
311
|
+
attrs(dv.svg.appendChild(document.createElementNS(svgNS, "path")),
|
312
|
+
"d", "M -1 " + topRpx + curveTop + " L " + (w + 2) + " " + botLpx + curveBot + " z",
|
313
|
+
"class", dv.classes.connect);
|
314
|
+
}
|
315
|
+
if (dv.copyButtons) {
|
316
|
+
var copy = dv.copyButtons.appendChild(elt("div", dv.type == "left" ? "\u21dd" : "\u21dc",
|
317
|
+
"CodeMirror-merge-copy"));
|
318
|
+
var editOriginals = dv.mv.options.allowEditingOriginals;
|
319
|
+
copy.title = editOriginals ? "Push to left" : "Revert chunk";
|
320
|
+
copy.chunk = {topEdit: topEdit, botEdit: botEdit, topOrig: topOrig, botOrig: botOrig};
|
321
|
+
copy.style.top = top + "px";
|
322
|
+
|
323
|
+
if (editOriginals) {
|
324
|
+
var topReverse = dv.orig.heightAtLine(topEdit, "local") - sTopEdit;
|
325
|
+
var copyReverse = dv.copyButtons.appendChild(elt("div", dv.type == "right" ? "\u21dd" : "\u21dc",
|
326
|
+
"CodeMirror-merge-copy-reverse"));
|
327
|
+
copyReverse.title = "Push to right";
|
328
|
+
copyReverse.chunk = {topEdit: topOrig, botEdit: botOrig, topOrig: topEdit, botOrig: botEdit};
|
329
|
+
copyReverse.style.top = topReverse + "px";
|
330
|
+
dv.type == "right" ? copyReverse.style.left = "2px" : copyReverse.style.right = "2px";
|
331
|
+
}
|
332
|
+
}
|
333
|
+
}
|
334
|
+
|
335
|
+
function alignChunks(dv, topOrig, botOrig, topEdit, botEdit, aboveViewport) {
|
336
|
+
var topOrigPx = dv.orig.heightAtLine(topOrig, "local");
|
337
|
+
var botOrigPx = dv.orig.heightAtLine(botOrig, "local");
|
338
|
+
var topEditPx = dv.edit.heightAtLine(topEdit, "local");
|
339
|
+
var botEditPx = dv.edit.heightAtLine(botEdit, "local");
|
340
|
+
var origH = botOrigPx -topOrigPx, editH = botEditPx - topEditPx;
|
341
|
+
var diff = editH - origH;
|
342
|
+
if (diff > 1) {
|
343
|
+
if (aboveViewport) aboveViewport.orig += diff;
|
344
|
+
else dv.aligners.push(padBelow(dv.orig, botOrig - 1, diff));
|
345
|
+
} else if (diff < -1) {
|
346
|
+
if (aboveViewport) aboveViewport.edit -= diff;
|
347
|
+
else dv.aligners.push(padBelow(dv.edit, botEdit - 1, -diff));
|
348
|
+
}
|
349
|
+
return 0;
|
350
|
+
}
|
351
|
+
|
352
|
+
function padBelow(cm, line, size) {
|
353
|
+
var elt = document.createElement("div");
|
354
|
+
elt.style.height = size + "px"; elt.style.minWidth = "1px";
|
355
|
+
return cm.addLineWidget(line, elt, {height: size});
|
301
356
|
}
|
302
357
|
|
303
358
|
function copyChunk(dv, to, from, chunk) {
|
@@ -313,6 +368,13 @@
|
|
313
368
|
|
314
369
|
this.options = options;
|
315
370
|
var origLeft = options.origLeft, origRight = options.origRight == null ? options.orig : options.origRight;
|
371
|
+
if (origLeft && origRight) {
|
372
|
+
if (options.connect == "align")
|
373
|
+
throw new Error("connect: \"align\" is not supported for three-way merge views");
|
374
|
+
if (options.collapseIdentical)
|
375
|
+
throw new Error("collapseIdentical option is not supported for three-way merge views");
|
376
|
+
}
|
377
|
+
|
316
378
|
var hasLeft = origLeft != null, hasRight = origRight != null;
|
317
379
|
var panes = 1 + (hasLeft ? 1 : 0) + (hasRight ? 1 : 0);
|
318
380
|
var wrap = [], left = this.left = null, right = this.right = null;
|
@@ -344,9 +406,12 @@
|
|
344
406
|
if (left) left.init(leftPane, origLeft, options);
|
345
407
|
if (right) right.init(rightPane, origRight, options);
|
346
408
|
|
409
|
+
if (options.collapseIdentical)
|
410
|
+
collapseIdenticalStretches(left || right, options.collapseIdentical);
|
411
|
+
|
347
412
|
var onResize = function() {
|
348
|
-
if (left)
|
349
|
-
if (right)
|
413
|
+
if (left) makeConnections(left);
|
414
|
+
if (right) makeConnections(right);
|
350
415
|
};
|
351
416
|
CodeMirror.on(window, "resize", onResize);
|
352
417
|
var resizeInterval = setInterval(function() {
|
@@ -374,10 +439,12 @@
|
|
374
439
|
});
|
375
440
|
gapElts.unshift(dv.copyButtons);
|
376
441
|
}
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
442
|
+
if (dv.mv.options.connect != "align") {
|
443
|
+
var svg = document.createElementNS && document.createElementNS(svgNS, "svg");
|
444
|
+
if (svg && !svg.createSVGRect) svg = null;
|
445
|
+
dv.svg = svg;
|
446
|
+
if (svg) gapElts.push(svg);
|
447
|
+
}
|
381
448
|
|
382
449
|
return dv.gap = elt("div", gapElts, "CodeMirror-merge-gap");
|
383
450
|
}
|
@@ -489,6 +556,46 @@
|
|
489
556
|
return {edit: {before: beforeE, after: afterE}, orig: {before: beforeO, after: afterO}};
|
490
557
|
}
|
491
558
|
|
559
|
+
function collapseSingle(cm, from, to) {
|
560
|
+
cm.addLineClass(from, "wrap", "CodeMirror-merge-collapsed-line");
|
561
|
+
var widget = document.createElement("span");
|
562
|
+
widget.className = "CodeMirror-merge-collapsed-widget";
|
563
|
+
widget.title = "Identical text collapsed. Click to expand.";
|
564
|
+
var mark = cm.markText(Pos(from, 0), Pos(to - 1), {
|
565
|
+
inclusiveLeft: true,
|
566
|
+
inclusiveRight: true,
|
567
|
+
replacedWith: widget,
|
568
|
+
clearOnEnter: true
|
569
|
+
});
|
570
|
+
function clear() {
|
571
|
+
mark.clear();
|
572
|
+
cm.removeLineClass(from, "wrap", "CodeMirror-merge-collapsed-line");
|
573
|
+
}
|
574
|
+
widget.addEventListener("click", clear);
|
575
|
+
return {mark: mark, clear: clear};
|
576
|
+
}
|
577
|
+
|
578
|
+
function collapseStretch(dv, origStart, editStart, size) {
|
579
|
+
var mOrig = collapseSingle(dv.orig, origStart, origStart + size);
|
580
|
+
var mEdit = collapseSingle(dv.edit, editStart, editStart + size);
|
581
|
+
mOrig.mark.on("clear", function() { mEdit.clear(); });
|
582
|
+
mEdit.mark.on("clear", function() { mOrig.clear(); });
|
583
|
+
}
|
584
|
+
|
585
|
+
function collapseIdenticalStretches(dv, margin) {
|
586
|
+
if (typeof margin != "number") margin = 2;
|
587
|
+
var lastOrig = dv.orig.firstLine(), lastEdit = dv.edit.firstLine();
|
588
|
+
iterateChunks(dv.diff, function(topOrig, botOrig, _topEdit, botEdit) {
|
589
|
+
var identicalSize = topOrig - margin - lastOrig;
|
590
|
+
if (identicalSize > margin)
|
591
|
+
collapseStretch(dv, lastOrig, lastEdit, identicalSize);
|
592
|
+
lastOrig = botOrig + margin; lastEdit = botEdit + margin;
|
593
|
+
});
|
594
|
+
var bottomSize = dv.orig.lastLine() + 1 - lastOrig;
|
595
|
+
if (bottomSize > margin)
|
596
|
+
collapseStretch(dv, lastOrig, lastEdit, bottomSize);
|
597
|
+
}
|
598
|
+
|
492
599
|
// General utilities
|
493
600
|
|
494
601
|
function elt(tag, content, className, style) {
|