kopia lustrzana https://github.com/c9/core
778 wiersze
27 KiB
JavaScript
778 wiersze
27 KiB
JavaScript
define(function(require, exports, module) {
|
|
"use strict";
|
|
var oop = require("ace/lib/oop");
|
|
var lang = require("ace/lib/lang");
|
|
var event = require("ace/lib/event");
|
|
var Range = require("ace/range").Range;
|
|
var dom = require("ace/lib/dom");
|
|
var config = require("ace/config");
|
|
|
|
var LineWidgets = require("ace/line_widgets").LineWidgets;
|
|
var css = require("text!./unified.css");
|
|
dom.importCssString(css, "unidiff.css");
|
|
var diff_match_patch = require("./diff_match_patch").diff_match_patch;
|
|
|
|
|
|
var Editor = require("ace/editor").Editor;
|
|
var Renderer = require("ace/virtual_renderer").VirtualRenderer;
|
|
var UndoManager = require("ace/undomanager").UndoManager;
|
|
var EditSession = require("ace/edit_session").EditSession;
|
|
|
|
var Mode = require("ace/mode/text").Mode;
|
|
|
|
var mode = new Mode();
|
|
var HEADER_ROWS = 3;
|
|
|
|
function createEditor(el) {
|
|
if (el instanceof Editor) return el;
|
|
var editor = new Editor(new Renderer(el), null);
|
|
editor.session.setUndoManager(new UndoManager());
|
|
return editor;
|
|
}
|
|
|
|
function DiffView(element, options) {
|
|
this.renderedHeaders = [];
|
|
this.renderHeaders = this.renderHeaders.bind(this);
|
|
this.handleWidgetMouseDown = this.handleWidgetMouseDown.bind(this);
|
|
// this.onInput = this.onInput.bind(this);
|
|
|
|
this.options = {};
|
|
var editor = createEditor(element);
|
|
this.container = editor.container;
|
|
this.editor = editor;
|
|
this.attachToEditor(editor);
|
|
|
|
oop.mixin(this.options, {
|
|
showDiffs: true,
|
|
maxDiffs: 5000
|
|
}, options);
|
|
|
|
config.resetOptions(this);
|
|
config._signal("diffView", this);
|
|
}
|
|
|
|
|
|
(function() {
|
|
|
|
/*** theme/session ***/
|
|
this.setValueFromPatch = function(v) {
|
|
var editor = this.editor;
|
|
var lines = editor.session.doc.$split(v);
|
|
|
|
var states = [];
|
|
var result = [];
|
|
var rowInsert = 0;
|
|
var rowRemove = 0;
|
|
var file;
|
|
var insertedTotal = 0;
|
|
var removedTotal = 0;
|
|
var inserted = 0;
|
|
var removed = 0;
|
|
for (var i = 0; i < lines.length; i++) {
|
|
var line = lines[i];
|
|
if (line[0] == "d" && line.slice(0, 5) == "diff ") {
|
|
if (file) {
|
|
file.inserted = inserted;
|
|
file.removed = removed;
|
|
}
|
|
insertedTotal += inserted;
|
|
removedTotal += removed;
|
|
inserted = removed = 0;
|
|
|
|
file = { type: "file" };
|
|
var none = { type: "none" };
|
|
var path = line.split(" b/").pop();
|
|
result.push("", "", "", path);
|
|
states.push(none, none, none, file);
|
|
while (i + 1 < lines.length && lines[i + 1][0] != "@")
|
|
i++;
|
|
}
|
|
else if (line[0] == "@") {
|
|
var m = line.match(/^@@ -(\d+)(,\d+) \+(\d+)(,\d+) @@/);
|
|
if (m) {
|
|
rowRemove = parseInt(m[1], 10);
|
|
rowInsert = parseInt(m[3], 10);
|
|
result.push(line);
|
|
states.push({ type: "header" });
|
|
}
|
|
}
|
|
else if (line[0] == " ") {
|
|
result.push(line.substr(1));
|
|
states.push({ type: "context", row2: rowInsert, row1: rowRemove });
|
|
rowInsert++;
|
|
rowRemove++;
|
|
}
|
|
else if (line[0] == "+") {
|
|
result.push(line.substr(1));
|
|
states.push({ type: "insert", row2: rowInsert, row1: "" });
|
|
rowInsert++;
|
|
inserted++;
|
|
}
|
|
else if (line[0] == "-") {
|
|
result.push(line.substr(1));
|
|
states.push({ type: "remove", row2: "", row1: rowRemove });
|
|
rowRemove++;
|
|
removed++;
|
|
}
|
|
}
|
|
|
|
result.push("", "");
|
|
states.push({ type: "none" }, { type: "file" });
|
|
|
|
v = result.join("\n");
|
|
editor.setValue(v, -1);
|
|
editor.session.bgTokenizer.diffStates = states;
|
|
editor.session.bgTokenizer.stop();
|
|
editor.setReadOnly(true);
|
|
editor.session.bgTokenizer.getTokens = function(row) {
|
|
var line = this.doc.getLine(row);
|
|
var type = this.diffStates[row].type;
|
|
return [{
|
|
value: line,
|
|
type: "uniDiff_" + type
|
|
}];
|
|
};
|
|
if (!editor.session.meta)
|
|
editor.session.meta = {};
|
|
editor.session.meta.deletedLines = removedTotal;
|
|
editor.session.meta.addedLines = insertedTotal;
|
|
};
|
|
|
|
this.foldingRules = {
|
|
getFoldWidget: function(session, foldStyle, row) {
|
|
var state = session.bgTokenizer.diffStates[row];
|
|
if (state && state.type == "file" || state.type == "header")
|
|
return "start";
|
|
return "";
|
|
},
|
|
|
|
getFoldWidgetRange: function(session, foldStyle, row) {
|
|
var states = session.bgTokenizer.diffStates;
|
|
var state = states[row];
|
|
var type = state.type;
|
|
if (!state || (type != "header" && type != "file"))
|
|
return null;
|
|
|
|
var line = session.getLine(row);
|
|
var start = { row: row, column: line.length };
|
|
|
|
for (var l = states.length; ++row < l;) {
|
|
state = states[row];
|
|
if (state.type == type || state.type == "file" || state.type == "none")
|
|
break;
|
|
}
|
|
if (row == start.row + 1)
|
|
return;
|
|
return new Range(start.row, start.column, row - 1, session.getLine(row - 1).length);
|
|
}
|
|
};
|
|
|
|
this.attachToEditor = function(editor) {
|
|
mode.foldingRules = this.foldingRules;
|
|
editor.session.setMode(mode);
|
|
editor.session.removeMarker(editor.session.mi);
|
|
editor.session.mi = editor.session.addDynamicMarker(new DiffHighlight);
|
|
editor.renderer.on("afterRender", this.renderHeaders);
|
|
editor.session.diffView = this;
|
|
editor.renderer.$gutterLayer.$cells = [];
|
|
editor.renderer.$gutterLayer.element.innerHTML = "";
|
|
editor.renderer.$gutterLayer.gutterWidth = NaN;
|
|
editor.renderer.$gutterLayer.$padding = null;
|
|
editor.renderer.$gutterLayer.update = this.updateGutter;
|
|
editor.diffView = this;
|
|
};
|
|
|
|
this.updateGutter = function(config) {
|
|
var session = this.session;
|
|
var firstRow = config.firstRow;
|
|
var lastRow = Math.min(config.lastRow + config.gutterOffset, // needed to compensate for hor scollbar
|
|
session.getLength() - 1);
|
|
var fold = session.getNextFoldLine(firstRow);
|
|
var foldStart = fold ? fold.start.row : Infinity;
|
|
var foldWidgets = this.$showFoldWidgets && session.foldWidgets;
|
|
|
|
var diffStates = session.bgTokenizer.diffStates;
|
|
|
|
if (!diffStates)
|
|
return;
|
|
|
|
var cell = null;
|
|
var index = -1;
|
|
var row = firstRow;
|
|
while (true) {
|
|
if (row > foldStart) {
|
|
row = fold.end.row + 1;
|
|
fold = session.getNextFoldLine(row, fold);
|
|
foldStart = fold ? fold.start.row : Infinity;
|
|
}
|
|
if (row > lastRow) {
|
|
while (this.$cells.length > index + 1) {
|
|
cell = this.$cells.pop();
|
|
this.element.removeChild(cell.element);
|
|
}
|
|
break;
|
|
}
|
|
|
|
cell = this.$cells[++index];
|
|
if (!cell) {
|
|
cell = { element: null, textNode: null, foldWidget: null };
|
|
cell.element = dom.createElement("div");
|
|
cell.textNode = document.createTextNode('');
|
|
cell.element1 = dom.createElement("span");
|
|
cell.element2 = dom.createElement("span");
|
|
cell.element1.className = "unidiff-cell first";
|
|
cell.element2.className = "unidiff-cell";
|
|
cell.element.appendChild(cell.element1);
|
|
cell.element.appendChild(cell.element2);
|
|
this.element.appendChild(cell.element);
|
|
this.$cells[index] = cell;
|
|
}
|
|
|
|
var line = session.getLine(row);
|
|
var state = diffStates[row];
|
|
var className = "unidiff_gutter-cell unidiff " + state.type;
|
|
|
|
if (cell.element.className != className)
|
|
cell.element.className = className;
|
|
|
|
var height = session.getRowLength(row) * config.lineHeight + "px";
|
|
if (height != cell.element.style.height)
|
|
cell.element.style.height = height;
|
|
|
|
if (foldWidgets) {
|
|
var c = foldWidgets[row];
|
|
// check if cached value is invalidated and we need to recompute
|
|
if (c == null)
|
|
c = foldWidgets[row] = session.getFoldWidget(row);
|
|
}
|
|
|
|
if (c) {
|
|
if (!cell.foldWidget) {
|
|
cell.foldWidget = dom.createElement("span");
|
|
cell.element.appendChild(cell.foldWidget);
|
|
}
|
|
var className = "ace_fold-widget ace_" + c;
|
|
if (c == "start" && row == foldStart && row < fold.end.row)
|
|
className += " ace_closed";
|
|
else
|
|
className += " ace_open";
|
|
if (cell.foldWidget.className != className)
|
|
cell.foldWidget.className = className;
|
|
|
|
var height = config.lineHeight + "px";
|
|
if (cell.foldWidget.style.height != height)
|
|
cell.foldWidget.style.height = height;
|
|
} else {
|
|
if (cell.foldWidget) {
|
|
cell.element.removeChild(cell.foldWidget);
|
|
cell.foldWidget = null;
|
|
}
|
|
}
|
|
|
|
if (line[0] == "@") {
|
|
cell.element1.innerHTML =
|
|
cell.element2.innerHTML = "<span style='cursor:pointer'>\xb7\xb7\xb7</span>";
|
|
} else {
|
|
cell.element1.textContent = state.row1 || "\x1b";
|
|
cell.element2.textContent = state.row2 || "\x1b";
|
|
}
|
|
row++;
|
|
}
|
|
|
|
this.element.style.height = config.minHeight + "px";
|
|
|
|
var gutterWidth = 2 * 6 * config.characterWidth;
|
|
|
|
var padding = this.$padding || this.$computePadding();
|
|
gutterWidth += padding.left + padding.right;
|
|
if (gutterWidth !== this.gutterWidth && !isNaN(gutterWidth)) {
|
|
this.gutterWidth = gutterWidth;
|
|
this.element.style.width = Math.ceil(this.gutterWidth) + "px";
|
|
this._emit("changeGutterWidth", gutterWidth);
|
|
}
|
|
};
|
|
|
|
this.handleWidgetMouseDown = function(e) {
|
|
e.stopPropagation();
|
|
var w = e.currentTarget.w;
|
|
var editor = this.editor;
|
|
if (e.target.classList.contains("ace_fold-widget")) {
|
|
editor.session.onFoldWidgetClick(w.row, { domEvent: e });
|
|
e.preventDefault();
|
|
}
|
|
};
|
|
this.createWidget = function(row, renderedHeaders) {
|
|
var w = {
|
|
row: row,
|
|
el: document.createElement("div"),
|
|
rowCount: 0,
|
|
pixelHeight: 0,
|
|
foldClosed: false,
|
|
coverGutter: 1,
|
|
fixedWidth: true
|
|
};
|
|
w.el.onmousedown = this.handleWidgetMouseDown;
|
|
renderedHeaders.push(w);
|
|
w.el.w = w;
|
|
return w;
|
|
};
|
|
this.renderWidget = function(w, i, state) {
|
|
if (state === w.state)
|
|
return;
|
|
w.state = state;
|
|
var editor = this.editor;
|
|
var session = editor.session;
|
|
var line = session.getLine(i);
|
|
var lineHeight = editor.renderer.layerConfig.lineHeight;
|
|
w.el.style.borderTopWidth = i > HEADER_ROWS ? "" : "0";
|
|
w.el.className = "unidiff_fileHeader ace_lineWidgetContainer";
|
|
if (!line) {
|
|
w.el.style.height = lineHeight * 100 + "px";
|
|
w.el.innerHTML = "";
|
|
w.foldArrow = null;
|
|
return;
|
|
}
|
|
w.el.style.height = lineHeight * HEADER_ROWS + "px";
|
|
w.el.innerHTML = '<div class="unidiff_fileHeaderInner">'
|
|
+ '<span class="ace_fold-widget ace_start' + (w.foldClosed ? 'ace_closed' : '') + '"\
|
|
style="height:1.5em;left: -20px;\
|
|
position: relative;display: inline-block;"></span>'
|
|
+ " " + lang.escapeHTML(line) + " "
|
|
+ '<div>';
|
|
w.foldArrow = w.el.firstChild.firstChild;
|
|
w.el.firstChild.style.height = lineHeight * HEADER_ROWS + "px";
|
|
w.el.firstChild.style.marginTop = lineHeight + "px";
|
|
};
|
|
this.renderHeaders = function(e, renderer) {
|
|
var config = renderer.layerConfig;
|
|
var session = renderer.session;
|
|
var diffStates = session.bgTokenizer.diffStates;
|
|
if (!diffStates)
|
|
return;
|
|
var first = Math.max(0, config.firstRow - HEADER_ROWS);
|
|
var last = Math.min(diffStates.length, config.lastRow + HEADER_ROWS);
|
|
|
|
this.firstRow = config.firstRow;
|
|
this.lastRow = config.lastRow;
|
|
|
|
var renderedHeaders = this.renderedHeaders;
|
|
var j = 0;
|
|
renderer.$cursorLayer.config = config;
|
|
|
|
var fold = session.getNextFoldLine(first);
|
|
var foldStart = fold ? fold.start.row : Infinity;
|
|
|
|
var row = first || 0;
|
|
while (true) {
|
|
if (row > foldStart) {
|
|
row = fold.end.row + 1;
|
|
fold = session.getNextFoldLine(row, fold);
|
|
foldStart = fold ? fold.start.row : Infinity;
|
|
}
|
|
if (row > last) {
|
|
break;
|
|
}
|
|
var state = diffStates[row];
|
|
if (!state || diffStates[row].type != "file") {
|
|
row++;
|
|
continue;
|
|
}
|
|
var w = renderedHeaders[j] || this.createWidget(row, renderedHeaders);
|
|
j++;
|
|
this.renderWidget(w, row, state);
|
|
var foldClosed = fold && fold.start.row == row;
|
|
if (foldClosed != w.foldClosed && w.foldArrow) {
|
|
w.foldClosed = foldClosed;
|
|
dom.setCssClass(w.foldArrow, "ace_closed", !!foldClosed);
|
|
w.el.firstChild.style.borderBottomColor = foldClosed ? "transparent" : "";
|
|
}
|
|
if (!w._inDocument) {
|
|
w._inDocument = true;
|
|
renderer.container.appendChild(w.el);
|
|
}
|
|
var top = renderer.$cursorLayer.getPixelPosition({
|
|
row: row - (row == diffStates.length - 1 ? 1 : HEADER_ROWS),
|
|
column: 0
|
|
}, true).top;
|
|
w.el.style.top = top - config.offset + "px";
|
|
w.row = row;
|
|
|
|
var left = w.coverGutter ? 0 : renderer.gutterWidth;
|
|
w.el.style.left = left + "px";
|
|
|
|
if (w.fixedWidth) {
|
|
w.el.style.right = renderer.scrollBar.getWidth() + "px";
|
|
} else {
|
|
w.el.style.right = "";
|
|
}
|
|
|
|
row++;
|
|
}
|
|
|
|
for (var k = j; k < renderedHeaders.length; k++) {
|
|
var h = renderedHeaders[k];
|
|
if (h.el) h.el.remove();
|
|
}
|
|
renderedHeaders.length = j;
|
|
};
|
|
|
|
/*** patch ***/
|
|
this.createPatch = function(options) {
|
|
var chunks = this.chunks;
|
|
var editLines = this.edit.session.doc.getAllLines();
|
|
var origLines = this.orig.session.doc.getAllLines();
|
|
var path1 = options.path1 || options.path || "_";
|
|
var path2 = options.path2 || path1;
|
|
var patch = [
|
|
"diff --git a/" + path1 + " b/" + path2,
|
|
"--- a/" + path1,
|
|
"+++ b/" + path2,
|
|
].join("\n");
|
|
|
|
if (!chunks.length) {
|
|
chunks = [{
|
|
origStart: 0,
|
|
origEnd: 0,
|
|
editStart: 0,
|
|
editEnd: 0
|
|
}];
|
|
}
|
|
|
|
function header(s1, c1, s2, c2) {
|
|
return "@@ -" + (c1 ? s1 + 1 : s1) + "," + c1
|
|
+ " +" + (c2 ? s2 + 1 : s2) + "," + c2 + " @@";
|
|
}
|
|
|
|
var context = options.context || 0;
|
|
// changed newline at the end of file
|
|
var editEOF = !editLines[editLines.length - 1];
|
|
var origEOF = !origLines[origLines.length - 1];
|
|
if (editEOF)
|
|
editLines.pop();
|
|
if (origEOF)
|
|
origLines.pop();
|
|
if (editEOF != origEOF) {
|
|
chunks = chunks.slice();
|
|
var last = chunks.pop();
|
|
chunks.push(last = {
|
|
origStart: Math.min(last.origStart, origLines.length - 1),
|
|
origEnd: Math.min(last.origEnd, origLines.length),
|
|
editStart: Math.min(last.editStart, editLines.length - 1),
|
|
editEnd: Math.min(last.editEnd, editLines.length)
|
|
});
|
|
}
|
|
|
|
var hunk = "";
|
|
var start1 = 0;
|
|
var start2 = 0;
|
|
var end1 = 0;
|
|
var end2 = 0;
|
|
var length1 = 0;
|
|
var length2 = 0;
|
|
var mergeWithNext = false;
|
|
for (var i = 0; i < chunks.length; i++) {
|
|
var ch = chunks[i];
|
|
var s1 = ch.origStart;
|
|
var e1 = ch.origEnd;
|
|
var s2 = ch.editStart;
|
|
var e2 = ch.editEnd;
|
|
var next = chunks[i + 1];
|
|
|
|
|
|
start1 = Math.max(s1 - context, end1);
|
|
start2 = Math.max(s2 - context, end2);
|
|
end1 = Math.min(e1 + context, origLines.length);
|
|
end2 = Math.min(e2 + context, editLines.length);
|
|
|
|
mergeWithNext = false;
|
|
if (next) {
|
|
if (end1 >= next.origStart - context) {
|
|
end1 = next.origStart;
|
|
end2 = next.editStart;
|
|
mergeWithNext = true;
|
|
}
|
|
}
|
|
|
|
for (var j = start1; j < s1; j++)
|
|
hunk += "\n " + origLines[j];
|
|
for (var j = s1; j < e1; j++)
|
|
hunk += "\n-" + origLines[j];
|
|
if (ch == last && editEOF)
|
|
hunk += "\n\\ No newline at end of file";
|
|
for (var j = s2; j < e2; j++)
|
|
hunk += "\n+" + editLines[j];
|
|
if (ch == last && origEOF)
|
|
hunk += "\n\\ No newline at end of file";
|
|
for (var j = e1; j < end1; j++)
|
|
hunk += "\n " + origLines[j];
|
|
|
|
length1 += end1 - start1;
|
|
length2 += end2 - start2;
|
|
if (mergeWithNext)
|
|
continue;
|
|
|
|
patch += "\n" + header(end1 - length1, length1, end2 - length2, length2) + hunk;
|
|
length2 = length1 = 0;
|
|
hunk = "";
|
|
}
|
|
|
|
if (!editEOF && !origEOF && end1 == origLines.length) {
|
|
patch += "\n\\ No newline at end of file";
|
|
}
|
|
|
|
return patch;
|
|
};
|
|
|
|
this.applyPatch = function(oldStr, uniDiff) {
|
|
var lines = uniDiff.split("\n");
|
|
var hunks = [];
|
|
var i = 0;
|
|
var EOFChanged = 0;
|
|
|
|
// Skip to the first change hunk
|
|
while (i < lines.length && !(/^@@/.test(lines[i]))) {
|
|
i++;
|
|
}
|
|
|
|
// Parse the unified diff
|
|
for (; i < lines.length; i++) {
|
|
var tag = lines[i][0];
|
|
var line = lines[i].substr(1);
|
|
if (tag === "@") {
|
|
var chunkHeader = /@@ -(\d+)(?:,(\d*))? \+(\d+)(?:,(\d*)) @@/.exec(line);
|
|
hunks.unshift({
|
|
start: +chunkHeader[1],
|
|
oldlength: +chunkHeader[2] || 1,
|
|
removed: [],
|
|
added: []
|
|
});
|
|
}
|
|
else if (tag === "+") {
|
|
hunks[0].added.push(line);
|
|
}
|
|
else if (tag === "-") {
|
|
hunks[0].removed.push(line);
|
|
}
|
|
else if (tag === " ") {
|
|
hunks[0].added.push(line);
|
|
hunks[0].removed.push(line);
|
|
}
|
|
else if (tag === "\\") {
|
|
if (lines[i - 1][0] === "+")
|
|
EOFChanged = 1;
|
|
else if (lines[i - 1][0] === "-")
|
|
EOFChanged = -1;
|
|
}
|
|
}
|
|
|
|
// Apply the diff to the input
|
|
lines = oldStr.split("\n");
|
|
for (i = hunks.length - 1; i >= 0; i--) {
|
|
var hunk = hunks[i];
|
|
// Sanity check the input string. Bail if we don't match.
|
|
for (var j = 0; j < hunk.oldlength; j++) {
|
|
if (lines[hunk.start - 1 + j] !== hunk.removed[j]) {
|
|
return false;
|
|
}
|
|
}
|
|
lines.splice.apply(lines, [hunk.start - 1, hunk.oldlength].concat(hunk.added));
|
|
}
|
|
|
|
// Handle EOFNL insertion/removal
|
|
if (EOFChanged == -1) {
|
|
while (!lines[lines.length - 1]) {
|
|
lines.pop();
|
|
}
|
|
}
|
|
else if (EOFChanged == 1) {
|
|
lines.push("");
|
|
}
|
|
return lines.join("\n");
|
|
};
|
|
|
|
/*** options ***/
|
|
config.defineOptions(this, "editor", {
|
|
alignDiffs: {
|
|
set: function(val) {
|
|
if (val)
|
|
this.align();
|
|
},
|
|
initialValue: false
|
|
},
|
|
});
|
|
}).call(DiffView.prototype);
|
|
|
|
function findChunkIndex(chunks, row, orig) {
|
|
if (orig) {
|
|
for (var i = 0; i < chunks.length; i++) {
|
|
var ch = chunks[i];
|
|
if (ch.origEnd < row) continue;
|
|
if (ch.origStart > row) break;
|
|
}
|
|
}
|
|
else {
|
|
for (var i = 0; i < chunks.length; i++) {
|
|
var ch = chunks[i];
|
|
if (ch.editEnd < row) continue;
|
|
if (ch.editStart > row) break;
|
|
}
|
|
}
|
|
return i - 1;
|
|
}
|
|
|
|
|
|
|
|
var DiffHighlight = function(diffView, type) {
|
|
this.diffView = diffView;
|
|
this.type = type;
|
|
};
|
|
|
|
(function() {
|
|
this.MAX_RANGES = 500;
|
|
|
|
this.update = function(html, markerLayer, session, config) {
|
|
var start = config.firstRow;
|
|
var end = config.lastRow;
|
|
|
|
var diffView = this.diffView;
|
|
var chunks = diffView.chunks;
|
|
var isOrig = this.type == -1;
|
|
var type = this.type;
|
|
var index = findChunkIndex(chunks, start, isOrig);
|
|
if (index == -1 && chunks.length && (isOrig ? chunks[0].origStart : chunks[0].editStart) > start)
|
|
index = 0;
|
|
var chunk = chunks[index];
|
|
while (chunk) {
|
|
if (isOrig) {
|
|
if (chunk.origStart > end && chunk.origStart != chunk.origEnd)
|
|
return;
|
|
var range = new Range(chunk.origStart, 0, chunk.origEnd - 1, 1);
|
|
var l1 = chunk.origEnd - chunk.origStart;
|
|
var l2 = chunk.editEnd - chunk.editStart;
|
|
}
|
|
else {
|
|
if (chunk.editStart > end && chunk.editStart != chunk.editEnd)
|
|
return;
|
|
range = new Range(chunk.editStart, 0, chunk.editEnd - 1, 1);
|
|
l1 = chunk.origEnd - chunk.origStart;
|
|
l2 = chunk.editEnd - chunk.editStart;
|
|
}
|
|
var className = "";
|
|
if (!l1 && isOrig || !l2 && !isOrig) {
|
|
className = range.start.row == session.getLength() ? "insertEnd" : "insertStart";
|
|
}
|
|
className += chunk.type == -1 ? " delete" : chunk.type == 1 ? " insert" : "";
|
|
|
|
markerLayer.drawFullLineMarker(html, range.toScreenRange(session),
|
|
"unidiff " + className, config);
|
|
var inlineChanges = chunk.inlineChanges;
|
|
var row = range.start.row;
|
|
var column = 0;
|
|
for (var j = 0; j < inlineChanges.length; j++) {
|
|
var diff = inlineChanges[j];
|
|
if (diff[0] == 0) {
|
|
if (diff[1]) {
|
|
row += diff[1];
|
|
column = diff[2];
|
|
}
|
|
else {
|
|
column += diff[2];
|
|
}
|
|
}
|
|
else {
|
|
range.start.row = row;
|
|
range.start.column = column;
|
|
if (row > end)
|
|
break;
|
|
if (diff[0] == (isOrig ? -1 : 1)) {
|
|
type = isOrig ? "delete" : "insert";
|
|
if (diff[1]) {
|
|
row += diff[1];
|
|
column = diff[2];
|
|
}
|
|
else {
|
|
column += diff[2];
|
|
}
|
|
}
|
|
else {
|
|
type = isOrig ? "insert" : "delete";
|
|
}
|
|
if (row < start)
|
|
continue;
|
|
range.end.row = row;
|
|
range.end.column = column;
|
|
if (range.isEmpty())
|
|
type += " empty";
|
|
|
|
var screenRange = range.clipRows(start, end).toScreenRange(session);
|
|
if (screenRange.isMultiLine()) {
|
|
markerLayer.drawTextMarker(html, screenRange, "unidiff inline " + type, config);
|
|
}
|
|
else {
|
|
markerLayer.drawSingleLineMarker(html, screenRange, "unidiff inline " + type, config);
|
|
}
|
|
}
|
|
}
|
|
chunk = chunks[++index];
|
|
}
|
|
};
|
|
|
|
}).call(DiffHighlight.prototype);
|
|
|
|
|
|
var DiffHighlight = function(diffView, type) {
|
|
this.diffView = diffView;
|
|
};
|
|
|
|
(function() {
|
|
this.MAX_RANGES = 500;
|
|
|
|
this.update = function(html, markerLayer, session, config) {
|
|
var first = config.firstRow;
|
|
var last = config.lastRow;
|
|
var states = session.bgTokenizer.diffStates;
|
|
var range = new Range(0, 0, 0, 1);
|
|
var lastType = "";
|
|
if (!states)
|
|
return;
|
|
var fold = session.getNextFoldLine(first);
|
|
var foldStart = fold ? fold.start.row : Infinity;
|
|
var row = first || 0;
|
|
while (true) {
|
|
if (row > foldStart) {
|
|
row = fold.end.row + 1;
|
|
fold = session.getNextFoldLine(row, fold);
|
|
foldStart = fold ? fold.start.row : Infinity;
|
|
}
|
|
|
|
var type = row <= last ? states[row].type : "";
|
|
if (lastType != type) {
|
|
if (lastType) {
|
|
markerLayer.drawFullLineMarker(html, range.toScreenRange(session),
|
|
"unidiff marker " + lastType, config);
|
|
}
|
|
if (type == "insert" || type == "remove" || type == "header") {
|
|
range.start.row = row;
|
|
lastType = type;
|
|
} else {
|
|
lastType = "";
|
|
}
|
|
}
|
|
if (row > last) {
|
|
break;
|
|
}
|
|
range.end.row = row;
|
|
|
|
row++;
|
|
}
|
|
};
|
|
|
|
}).call(DiffHighlight.prototype);
|
|
|
|
|
|
|
|
|
|
module.exports.DiffView = DiffView;
|
|
|
|
});
|