From 10567afbb9275a4bd684ba27d6e6b3d2e3a5b3c1 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Mon, 9 Oct 2017 00:11:07 +0100 Subject: [PATCH] Add unified diff view to version control tab --- editor/js/ui/diff.js | 114 +++++++++++++++++- editor/js/ui/tab-versionControl.js | 28 ++++- editor/sass/diff.scss | 27 +++-- red/api/editor/projects/index.js | 15 +++ .../localfilesystem/projects/git/index.js | 10 ++ .../storage/localfilesystem/projects/index.js | 5 + 6 files changed, 185 insertions(+), 14 deletions(-) diff --git a/editor/js/ui/diff.js b/editor/js/ui/diff.js index 68618de74..891c8cf8b 100644 --- a/editor/js/ui/diff.js +++ b/editor/js/ui/diff.js @@ -1471,7 +1471,7 @@ RED.diff = (function() { } currentBlock.end = diffLength; diffBlocks.push(currentBlock); -console.table(diffBlocks); + // console.table(diffBlocks); var diffRow; for (var b = 0; b'); + diffRow = $(''); var content = $(' ').appendTo(diffRow); var label = $('').appendTo(content); if (end < diffLines.length-1) { @@ -1546,8 +1546,8 @@ console.table(diffBlocks); var Adiff = diffLine.a; var Bdiff = diffLine.b; //console.log(diffLine); - var cellNo = $("").text(Adiff.type === 2?"":Adiff.i).appendTo(diffRow); - var cellLine = $("").text(Adiff.line).appendTo(diffRow); + var cellNo = $('').text(Adiff.type === 2?"":Adiff.i).appendTo(diffRow); + var cellLine = $('').text(Adiff.line).appendTo(diffRow); if (Adiff.type === 2) { cellNo.addClass('blank'); cellLine.addClass('blank'); @@ -1558,8 +1558,8 @@ console.table(diffBlocks); cellNo.addClass('removed'); cellLine.addClass('removed'); } - cellNo = $("").text(Bdiff.type === 2?"":Bdiff.i).appendTo(diffRow); - cellLine = $("").text(Bdiff.line).appendTo(diffRow); + cellNo = $('').text(Bdiff.type === 2?"":Bdiff.i).appendTo(diffRow); + cellLine = $('').text(Bdiff.line).appendTo(diffRow); if (Bdiff.type === 2) { cellNo.addClass('blank'); cellLine.addClass('blank'); @@ -1646,13 +1646,115 @@ console.table(diffBlocks); return string1 === string2 ? 0 : 1; } + function showUnifiedDiff(diff,title) { + var hunks = parseUnifiedDiff(diff); + var trayOptions = { + title: title||"Compare Changes", //TODO: nls + width: Infinity, + overlay: true, + buttons: [ + { + text: RED._("common.label.done"), + click: function() { + RED.tray.close(); + } + } + ], + resize: function(dimensions) { + // trayWidth = dimensions.width; + }, + open: function(tray) { + var trayBody = tray.find('.editor-tray-body'); + var diffPanel = $('
').appendTo(trayBody); + + var codeTable = $("").appendTo(diffPanel); + $('').appendTo(codeTable); + var codeBody = $('').appendTo(codeTable); + + for (var i=0;i').appendTo(codeBody); + var content = $('').appendTo(diffRow); + var label = $('').text(hunks[i].header).appendTo(content); + + var localLine = hunks[i].localStartLine; + var remoteLine = hunks[i].remoteStartLine; + for (var j=0;j').appendTo(codeBody); + var localLineNo = $('
').appendTo(diffRow); + var remoteLineNo = $('').appendTo(diffRow); + var line = $('').appendTo(diffRow); + $('').text(lineText[0]).appendTo(line); + $('').text(lineText.substring(1)).appendTo(line); + if (lineText[0] === '+') { + line.addClass("added"); + remoteLineNo.text(remoteLine++); + } else if (lineText[0] === '-') { + line.addClass("removed"); + localLineNo.text(localLine++); + } else { + line.addClass("unchanged"); + localLineNo.text(localLine++); + remoteLineNo.text(remoteLine++); + } + } + } + }, + close: function() { + diffVisible = false; + + }, + show: function() { + + } + } + RED.tray.show(trayOptions); + + + } + function parseUnifiedDiff(diff) { + var lines = diff.split("\n"); + var hunks = []; + var inHunk = false; + var currentHunk; + var hunkHeader = /^@@ -((\d+)(,(\d+))?) \+((\d+)(,(\d+))?) @@ ?(.*)$/; + var comment = /^\\/; + var localChange = /^-/; + var remoteChange = /^\+/; + + for (var i=0;i').appendTo(container); var bg = $('
').appendTo(row); - $('').appendTo(bg); + $('') + .appendTo(bg) + .click(function(evt) { + evt.preventDefault(); + var activeProject = RED.projects.getActiveProject(); + utils.sendRequest({ + url: "projects/"+activeProject.name+"/diff/"+(unstaged?"tree":"index")+"/"+encodeURIComponent(entry.file), + type: "GET", + responses: { + 0: function(error) { + console.log(error); + // done(error,null); + }, + 200: function(data) { + RED.diff.showUnifiedDiff(data.diff,(unstaged?"Unstaged":"Staged")+" changes : "+entry.file); + // console.log(data.diff); + }, + 400: { + 'unexpected_error': function(error) { + console.log(error); + // done(error,null); + } + }, + } + }) + + }) $('') .appendTo(bg) .click(function(evt) { diff --git a/editor/sass/diff.scss b/editor/sass/diff.scss index 78f5e9174..388b8b7b3 100644 --- a/editor/sass/diff.scss +++ b/editor/sass/diff.scss @@ -561,18 +561,24 @@ vertical-align: top; word-wrap: break-word; } - td:nth-child(odd) { + td.lineno { text-align: right; color: #999; background: #fafafa; padding: 1px 5px; } - td:nth-child(3) { + td.lineno:nth-child(3) { border-left: 1px solid $secondary-border-color; } - td:nth-child(even) { + td.linetext { white-space: pre-wrap; padding: 1px 5px; + span.prefix { + width: 30px; + display: inline-block; + text-align: center; + color: #999; + } } td.blank { background: #f6f6f6; @@ -583,21 +589,28 @@ td.removed { background: #fadddd; } + td.unchanged { + color: #999; + } tr.unchanged { background: #fefefe; } tr.start-block { - border-top: 1px solid #f3f3f3; + border-top: 1px solid #f0f0f0; } tr.end-block { - border-bottom: 1px solid #f3f3f3; + border-bottom: 1px solid #f0f0f0; } - tr.node-text-diff-expand td { + tr.node-text-diff-header td { text-align: left; color: #999; background: #ffd; + height: 30px; + vertical-align: middle; + } + tr.node-text-diff-expand td { + cursor: pointer; &:hover { - cursor: pointer; background: #ffc; } } diff --git a/red/api/editor/projects/index.js b/red/api/editor/projects/index.js index 8792fe682..474ee39bd 100644 --- a/red/api/editor/projects/index.js +++ b/red/api/editor/projects/index.js @@ -188,6 +188,21 @@ module.exports = { }) }); + app.get(/([^\/]+)\/diff\/([^\/]+)\/(.+)$/, function(req,res) { + var projectName = req.params[0]; + var type = req.params[1]; + var file = req.params[2]; + runtime.storage.projects.getFileDiff(projectName,file,type).then(function(data) { + res.json({ + diff: data + }) + }) + .catch(function(err) { + console.log(err.stack); + res.status(400).json({error:"unexpected_error", message:err.toString()}); + }) + }); + app.get(new RegExp("/([^\/]+)\/files\/(.*)"), function(req,res) { // Get project file }); diff --git a/red/runtime/storage/localfilesystem/projects/git/index.js b/red/runtime/storage/localfilesystem/projects/git/index.js index ce8a663dc..00aecf1f7 100644 --- a/red/runtime/storage/localfilesystem/projects/git/index.js +++ b/red/runtime/storage/localfilesystem/projects/git/index.js @@ -209,5 +209,15 @@ module.exports = { commit: function(cwd, message) { var args = ["commit","-m",message]; return runCommand(gitCommand,args,cwd); + }, + getFileDiff(cwd,file,type) { + var args = ["diff"]; + if (type === "tree") { + // nothing else to do + } else if (type === "index") { + args.push("--cached"); + } + args.push(file); + return runCommand(gitCommand,args,cwd); } } diff --git a/red/runtime/storage/localfilesystem/projects/index.js b/red/runtime/storage/localfilesystem/projects/index.js index be09ab891..096f2d5b9 100644 --- a/red/runtime/storage/localfilesystem/projects/index.js +++ b/red/runtime/storage/localfilesystem/projects/index.js @@ -351,6 +351,10 @@ function commit(project,options) { var projectPath = fspath.join(projectsDir,project); return gitTools.commit(projectPath,options.message); } +function getFileDiff(project,file,type) { + var projectPath = fspath.join(projectsDir,project); + return gitTools.getFileDiff(projectPath,file,type); +} function getFile(project,path) { } @@ -507,6 +511,7 @@ module.exports = { stageFile: stageFile, unstageFile: unstageFile, commit: commit, + getFileDiff: getFileDiff, getFlows: getFlows, saveFlows: saveFlows,