Merge "Add ignore-whitespace control"
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.js b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.js
index 3e9e796..6f61fb9 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.js
@@ -28,6 +28,8 @@
UNIFIED: 'UNIFIED_DIFF',
};
+ const WHITESPACE_IGNORE_NONE = 'IGNORE_NONE';
+
/**
* @param {Object} diff
* @return {boolean}
@@ -105,7 +107,10 @@
type: Boolean,
reflectToAttribute: true,
},
- noRenderOnPrefsChange: Boolean,
+ noRenderOnPrefsChange: {
+ type: Boolean,
+ value: false,
+ },
comments: Object,
lineWrapping: {
type: Boolean,
@@ -167,12 +172,19 @@
type: Object,
value: null,
},
+
+ _loadedWhitespaceLevel: String,
},
listeners: {
'draft-interaction': '_handleDraftInteraction',
},
+ observers: [
+ '_whitespaceChanged(prefs.ignore_whitespace, _loadedWhitespaceLevel,' +
+ ' noRenderOnPrefsChange)',
+ ],
+
ready() {
if (this._canReload()) {
this.reload();
@@ -189,10 +201,15 @@
reload() {
this._loading = true;
this._errorMessage = null;
+ const whitespaceLevel = this._getIgnoreWhitespace();
const diffRequest = this._getDiff()
.then(diff => {
+ this._loadedWhitespaceLevel = whitespaceLevel;
this._reportDiff(diff);
+ if (this._getIgnoreWhitespace() !== WHITESPACE_IGNORE_NONE) {
+ return this._translateChunksToIgnore(diff);
+ }
return diff;
})
.catch(e => {
@@ -321,6 +338,7 @@
this.patchRange.basePatchNum,
this.patchRange.patchNum,
this.path,
+ this._getIgnoreWhitespace(),
reject)
.then(resolve);
});
@@ -430,5 +448,63 @@
_handleDraftInteraction() {
this.$.reporting.recordDraftInteraction();
},
+
+ /**
+ * Take a diff that was loaded with a ignore-whitespace other than
+ * IGNORE_NONE, and convert delta chunks labeled as common into shared
+ * chunks.
+ * @param {!Object} diff
+ * @returns {!Object}
+ */
+ _translateChunksToIgnore(diff) {
+ const newDiff = Object.assign({}, diff);
+ const mergedContent = [];
+
+ // Was the last chunk visited a shared chunk?
+ let lastWasShared = false;
+
+ for (const chunk of diff.content) {
+ if (lastWasShared && chunk.common && chunk.b) {
+ // The last chunk was shared and this chunk should be ignored, so
+ // add its revision content to the previous chunk.
+ mergedContent[mergedContent.length - 1].ab.push(...chunk.b);
+ } else if (chunk.common && !chunk.b) {
+ // If the chunk should be ignored, but it doesn't have revision
+ // content, then drop it and continue without updating lastWasShared.
+ continue;
+ } else if (lastWasShared && chunk.ab) {
+ // Both the last chunk and the current chunk are shared. Merge this
+ // chunk's shared content into the previous shared content.
+ mergedContent[mergedContent.length - 1].ab.push(...chunk.ab);
+ } else if (!lastWasShared && chunk.common && chunk.b) {
+ // If the previous chunk was not shared, but this one should be
+ // ignored, then add it as a shared chunk.
+ mergedContent.push({ab: chunk.b});
+ } else {
+ // Otherwise add the chunk as is.
+ mergedContent.push(chunk);
+ }
+
+ lastWasShared = !!mergedContent[mergedContent.length - 1].ab;
+ }
+
+ newDiff.content = mergedContent;
+ return newDiff;
+ },
+
+ _getIgnoreWhitespace() {
+ if (!this.prefs || !this.prefs.ignore_whitespace) {
+ return WHITESPACE_IGNORE_NONE;
+ }
+ return this.prefs.ignore_whitespace;
+ },
+
+ _whitespaceChanged(preferredWhitespaceLevel, loadedWhitespaceLevel,
+ noRenderOnPrefsChange) {
+ if (preferredWhitespaceLevel !== loadedWhitespaceLevel &&
+ !noRenderOnPrefsChange) {
+ this.reload();
+ }
+ },
});
})();
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.html b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.html
index a05d44f..f83253e 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.html
@@ -775,5 +775,89 @@
assert.isUndefined(reportStub.lastCall.args[1]);
});
});
+
+ suite('_translateChunksToIgnore', () => {
+ let content;
+
+ setup(() => {
+ content = [
+ {ab: ['one', 'two']},
+ {a: ['three'], b: ['different three']},
+ {b: ['four']},
+ {ab: ['five', 'six']},
+ {a: ['seven']},
+ {ab: ['eight', 'nine']},
+ ];
+ });
+
+ test('does nothing to unmarked diff', () => {
+ assert.deepEqual(element._translateChunksToIgnore({content}),
+ {content});
+ });
+
+ test('merges marked delta chunk', () => {
+ content[1].common = true;
+ assert.deepEqual(element._translateChunksToIgnore({content}), {
+ content: [
+ {ab: ['one', 'two', 'different three']},
+ {b: ['four']},
+ {ab: ['five', 'six']},
+ {a: ['seven']},
+ {ab: ['eight', 'nine']},
+ ],
+ });
+ });
+
+ test('merges marked addition chunk', () => {
+ content[2].common = true;
+ assert.deepEqual(element._translateChunksToIgnore({content}), {
+ content: [
+ {ab: ['one', 'two']},
+ {a: ['three'], b: ['different three']},
+ {ab: ['four', 'five', 'six']},
+ {a: ['seven']},
+ {ab: ['eight', 'nine']},
+ ],
+ });
+ });
+
+ test('merges multiple marked delta', () => {
+ content[1].common = true;
+ content[2].common = true;
+ assert.deepEqual(element._translateChunksToIgnore({content}), {
+ content: [
+ {ab: ['one', 'two', 'different three', 'four', 'five', 'six']},
+ {a: ['seven']},
+ {ab: ['eight', 'nine']},
+ ],
+ });
+ });
+
+ test('marked deletion chunks are omitted', () => {
+ content[4].common = true;
+ assert.deepEqual(element._translateChunksToIgnore({content}), {
+ content: [
+ {ab: ['one', 'two']},
+ {a: ['three'], b: ['different three']},
+ {b: ['four']},
+ {ab: ['five', 'six', 'eight', 'nine']},
+ ],
+ });
+ });
+
+ test('marked deltas can start shared chunks', () => {
+ content[0] = {a: ['one'], b: ['two'], common: true};
+ assert.deepEqual(element._translateChunksToIgnore({content}), {
+ content: [
+ {ab: ['two']},
+ {a: ['three'], b: ['different three']},
+ {b: ['four']},
+ {ab: ['five', 'six']},
+ {a: ['seven']},
+ {ab: ['eight', 'nine']},
+ ],
+ });
+ });
+ });
});
</script>
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.html b/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.html
index 375e598..78814d4 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.html
@@ -60,7 +60,7 @@
align-items: center;
display: flex;
padding: .35em 1.5em;
- width: 20em;
+ width: 25em;
}
.pref:hover {
background-color: var(--hover-background-color);
@@ -149,6 +149,15 @@
type="checkbox"
on-tap="_handleAutomaticReviewTap">
</div>
+ <div class="pref">
+ <label for="ignoreWhitespace">Ignore Whitespace</label>
+ <select id="ignoreWhitespace" on-change="_handleIgnoreWhitespaceChange">
+ <option value="IGNORE_NONE">None</option>
+ <option value="IGNORE_TRAILING">Trailing</option>
+ <option value="IGNORE_LEADING_AND_TRAILING">Leading & trailing</option>
+ <option value="IGNORE_ALL">All</option>
+ </select>
+ </div>
</div>
<div class="actions">
<gr-button id="cancelButton" link on-tap="_handleCancel">
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.js b/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.js
index 47a3c2d..8fc90b9 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.js
@@ -67,6 +67,7 @@
this.$.lineWrappingInput.checked = prefs.line_wrapping;
this.$.syntaxHighlightInput.checked = prefs.syntax_highlighting;
this.$.automaticReviewInput.checked = !prefs.manual_review;
+ this.$.ignoreWhitespace.value = prefs.ignore_whitespace;
},
_localPrefsChanged(changeRecord) {
@@ -79,6 +80,11 @@
this.set('_newPrefs.context', parseInt(selectEl.value, 10));
},
+ _handleIgnoreWhitespaceChange(e) {
+ const selectEl = Polymer.dom(e).rootTarget;
+ this.set('_newPrefs.ignore_whitespace', selectEl.value);
+ },
+
_handleShowTabsTap(e) {
this.set('_newPrefs.show_tabs', Polymer.dom(e).rootTarget.checked);
},
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.html b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.html
index 18c1734..029ce88 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.html
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.html
@@ -348,6 +348,20 @@
on-change="_handleDiffSyntaxHighlightingChanged">
</span>
</section>
+ <section>
+ <div class="pref">
+ <span class="title">Ignore Whitespace</span>
+ <span class="value">
+ <gr-select bind-value="{{_diffPrefs.ignore_whitespace}}">
+ <select>
+ <option value="IGNORE_NONE">None</option>
+ <option value="IGNORE_TRAILING">Trailing</option>
+ <option value="IGNORE_LEADING_AND_TRAILING">Leading & trailing</option>
+ <option value="IGNORE_ALL">All</option>
+ </select>
+ </gr-select>
+ </span>
+ </div>
<gr-button
id="saveDiffPrefs"
on-tap="_handleSaveDiffPreferences"
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
index af10b8371..c97c4c7 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
@@ -2134,13 +2134,16 @@
* index.
* @param {number|string} patchNum
* @param {string} path
+ * @param {string=} opt_whitespace the ignore-whitespace level for the diff
+ * algorithm.
* @param {function(?Response, string=)=} opt_errFn
*/
- getDiff(changeNum, basePatchNum, patchNum, path, opt_errFn) {
+ getDiff(changeNum, basePatchNum, patchNum, path, opt_whitespace,
+ opt_errFn) {
const params = {
context: 'ALL',
intraline: null,
- whitespace: 'IGNORE_NONE',
+ whitespace: opt_whitespace || 'IGNORE_NONE',
};
if (this.isMergeParent(basePatchNum)) {
params.parent = this.getParentIndex(basePatchNum);