codemirror-rails 4.8 → 4.9
Sign up to get free protection for your applications and to get access to all the features.
- 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) {
|