diff options
author | Tim Zallmann <tzallmann@gitlab.com> | 2018-03-23 11:45:43 +0100 |
---|---|---|
committer | Tim Zallmann <tzallmann@gitlab.com> | 2018-03-28 12:17:02 +0200 |
commit | f62359c23b86bb8c8dc241ff4e09bab24e74ccbd (patch) | |
tree | f2ac4a95d433ce476fd5337cabed81c8bb524530 /app/assets/javascripts/ide/lib | |
parent | 06afa5a3ff82e2d6edbcf668cc870e625784c09c (diff) | |
download | gitlab-ce-f62359c23b86bb8c8dc241ff4e09bab24e74ccbd.tar.gz |
Basic Setup for MR Showing
Diffstat (limited to 'app/assets/javascripts/ide/lib')
-rw-r--r-- | app/assets/javascripts/ide/lib/common/model.js | 14 | ||||
-rw-r--r-- | app/assets/javascripts/ide/lib/diff/revert_patch.js | 183 | ||||
-rw-r--r-- | app/assets/javascripts/ide/lib/editor.js | 7 |
3 files changed, 204 insertions, 0 deletions
diff --git a/app/assets/javascripts/ide/lib/common/model.js b/app/assets/javascripts/ide/lib/common/model.js index 73cd684351c..8e16df99a03 100644 --- a/app/assets/javascripts/ide/lib/common/model.js +++ b/app/assets/javascripts/ide/lib/common/model.js @@ -22,6 +22,16 @@ export default class Model { )), ); + if (this.file.targetBranch) { + this.disposable.add( + (this.targetModel = this.monaco.editor.createModel( + this.file.targetRaw, + undefined, + new this.monaco.Uri(null, null, `target/${this.file.path}`), + )), + ); + } + this.events = new Map(); this.updateContent = this.updateContent.bind(this); @@ -58,6 +68,10 @@ export default class Model { return this.originalModel; } + getTargetModel() { + return this.targetModel; + } + setValue(value) { this.getModel().setValue(value); } diff --git a/app/assets/javascripts/ide/lib/diff/revert_patch.js b/app/assets/javascripts/ide/lib/diff/revert_patch.js new file mode 100644 index 00000000000..21c90adedd8 --- /dev/null +++ b/app/assets/javascripts/ide/lib/diff/revert_patch.js @@ -0,0 +1,183 @@ +export function revertPatch(source, uniDiff, options = {}) { + if (typeof uniDiff === 'string') { + uniDiff = parsePatch(uniDiff); + } + + if (Array.isArray(uniDiff)) { + if (uniDiff.length > 1) { + throw new Error('applyPatch only works with a single input.'); + } + + uniDiff = uniDiff[0]; + } + + // Apply the diff to the input + let lines = source.split(/\r\n|[\n\v\f\r\x85]/), + delimiters = source.match(/\r\n|[\n\v\f\r\x85]/g) || [], + hunks = uniDiff.hunks, + compareLine = + options.compareLine || + ((lineNumber, line, operation, patchContent) => line === patchContent), + errorCount = 0, + fuzzFactor = options.fuzzFactor || 0, + minLine = 0, + offset = 0, + removeEOFNL, + addEOFNL; + + /** + * Checks if the hunk exactly fits on the provided location + */ + function hunkFits(hunk, toPos) { + for (let j = 0; j < hunk.lines.length; j++) { + let line = hunk.lines[j], + operation = line[0], + content = line.substr(1); + + if (operation === ' ' || operation === '-') { + // Context sanity check + if (!compareLine(toPos + 1, lines[toPos], operation, content)) { + errorCount++; + + if (errorCount > fuzzFactor) { + return false; + } + } + toPos++; + } + } + + return true; + } + + // Search best fit offsets for each hunk based on the previous ones + for (let i = 0; i < hunks.length; i++) { + let hunk = hunks[i], + maxLine = lines.length - hunk.oldLines, + localOffset = 0, + toPos = offset + hunk.oldStart - 1; + + const iterator = distanceIterator(toPos, minLine, maxLine); + + for (; localOffset !== undefined; localOffset = iterator()) { + if (hunkFits(hunk, toPos + localOffset)) { + hunk.offset = offset += localOffset; + break; + } + } + + if (localOffset === undefined) { + return false; + } + + // Set lower text limit to end of the current hunk, so next ones don't try + // to fit over already patched text + minLine = hunk.offset + hunk.oldStart + hunk.oldLines; + } + + // Apply patch hunks + let diffOffset = 0; + for (let i = 0; i < hunks.length; i++) { + let hunk = hunks[i], + toPos = hunk.oldStart + hunk.offset + diffOffset - 1; + diffOffset += hunk.newLines - hunk.oldLines; + + if (toPos < 0) { + // Creating a new file + toPos = 0; + } + + for (let j = 0; j < hunk.lines.length; j++) { + let line = hunk.lines[j], + operation = line[0], + content = line.substr(1), + delimiter = hunk.linedelimiters[j]; + + // Turned around the commands to revert the applying + if (operation === ' ') { + toPos++; + } else if (operation === '+') { + lines.splice(toPos, 1); + delimiters.splice(toPos, 1); + /* istanbul ignore else */ + } else if (operation === '-') { + lines.splice(toPos, 0, content); + delimiters.splice(toPos, 0, delimiter); + toPos++; + } else if (operation === '\\') { + const previousOperation = hunk.lines[j - 1] + ? hunk.lines[j - 1][0] + : null; + if (previousOperation === '+') { + removeEOFNL = true; + } else if (previousOperation === '-') { + addEOFNL = true; + } + } + } + } + + // Handle EOFNL insertion/removal + if (removeEOFNL) { + while (!lines[lines.length - 1]) { + lines.pop(); + delimiters.pop(); + } + } else if (addEOFNL) { + lines.push(''); + delimiters.push('\n'); + } + for (let _k = 0; _k < lines.length - 1; _k++) { + lines[_k] = lines[_k] + delimiters[_k]; + } + return lines.join(''); +} + +/** + * Utility Function + * @param {*} start + * @param {*} minLine + * @param {*} maxLine + */ +const distanceIterator = function(start, minLine, maxLine) { + let wantForward = true, + backwardExhausted = false, + forwardExhausted = false, + localOffset = 1; + + return function iterator() { + if (wantForward && !forwardExhausted) { + if (backwardExhausted) { + localOffset++; + } else { + wantForward = false; + } + + // Check if trying to fit beyond text length, and if not, check it fits + // after offset location (or desired location on first iteration) + if (start + localOffset <= maxLine) { + return localOffset; + } + + forwardExhausted = true; + } + + if (!backwardExhausted) { + if (!forwardExhausted) { + wantForward = true; + } + + // Check if trying to fit before text beginning, and if not, check it fits + // before offset location + if (minLine <= start - localOffset) { + return -localOffset++; + } + + backwardExhausted = true; + return iterator(); + } + + // We tried to fit hunk before text beginning and beyond text length, then + // hunk can't fit on the text. Return undefined + }; +}; diff --git a/app/assets/javascripts/ide/lib/editor.js b/app/assets/javascripts/ide/lib/editor.js index 887dd7e39b1..cdb277603f0 100644 --- a/app/assets/javascripts/ide/lib/editor.js +++ b/app/assets/javascripts/ide/lib/editor.js @@ -109,6 +109,13 @@ export default class Editor { if (this.dirtyDiffController) this.dirtyDiffController.reDecorate(model); } + attachMergeRequestModel(model) { + this.instance.setModel({ + original: model.getTargetModel(), + modified: model.getModel(), + }); + } + setupMonacoTheme() { this.monaco.editor.defineTheme( gitlabTheme.themeName, |