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._splitUnchangedChunksWithComments(content);
 | 
			
		||||
            content = this._splitUnchangedChunksWithKeyLocations(content);
 | 
			
		||||
 | 
			
		||||
            let currentBatch = 0;
 | 
			
		||||
            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 {!Array<!Object>} sections
 | 
			
		||||
     */
 | 
			
		||||
    _processNext(state, sections) {
 | 
			
		||||
      const firstUncommonSectionIndex = this._firstUncommonSectionIndex(
 | 
			
		||||
          sections, state.sectionIndex);
 | 
			
		||||
      if (firstUncommonSectionIndex === state.sectionIndex) {
 | 
			
		||||
      const firstUncollapsibleSectionIndex =
 | 
			
		||||
          this._firstUncollapsibleSectionIndex(sections, state.sectionIndex);
 | 
			
		||||
      if (firstUncollapsibleSectionIndex === state.sectionIndex) {
 | 
			
		||||
        const section = sections[state.sectionIndex];
 | 
			
		||||
        return {
 | 
			
		||||
          lineDelta: {
 | 
			
		||||
@@ -221,25 +221,25 @@
 | 
			
		||||
        };
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return this._processCommonSections(
 | 
			
		||||
          state, sections, firstUncommonSectionIndex);
 | 
			
		||||
      return this._processCollapsibleSections(
 | 
			
		||||
          state, sections, firstUncollapsibleSectionIndex);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _firstUncommonSectionIndex(sections, offset) {
 | 
			
		||||
    _firstUncollapsibleSectionIndex(sections, offset) {
 | 
			
		||||
      let sectionIndex = offset;
 | 
			
		||||
      while (sectionIndex < sections.length &&
 | 
			
		||||
          this._isCommonSection(sections[sectionIndex])) {
 | 
			
		||||
          this._isCollapsibleSection(sections[sectionIndex])) {
 | 
			
		||||
        sectionIndex++;
 | 
			
		||||
      }
 | 
			
		||||
      return sectionIndex;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _isCommonSection(section) {
 | 
			
		||||
      return section.ab || section.common;
 | 
			
		||||
    _isCollapsibleSection(section) {
 | 
			
		||||
      return (section.ab || section.common) && !section.keyLocation;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Process a stretch of common sections.
 | 
			
		||||
     * Process a stretch of collapsible sections.
 | 
			
		||||
     *
 | 
			
		||||
     * Outputs up to three groups:
 | 
			
		||||
     *  1) Visible context before the hidden common code, unless it's the
 | 
			
		||||
@@ -250,22 +250,25 @@
 | 
			
		||||
     *
 | 
			
		||||
     * @param {!Object} state
 | 
			
		||||
     * @param {!Array<Object>} sections
 | 
			
		||||
     * @param {number} firstUncommonSectionIndex
 | 
			
		||||
     * @param {number} firstUncollapsibleSectionIndex
 | 
			
		||||
     * @return {!Object}
 | 
			
		||||
     */
 | 
			
		||||
    _processCommonSections(state, sections, firstUncommonSectionIndex) {
 | 
			
		||||
      const commonSections = sections.slice(
 | 
			
		||||
          state.sectionIndex, firstUncommonSectionIndex);
 | 
			
		||||
      const lineCount = commonSections.reduce(
 | 
			
		||||
    _processCollapsibleSections(
 | 
			
		||||
        state, sections, firstUncollapsibleSectionIndex) {
 | 
			
		||||
      const collapsibleSections = sections.slice(
 | 
			
		||||
          state.sectionIndex, firstUncollapsibleSectionIndex);
 | 
			
		||||
      const lineCount = collapsibleSections.reduce(
 | 
			
		||||
          (sum, section) => sum + this._commonSectionLength(section), 0);
 | 
			
		||||
 | 
			
		||||
      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) {
 | 
			
		||||
        const hiddenStart = state.sectionIndex === 0 ? 0 : this.context;
 | 
			
		||||
        const hiddenEnd = lineCount - (
 | 
			
		||||
            firstUncommonSectionIndex === sections.length ?
 | 
			
		||||
            firstUncollapsibleSectionIndex === sections.length ?
 | 
			
		||||
            0 : this.context);
 | 
			
		||||
        groups = GrDiffGroup.hideInContextControl(
 | 
			
		||||
            groups, hiddenStart, hiddenEnd);
 | 
			
		||||
@@ -277,14 +280,15 @@
 | 
			
		||||
          right: lineCount,
 | 
			
		||||
        },
 | 
			
		||||
        groups,
 | 
			
		||||
        newSectionIndex: firstUncommonSectionIndex,
 | 
			
		||||
        newSectionIndex: firstUncollapsibleSectionIndex,
 | 
			
		||||
      };
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _commonSectionLength(section) {
 | 
			
		||||
      console.assert(section.ab || section.common);
 | 
			
		||||
      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;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -302,6 +306,7 @@
 | 
			
		||||
      const type = section.ab ? GrDiffGroup.Type.BOTH : GrDiffGroup.Type.DELTA;
 | 
			
		||||
      const lines = this._linesFromSection(section, offsetLeft, offsetRight);
 | 
			
		||||
      const group = new GrDiffGroup(type, lines);
 | 
			
		||||
      group.keyLocation = section.keyLocation;
 | 
			
		||||
      group.dueToRebase = section.due_to_rebase;
 | 
			
		||||
      group.ignoredWhitespaceOnly = section.common;
 | 
			
		||||
      return group;
 | 
			
		||||
@@ -414,13 +419,13 @@
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * In order to show comments out of the bounds of the selected context,
 | 
			
		||||
     * treat them as separate chunks within the model so that the content (and
 | 
			
		||||
     * context surrounding it) renders correctly.
 | 
			
		||||
     * In order to show key locations, such as comments, out of the bounds of
 | 
			
		||||
     * the selected context, treat them as separate chunks within the model so
 | 
			
		||||
     * that the content (and context surrounding it) renders correctly.
 | 
			
		||||
     * @param {!Array<!Object>} chunks DiffContents as returned from server.
 | 
			
		||||
     * @return {!Array<!Object>} Finer grained DiffContents.
 | 
			
		||||
     */
 | 
			
		||||
    _splitUnchangedChunksWithComments(chunks) {
 | 
			
		||||
    _splitUnchangedChunksWithKeyLocations(chunks) {
 | 
			
		||||
      const result = [];
 | 
			
		||||
      let leftLineNum = 1;
 | 
			
		||||
      let rightLineNum = 1;
 | 
			
		||||
@@ -450,18 +455,24 @@
 | 
			
		||||
 | 
			
		||||
        if (chunk.ab) {
 | 
			
		||||
          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) {
 | 
			
		||||
          const aChunks = this._splitAtChunkEnds(chunk.a, chunkEnds);
 | 
			
		||||
          const bChunks = this._splitAtChunkEnds(chunk.b, chunkEnds);
 | 
			
		||||
          result.push(...aChunks.map((lines, i) =>
 | 
			
		||||
              Object.assign({}, chunk, {a: lines, b: bChunks[i]})));
 | 
			
		||||
          result.push(...aChunks.map(({lines, keyLocation}, i) =>
 | 
			
		||||
            Object.assign(
 | 
			
		||||
                {}, chunk, {a: lines, b: bChunks[i].lines, keyLocation})));
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      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) {
 | 
			
		||||
      const result = [];
 | 
			
		||||
      let lastChunkEnd = 0;
 | 
			
		||||
@@ -473,17 +484,17 @@
 | 
			
		||||
          // this non-collapse line, then add them as a chunk and start a new
 | 
			
		||||
          // one.
 | 
			
		||||
          if (i > lastChunkEnd) {
 | 
			
		||||
            result.push(i);
 | 
			
		||||
            result.push({offset: i, keyLocation: false});
 | 
			
		||||
            lastChunkEnd = i;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          // Add the non-collapse line as its own chunk.
 | 
			
		||||
          result.push(i + 1);
 | 
			
		||||
          result.push({offset: i + 1, keyLocation: true});
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (numLines > lastChunkEnd) {
 | 
			
		||||
        result.push(numLines);
 | 
			
		||||
        result.push({offset: numLines, keyLocation: false});
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return result;
 | 
			
		||||
@@ -491,10 +502,11 @@
 | 
			
		||||
 | 
			
		||||
    _splitAtChunkEnds(lines, chunkEnds) {
 | 
			
		||||
      const result = [];
 | 
			
		||||
      let lastChunkEnd = 0;
 | 
			
		||||
      for (const chunkEnd of chunkEnds) {
 | 
			
		||||
        result.push(lines.slice(lastChunkEnd, chunkEnd));
 | 
			
		||||
        lastChunkEnd = chunkEnd;
 | 
			
		||||
      let lastChunkEndOffset = 0;
 | 
			
		||||
      for (const {offset, keyLocation} of chunkEnds) {
 | 
			
		||||
        result.push(
 | 
			
		||||
            {lines: lines.slice(lastChunkEndOffset, offset), keyLocation});
 | 
			
		||||
        lastChunkEndOffset = offset;
 | 
			
		||||
      }
 | 
			
		||||
      return result;
 | 
			
		||||
    },
 | 
			
		||||
 
 | 
			
		||||
@@ -460,10 +460,11 @@ limitations under the License.
 | 
			
		||||
          },
 | 
			
		||||
        ];
 | 
			
		||||
        const result =
 | 
			
		||||
            element._splitUnchangedChunksWithComments(content);
 | 
			
		||||
            element._splitUnchangedChunksWithKeyLocations(content);
 | 
			
		||||
        assert.deepEqual(result, [
 | 
			
		||||
          {
 | 
			
		||||
            ab: ['Copyright (C) 2015 The Android Open Source Project'],
 | 
			
		||||
            keyLocation: true,
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            ab: [
 | 
			
		||||
@@ -477,10 +478,12 @@ limitations under the License.
 | 
			
		||||
              '',
 | 
			
		||||
              'Unless required by applicable law or agreed to in writing, ',
 | 
			
		||||
            ],
 | 
			
		||||
            keyLocation: false,
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            ab: [
 | 
			
		||||
              'software distributed under the License is distributed on an '],
 | 
			
		||||
            keyLocation: true,
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            ab: [
 | 
			
		||||
@@ -489,6 +492,7 @@ limitations under the License.
 | 
			
		||||
              'language governing permissions and limitations under the ' +
 | 
			
		||||
                  'License.',
 | 
			
		||||
            ],
 | 
			
		||||
            keyLocation: false,
 | 
			
		||||
          },
 | 
			
		||||
        ]);
 | 
			
		||||
      });
 | 
			
		||||
@@ -505,14 +509,16 @@ limitations under the License.
 | 
			
		||||
        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 = [{
 | 
			
		||||
          ab: _.times(75, () => { return `${Math.random()}`; }),
 | 
			
		||||
        }];
 | 
			
		||||
        element.context = 4;
 | 
			
		||||
        const result =
 | 
			
		||||
            element._splitUnchangedChunksWithComments(content);
 | 
			
		||||
        assert.deepEqual(result, content);
 | 
			
		||||
            element._splitUnchangedChunksWithKeyLocations(content);
 | 
			
		||||
        assert.equal(result.length, 1);
 | 
			
		||||
        assert.deepEqual(result[0].ab, content[0].ab);
 | 
			
		||||
        assert.isFalse(result[0].keyLocation);
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      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[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', () => {
 | 
			
		||||
 
 | 
			
		||||
@@ -40,6 +40,12 @@
 | 
			
		||||
     */
 | 
			
		||||
    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} */
 | 
			
		||||
    this.element = null;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user