Add intraline highlights to gr-new-diff
Change-Id: Ia797012253a537552a9640f6eaa78b6fcb10c02b
This commit is contained in:
@@ -40,6 +40,11 @@
|
||||
REMOVED: 'a',
|
||||
};
|
||||
|
||||
GrDiffBuilder.Highlights = {
|
||||
ADDED: 'edit_b',
|
||||
REMOVED: 'edit_a',
|
||||
};
|
||||
|
||||
GrDiffBuilder.Side = {
|
||||
LEFT: 'left',
|
||||
RIGHT: 'right',
|
||||
@@ -90,12 +95,25 @@
|
||||
}
|
||||
|
||||
if (group[GrDiffBuilder.GroupType.REMOVED] !== undefined) {
|
||||
var highlights;
|
||||
if (group[GrDiffBuilder.Highlights.REMOVED] !== undefined) {
|
||||
highlights = this._normalizeIntralineHighlights(
|
||||
group[GrDiffBuilder.GroupType.REMOVED],
|
||||
group[GrDiffBuilder.Highlights.REMOVED]);
|
||||
}
|
||||
this._appendRemovedLines(group[GrDiffBuilder.GroupType.REMOVED], lines,
|
||||
lineNums);
|
||||
lineNums, highlights);
|
||||
}
|
||||
|
||||
if (group[GrDiffBuilder.GroupType.ADDED] !== undefined) {
|
||||
var highlights;
|
||||
if (group[GrDiffBuilder.Highlights.ADDED] !== undefined) {
|
||||
highlights = this._normalizeIntralineHighlights(
|
||||
group[GrDiffBuilder.GroupType.ADDED],
|
||||
group[GrDiffBuilder.Highlights.ADDED]);
|
||||
}
|
||||
this._appendAddedLines(group[GrDiffBuilder.GroupType.ADDED], lines,
|
||||
lineNums);
|
||||
lineNums, highlights);
|
||||
}
|
||||
groups.push(new GrDiffGroup(GrDiffGroup.Type.DELTA, lines));
|
||||
}
|
||||
@@ -171,6 +189,66 @@
|
||||
return result;
|
||||
};
|
||||
|
||||
// The `highlights` array consists of a list of <skip length, mark length>
|
||||
// pairs, where the skip length is the number of characters between the
|
||||
// end of the previous edit and the start of this edit, and the mark
|
||||
// length is the number of edited characters following the skip. The start
|
||||
// of the edits is from the beginning of the related diff content lines.
|
||||
//
|
||||
// Note that the implied newline character at the end of each line is
|
||||
// included in the length calculation, and thus it is possible for the
|
||||
// edits to span newlines.
|
||||
//
|
||||
// A line highlight object consists of three fields:
|
||||
// - contentIndex: The index of the diffChunk `content` field (the line
|
||||
// being referred to).
|
||||
// - startIndex: Where the highlight should begin.
|
||||
// - endIndex: (optional) Where the highlight should end. If omitted, the
|
||||
// highlight is meant to be a continuation onto the next line.
|
||||
GrDiffBuilder.prototype._normalizeIntralineHighlights = function(content,
|
||||
highlights) {
|
||||
var contentIndex = 0;
|
||||
var idx = 0;
|
||||
var normalized = [];
|
||||
for (var i = 0; i < highlights.length; i++) {
|
||||
var line = content[contentIndex] + '\n';
|
||||
var hl = highlights[i];
|
||||
var j = 0;
|
||||
while (j < hl[0]) {
|
||||
if (idx === line.length) {
|
||||
idx = 0;
|
||||
line = content[++contentIndex] + '\n';
|
||||
continue;
|
||||
}
|
||||
idx++;
|
||||
j++;
|
||||
}
|
||||
var lineHighlight = {
|
||||
contentIndex: contentIndex,
|
||||
startIndex: idx,
|
||||
};
|
||||
|
||||
j = 0;
|
||||
while (line && j < hl[1]) {
|
||||
if (idx === line.length) {
|
||||
idx = 0;
|
||||
line = content[++contentIndex] + '\n';
|
||||
normalized.push(lineHighlight);
|
||||
lineHighlight = {
|
||||
contentIndex: contentIndex,
|
||||
startIndex: idx,
|
||||
};
|
||||
continue;
|
||||
}
|
||||
idx++;
|
||||
j++;
|
||||
}
|
||||
lineHighlight.endIndex = idx;
|
||||
normalized.push(lineHighlight);
|
||||
}
|
||||
return normalized;
|
||||
};
|
||||
|
||||
GrDiffBuilder.prototype._insertContextGroups = function(groups, lines,
|
||||
hiddenRange) {
|
||||
var linesBeforeCtx = lines.slice(0, hiddenRange[0]);
|
||||
@@ -201,21 +279,32 @@
|
||||
}
|
||||
};
|
||||
|
||||
GrDiffBuilder.prototype._appendRemovedLines = function(rows, lines,
|
||||
lineNums) {
|
||||
GrDiffBuilder.prototype._appendRemovedLines = function(rows, lines, lineNums,
|
||||
opt_highlights) {
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
var line = new GrDiffLine(GrDiffLine.Type.REMOVE);
|
||||
line.text = rows[i];
|
||||
line.beforeNumber = ++lineNums.left;
|
||||
if (opt_highlights) {
|
||||
line.highlights = opt_highlights.filter(function(hl) {
|
||||
return hl.contentIndex === i;
|
||||
});
|
||||
}
|
||||
lines.push(line);
|
||||
}
|
||||
};
|
||||
|
||||
GrDiffBuilder.prototype._appendAddedLines = function(rows, lines, lineNums) {
|
||||
GrDiffBuilder.prototype._appendAddedLines = function(rows, lines, lineNums,
|
||||
opt_highlights) {
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
var line = new GrDiffLine(GrDiffLine.Type.ADD);
|
||||
line.text = rows[i];
|
||||
line.afterNumber = ++lineNums.right;
|
||||
if (opt_highlights) {
|
||||
line.highlights = opt_highlights.filter(function(hl) {
|
||||
return hl.contentIndex === i;
|
||||
});
|
||||
}
|
||||
lines.push(line);
|
||||
}
|
||||
};
|
||||
@@ -334,6 +423,14 @@
|
||||
td.classList.add(line.type);
|
||||
var text = line.text;
|
||||
var html = util.escapeHTML(text);
|
||||
|
||||
td.classList.add(line.highlights.length > 0 ?
|
||||
'lightHighlight' : 'darkHighlight');
|
||||
|
||||
if (line.highlights.length > 0) {
|
||||
html = this._addIntralineHighlights(text, html, line.highlights);
|
||||
}
|
||||
|
||||
if (text.length > this._prefs.line_length) {
|
||||
html = this._addNewlines(text, html);
|
||||
}
|
||||
@@ -410,6 +507,41 @@
|
||||
return html.replace(GrDiffBuilder.TAB_REGEX, htmlStr);
|
||||
};
|
||||
|
||||
GrDiffBuilder.prototype._addIntralineHighlights = function(content, html,
|
||||
highlights) {
|
||||
var START_TAG = '<hl class="style-scope gr-new-diff">';
|
||||
var END_TAG = '</hl>';
|
||||
|
||||
for (var i = 0; i < highlights.length; i++) {
|
||||
var hl = highlights[i];
|
||||
|
||||
var htmlStartIndex = 0;
|
||||
// Find the index of the HTML string to insert the start tag.
|
||||
for (var j = 0; j < hl.startIndex; j++) {
|
||||
htmlStartIndex = this._advanceChar(html, htmlStartIndex);
|
||||
}
|
||||
|
||||
var htmlEndIndex = 0;
|
||||
if (hl.endIndex !== undefined) {
|
||||
for (var j = 0; j < hl.endIndex; j++) {
|
||||
htmlEndIndex = this._advanceChar(html, htmlEndIndex);
|
||||
}
|
||||
} else {
|
||||
// If endIndex isn't present, continue to the end of the line.
|
||||
htmlEndIndex = html.length;
|
||||
}
|
||||
// The start and end indices could be the same if a highlight is meant
|
||||
// to start at the end of a line and continue onto the next one.
|
||||
// Ignore it.
|
||||
if (htmlStartIndex !== htmlEndIndex) {
|
||||
html = html.slice(0, htmlStartIndex) + START_TAG +
|
||||
html.slice(htmlStartIndex, htmlEndIndex) + END_TAG +
|
||||
html.slice(htmlEndIndex);
|
||||
}
|
||||
}
|
||||
return html;
|
||||
};
|
||||
|
||||
GrDiffBuilder.prototype._getTabWrapper = function(tabSize, showTabs) {
|
||||
// Force this to be a number to prevent arbitrary injection.
|
||||
tabSize = +tabSize;
|
||||
|
||||
@@ -431,5 +431,86 @@ limitations under the License.
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
test('intraline normalization', function() {
|
||||
// The content and highlights are in the format returned by the Gerrit
|
||||
// REST API.
|
||||
var content = [
|
||||
' <section class="summary">',
|
||||
' <gr-linked-text content="' +
|
||||
'[[_computeCurrentRevisionMessage(change)]]"></gr-linked-text>',
|
||||
' </section>',
|
||||
];
|
||||
var highlights = [
|
||||
[31, 34], [42, 26]
|
||||
];
|
||||
var results = GrDiffBuilder.prototype._normalizeIntralineHighlights(
|
||||
content, highlights);
|
||||
assert.deepEqual(results, [
|
||||
{
|
||||
contentIndex: 0,
|
||||
startIndex: 31,
|
||||
},
|
||||
{
|
||||
contentIndex: 1,
|
||||
startIndex: 0,
|
||||
endIndex: 33,
|
||||
},
|
||||
{
|
||||
contentIndex: 1,
|
||||
startIndex: 75,
|
||||
},
|
||||
{
|
||||
contentIndex: 2,
|
||||
startIndex: 0,
|
||||
endIndex: 6,
|
||||
}
|
||||
]);
|
||||
|
||||
content = [
|
||||
' this._path = value.path;',
|
||||
'',
|
||||
' // When navigating away from the page, there is a possibility that the',
|
||||
' // patch number is no longer a part of the URL (say when navigating to',
|
||||
' // the top-level change info view) and therefore undefined in `params`.',
|
||||
' if (!this._patchRange.patchNum) {',
|
||||
];
|
||||
highlights = [
|
||||
[14, 17],
|
||||
[11, 70],
|
||||
[12, 67],
|
||||
[12, 67],
|
||||
[14, 29],
|
||||
];
|
||||
results = GrDiffBuilder.prototype._normalizeIntralineHighlights(content,
|
||||
highlights);
|
||||
assert.deepEqual(results, [
|
||||
{
|
||||
contentIndex: 0,
|
||||
startIndex: 14,
|
||||
endIndex: 31,
|
||||
},
|
||||
{
|
||||
contentIndex: 2,
|
||||
startIndex: 8,
|
||||
endIndex: 78,
|
||||
},
|
||||
{
|
||||
contentIndex: 3,
|
||||
startIndex: 11,
|
||||
endIndex: 78,
|
||||
},
|
||||
{
|
||||
contentIndex: 4,
|
||||
startIndex: 11,
|
||||
endIndex: 78,
|
||||
},
|
||||
{
|
||||
contentIndex: 5,
|
||||
startIndex: 12,
|
||||
endIndex: 41,
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
function GrDiffLine(type) {
|
||||
this.type = type;
|
||||
this.contextLines = [];
|
||||
this.highlights = [];
|
||||
}
|
||||
|
||||
GrDiffLine.prototype.beforeNumber = 0;
|
||||
|
||||
@@ -92,7 +92,7 @@ limitations under the License.
|
||||
}
|
||||
.content {
|
||||
overflow: hidden;
|
||||
width: var(--content-width, 80ch);
|
||||
min-width: var(--content-width, 80ch);
|
||||
}
|
||||
.content.left {
|
||||
-webkit-user-select: var(--left-user-select, text);
|
||||
@@ -106,12 +106,20 @@ limitations under the License.
|
||||
-ms-user-select: var(--right-user-select, text);
|
||||
user-select: var(--right-user-select, text);
|
||||
}
|
||||
.content.add {
|
||||
.content.add hl,
|
||||
.content.add.darkHighlight {
|
||||
background-color: var(--dark-add-highlight-color);
|
||||
}
|
||||
.content.remove {
|
||||
.content.add.lightHighlight {
|
||||
background-color: var(--light-add-highlight-color);
|
||||
}
|
||||
.content.remove hl,
|
||||
.content.remove.darkHighlight {
|
||||
background-color: var(--dark-remove-highlight-color);
|
||||
}
|
||||
.content.remove.lightHighlight {
|
||||
background-color: var(--light-remove.highlight-color);
|
||||
}
|
||||
.contextControl {
|
||||
color: #849;
|
||||
background-color: #fef;
|
||||
|
||||
Reference in New Issue
Block a user