Do not hide key locations
Probably a regression from properly supporting whitespace only changes. Change-Id: I6cdeef3bb5c617c673222402643c3e2f98c101a3
This commit is contained in:
@@ -146,7 +146,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
content = this._splitLargeChunks(content);
|
content = this._splitLargeChunks(content);
|
||||||
content = this._splitUnchangedChunksWithComments(content);
|
content = this._splitUnchangedChunksWithKeyLocations(content);
|
||||||
|
|
||||||
let currentBatch = 0;
|
let currentBatch = 0;
|
||||||
const nextStep = () => {
|
const nextStep = () => {
|
||||||
@@ -200,15 +200,15 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process the next uncommon section, or the next common sections.
|
* Process the next uncollapsible section, or the next collapsible sections.
|
||||||
*
|
*
|
||||||
* @param {!Object} state
|
* @param {!Object} state
|
||||||
* @param {!Array<!Object>} sections
|
* @param {!Array<!Object>} sections
|
||||||
*/
|
*/
|
||||||
_processNext(state, sections) {
|
_processNext(state, sections) {
|
||||||
const firstUncommonSectionIndex = this._firstUncommonSectionIndex(
|
const firstUncollapsibleSectionIndex =
|
||||||
sections, state.sectionIndex);
|
this._firstUncollapsibleSectionIndex(sections, state.sectionIndex);
|
||||||
if (firstUncommonSectionIndex === state.sectionIndex) {
|
if (firstUncollapsibleSectionIndex === state.sectionIndex) {
|
||||||
const section = sections[state.sectionIndex];
|
const section = sections[state.sectionIndex];
|
||||||
return {
|
return {
|
||||||
lineDelta: {
|
lineDelta: {
|
||||||
@@ -221,25 +221,25 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._processCommonSections(
|
return this._processCollapsibleSections(
|
||||||
state, sections, firstUncommonSectionIndex);
|
state, sections, firstUncollapsibleSectionIndex);
|
||||||
},
|
},
|
||||||
|
|
||||||
_firstUncommonSectionIndex(sections, offset) {
|
_firstUncollapsibleSectionIndex(sections, offset) {
|
||||||
let sectionIndex = offset;
|
let sectionIndex = offset;
|
||||||
while (sectionIndex < sections.length &&
|
while (sectionIndex < sections.length &&
|
||||||
this._isCommonSection(sections[sectionIndex])) {
|
this._isCollapsibleSection(sections[sectionIndex])) {
|
||||||
sectionIndex++;
|
sectionIndex++;
|
||||||
}
|
}
|
||||||
return sectionIndex;
|
return sectionIndex;
|
||||||
},
|
},
|
||||||
|
|
||||||
_isCommonSection(section) {
|
_isCollapsibleSection(section) {
|
||||||
return section.ab || section.common;
|
return (section.ab || section.common) && !section.keyLocation;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process a stretch of common sections.
|
* Process a stretch of collapsible sections.
|
||||||
*
|
*
|
||||||
* Outputs up to three groups:
|
* Outputs up to three groups:
|
||||||
* 1) Visible context before the hidden common code, unless it's the
|
* 1) Visible context before the hidden common code, unless it's the
|
||||||
@@ -250,22 +250,25 @@
|
|||||||
*
|
*
|
||||||
* @param {!Object} state
|
* @param {!Object} state
|
||||||
* @param {!Array<Object>} sections
|
* @param {!Array<Object>} sections
|
||||||
* @param {number} firstUncommonSectionIndex
|
* @param {number} firstUncollapsibleSectionIndex
|
||||||
* @return {!Object}
|
* @return {!Object}
|
||||||
*/
|
*/
|
||||||
_processCommonSections(state, sections, firstUncommonSectionIndex) {
|
_processCollapsibleSections(
|
||||||
const commonSections = sections.slice(
|
state, sections, firstUncollapsibleSectionIndex) {
|
||||||
state.sectionIndex, firstUncommonSectionIndex);
|
const collapsibleSections = sections.slice(
|
||||||
const lineCount = commonSections.reduce(
|
state.sectionIndex, firstUncollapsibleSectionIndex);
|
||||||
|
const lineCount = collapsibleSections.reduce(
|
||||||
(sum, section) => sum + this._commonSectionLength(section), 0);
|
(sum, section) => sum + this._commonSectionLength(section), 0);
|
||||||
|
|
||||||
let groups = this._sectionsToGroups(
|
let groups = this._sectionsToGroups(
|
||||||
commonSections, state.lineNums.left + 1, state.lineNums.right + 1);
|
collapsibleSections,
|
||||||
|
state.lineNums.left + 1,
|
||||||
|
state.lineNums.right + 1);
|
||||||
|
|
||||||
if (this.context !== WHOLE_FILE) {
|
if (this.context !== WHOLE_FILE) {
|
||||||
const hiddenStart = state.sectionIndex === 0 ? 0 : this.context;
|
const hiddenStart = state.sectionIndex === 0 ? 0 : this.context;
|
||||||
const hiddenEnd = lineCount - (
|
const hiddenEnd = lineCount - (
|
||||||
firstUncommonSectionIndex === sections.length ?
|
firstUncollapsibleSectionIndex === sections.length ?
|
||||||
0 : this.context);
|
0 : this.context);
|
||||||
groups = GrDiffGroup.hideInContextControl(
|
groups = GrDiffGroup.hideInContextControl(
|
||||||
groups, hiddenStart, hiddenEnd);
|
groups, hiddenStart, hiddenEnd);
|
||||||
@@ -277,14 +280,15 @@
|
|||||||
right: lineCount,
|
right: lineCount,
|
||||||
},
|
},
|
||||||
groups,
|
groups,
|
||||||
newSectionIndex: firstUncommonSectionIndex,
|
newSectionIndex: firstUncollapsibleSectionIndex,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
_commonSectionLength(section) {
|
_commonSectionLength(section) {
|
||||||
console.assert(section.ab || section.common);
|
console.assert(section.ab || section.common);
|
||||||
console.assert(
|
console.assert(
|
||||||
!section.a || (section.b && section.a.length === section.b.length));
|
!section.a || (section.b && section.a.length === section.b.length),
|
||||||
|
`common section needs same number of a and b lines: `, section);
|
||||||
return (section.ab || section.a).length;
|
return (section.ab || section.a).length;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -302,6 +306,7 @@
|
|||||||
const type = section.ab ? GrDiffGroup.Type.BOTH : GrDiffGroup.Type.DELTA;
|
const type = section.ab ? GrDiffGroup.Type.BOTH : GrDiffGroup.Type.DELTA;
|
||||||
const lines = this._linesFromSection(section, offsetLeft, offsetRight);
|
const lines = this._linesFromSection(section, offsetLeft, offsetRight);
|
||||||
const group = new GrDiffGroup(type, lines);
|
const group = new GrDiffGroup(type, lines);
|
||||||
|
group.keyLocation = section.keyLocation;
|
||||||
group.dueToRebase = section.due_to_rebase;
|
group.dueToRebase = section.due_to_rebase;
|
||||||
group.ignoredWhitespaceOnly = section.common;
|
group.ignoredWhitespaceOnly = section.common;
|
||||||
return group;
|
return group;
|
||||||
@@ -414,13 +419,13 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In order to show comments out of the bounds of the selected context,
|
* In order to show key locations, such as comments, out of the bounds of
|
||||||
* treat them as separate chunks within the model so that the content (and
|
* the selected context, treat them as separate chunks within the model so
|
||||||
* context surrounding it) renders correctly.
|
* that the content (and context surrounding it) renders correctly.
|
||||||
* @param {!Array<!Object>} chunks DiffContents as returned from server.
|
* @param {!Array<!Object>} chunks DiffContents as returned from server.
|
||||||
* @return {!Array<!Object>} Finer grained DiffContents.
|
* @return {!Array<!Object>} Finer grained DiffContents.
|
||||||
*/
|
*/
|
||||||
_splitUnchangedChunksWithComments(chunks) {
|
_splitUnchangedChunksWithKeyLocations(chunks) {
|
||||||
const result = [];
|
const result = [];
|
||||||
let leftLineNum = 1;
|
let leftLineNum = 1;
|
||||||
let rightLineNum = 1;
|
let rightLineNum = 1;
|
||||||
@@ -450,18 +455,24 @@
|
|||||||
|
|
||||||
if (chunk.ab) {
|
if (chunk.ab) {
|
||||||
result.push(...this._splitAtChunkEnds(chunk.ab, chunkEnds)
|
result.push(...this._splitAtChunkEnds(chunk.ab, chunkEnds)
|
||||||
.map(lines => Object.assign({}, chunk, {ab: lines})));
|
.map(({lines, keyLocation}) =>
|
||||||
|
Object.assign({}, chunk, {ab: lines, keyLocation})));
|
||||||
} else if (chunk.common) {
|
} else if (chunk.common) {
|
||||||
const aChunks = this._splitAtChunkEnds(chunk.a, chunkEnds);
|
const aChunks = this._splitAtChunkEnds(chunk.a, chunkEnds);
|
||||||
const bChunks = this._splitAtChunkEnds(chunk.b, chunkEnds);
|
const bChunks = this._splitAtChunkEnds(chunk.b, chunkEnds);
|
||||||
result.push(...aChunks.map((lines, i) =>
|
result.push(...aChunks.map(({lines, keyLocation}, i) =>
|
||||||
Object.assign({}, chunk, {a: lines, b: bChunks[i]})));
|
Object.assign(
|
||||||
|
{}, chunk, {a: lines, b: bChunks[i].lines, keyLocation})));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {!Array<{offset: number, keyLocation: boolean}>} Offsets of the
|
||||||
|
* new chunk ends, including whether it's a key location.
|
||||||
|
*/
|
||||||
_findChunkEndsAtKeyLocations(numLines, leftOffset, rightOffset) {
|
_findChunkEndsAtKeyLocations(numLines, leftOffset, rightOffset) {
|
||||||
const result = [];
|
const result = [];
|
||||||
let lastChunkEnd = 0;
|
let lastChunkEnd = 0;
|
||||||
@@ -473,17 +484,17 @@
|
|||||||
// this non-collapse line, then add them as a chunk and start a new
|
// this non-collapse line, then add them as a chunk and start a new
|
||||||
// one.
|
// one.
|
||||||
if (i > lastChunkEnd) {
|
if (i > lastChunkEnd) {
|
||||||
result.push(i);
|
result.push({offset: i, keyLocation: false});
|
||||||
lastChunkEnd = i;
|
lastChunkEnd = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the non-collapse line as its own chunk.
|
// Add the non-collapse line as its own chunk.
|
||||||
result.push(i + 1);
|
result.push({offset: i + 1, keyLocation: true});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numLines > lastChunkEnd) {
|
if (numLines > lastChunkEnd) {
|
||||||
result.push(numLines);
|
result.push({offset: numLines, keyLocation: false});
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -491,10 +502,11 @@
|
|||||||
|
|
||||||
_splitAtChunkEnds(lines, chunkEnds) {
|
_splitAtChunkEnds(lines, chunkEnds) {
|
||||||
const result = [];
|
const result = [];
|
||||||
let lastChunkEnd = 0;
|
let lastChunkEndOffset = 0;
|
||||||
for (const chunkEnd of chunkEnds) {
|
for (const {offset, keyLocation} of chunkEnds) {
|
||||||
result.push(lines.slice(lastChunkEnd, chunkEnd));
|
result.push(
|
||||||
lastChunkEnd = chunkEnd;
|
{lines: lines.slice(lastChunkEndOffset, offset), keyLocation});
|
||||||
|
lastChunkEndOffset = offset;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
@@ -460,10 +460,11 @@ limitations under the License.
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
const result =
|
const result =
|
||||||
element._splitUnchangedChunksWithComments(content);
|
element._splitUnchangedChunksWithKeyLocations(content);
|
||||||
assert.deepEqual(result, [
|
assert.deepEqual(result, [
|
||||||
{
|
{
|
||||||
ab: ['Copyright (C) 2015 The Android Open Source Project'],
|
ab: ['Copyright (C) 2015 The Android Open Source Project'],
|
||||||
|
keyLocation: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ab: [
|
ab: [
|
||||||
@@ -477,10 +478,12 @@ limitations under the License.
|
|||||||
'',
|
'',
|
||||||
'Unless required by applicable law or agreed to in writing, ',
|
'Unless required by applicable law or agreed to in writing, ',
|
||||||
],
|
],
|
||||||
|
keyLocation: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ab: [
|
ab: [
|
||||||
'software distributed under the License is distributed on an '],
|
'software distributed under the License is distributed on an '],
|
||||||
|
keyLocation: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ab: [
|
ab: [
|
||||||
@@ -489,6 +492,7 @@ limitations under the License.
|
|||||||
'language governing permissions and limitations under the ' +
|
'language governing permissions and limitations under the ' +
|
||||||
'License.',
|
'License.',
|
||||||
],
|
],
|
||||||
|
keyLocation: false,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
@@ -505,14 +509,16 @@ limitations under the License.
|
|||||||
assert.deepEqual(result[1].ab, content[0].ab.slice(120));
|
assert.deepEqual(result[1].ab, content[0].ab.slice(120));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('does not break-down shared chunks w/ context', () => {
|
test('does not break-down common chunks w/ context', () => {
|
||||||
const content = [{
|
const content = [{
|
||||||
ab: _.times(75, () => { return `${Math.random()}`; }),
|
ab: _.times(75, () => { return `${Math.random()}`; }),
|
||||||
}];
|
}];
|
||||||
element.context = 4;
|
element.context = 4;
|
||||||
const result =
|
const result =
|
||||||
element._splitUnchangedChunksWithComments(content);
|
element._splitUnchangedChunksWithKeyLocations(content);
|
||||||
assert.deepEqual(result, content);
|
assert.equal(result.length, 1);
|
||||||
|
assert.deepEqual(result[0].ab, content[0].ab);
|
||||||
|
assert.isFalse(result[0].keyLocation);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('intraline normalization', () => {
|
test('intraline normalization', () => {
|
||||||
@@ -764,6 +770,32 @@ limitations under the License.
|
|||||||
assert.equal(result.groups.length, 1, 'Results in one group');
|
assert.equal(result.groups.length, 1, 'Results in one group');
|
||||||
assert.equal(result.groups[0].lines.length, rows.length);
|
assert.equal(result.groups[0].lines.length, rows.length);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('with key location', () => {
|
||||||
|
element.context = 10;
|
||||||
|
const state = {
|
||||||
|
lineNums: {left: 10, right: 100},
|
||||||
|
sectionIndex: 0,
|
||||||
|
};
|
||||||
|
const sections = [
|
||||||
|
{ab: rows},
|
||||||
|
{ab: ['foo'], keyLocation: true},
|
||||||
|
{ab: rows},
|
||||||
|
];
|
||||||
|
const result = element._processNext(state, sections);
|
||||||
|
|
||||||
|
assert.equal(result.groups.length, 2);
|
||||||
|
|
||||||
|
// The first section has a single context-control line, the second
|
||||||
|
// section is the context before the key location not processed in
|
||||||
|
// this step
|
||||||
|
assert.equal(result.groups[0].lines.length, 1);
|
||||||
|
assert.equal(result.groups[1].lines.length, element.context);
|
||||||
|
|
||||||
|
// The collapsed group has the hidden lines as its context group.
|
||||||
|
assert.equal(result.groups[0].lines[0].contextGroups[0].lines.length,
|
||||||
|
rows.length - element.context);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
suite('gr-diff-processor helpers', () => {
|
suite('gr-diff-processor helpers', () => {
|
||||||
|
@@ -40,6 +40,12 @@
|
|||||||
*/
|
*/
|
||||||
this.ignoredWhitespaceOnly = false;
|
this.ignoredWhitespaceOnly = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True means it should not be collapsed (because it was in the URL, or
|
||||||
|
* there is a comment on that line)
|
||||||
|
*/
|
||||||
|
this.keyLocation = false;
|
||||||
|
|
||||||
/** @type {?HTMLElement} */
|
/** @type {?HTMLElement} */
|
||||||
this.element = null;
|
this.element = null;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user