diff --git a/diff2html.js b/diff2html.js
index c8e4344..8fd76db 100644
--- a/diff2html.js
+++ b/diff2html.js
@@ -4,6 +4,10 @@
* Author: rtfpessoa
* Date: Friday 29 August 2014
*
+ * Useful commands:
+ * git diff HEAD~1
+ * git diff HEAD~1 --word-diff-regex='[[:alnum:]]+|[^[:space:]]'
+ * git diff HEAD~1 --word-diff-regex=.
*/
(function($, window) {
@@ -18,13 +22,21 @@
DELETED: "delete"
};
- var BLOCK_HEADER_LINE = "..."
+ var BLOCK_HEADER_LINE = "...";
- function Diff2Html() {}
+ var wordDiffParser = WordDiffParser.getInstance();
- Diff2Html.prototype.generatePrettyDiff = function(diffInput) {
+ function Diff2Html() {}
+
+ Diff2Html.prototype.generatePrettyDiff = function(diffInput, wordDiffInput) {
var diffFiles = splitByFile(diffInput);
- var html = generateHtml(diffFiles);
+ var changedWords = wordDiffParser.generateChangedWords(wordDiffInput);
+
+ if (!changedWords) {
+ changedWords = {};
+ }
+
+ var html = generateHtml(diffFiles, changedWords);
return html;
};
@@ -147,47 +159,74 @@
return files;
};
- var generateHtml = function( diffFiles ) {
- return diffFiles.map(function( file ) {
+ var generateHtml = function(diffFiles, changedWords) {
+ return diffFiles.map(function(file, index) {
var fileHeader = file.oldName === file.newName ? file.newName : file.oldName + " -> " + file.newName
return "
" +
- " " +
- "
" +
- "
" +
- "
" +
- " " +
- generateFileHtml(file) +
- " " +
- "
" +
- "
" +
- "
" +
- "
";
+ " " +
+ " " +
+ "
" +
+ "
" +
+ " " +
+ generateFileHtml(file, changedWords[index]) +
+ " " +
+ "
" +
+ "
" +
+ "
" +
+ "";
});
};
- var generateFileHtml = function(file) {
+ var generateFileHtml = function(file, changedWords) {
return file.blocks.map(function(block) {
return block.lines.map(function(line) {
- var oldLine = line.oldNumber ? line.oldNumber : "",
- newLine = line.newNumber ? line.newNumber : "";
+ var oldLine = line.oldNumber ? line.oldNumber : "";
+ var newLine = line.newNumber ? line.newNumber : "";
+
+ var oldWords = [];
+ var newWords = [];
+
+ if (oldLine && oldLine !== BLOCK_HEADER_LINE &&
+ changedWords && changedWords.deletedWords && changedWords.deletedWords[oldLine]) {
+ oldWords = changedWords.deletedWords[oldLine];
+ }
+
+ if (newLine && newLine !== BLOCK_HEADER_LINE &&
+ changedWords && changedWords.addedWords && changedWords.addedWords[newLine]) {
+ newWords = changedWords.addedWords[newLine];
+ }
+
+ //var newLine = escape(line.content);
+ var newCodeLine = line.content;
+ newCodeLine = markWords(oldWords, newCodeLine, "del");
+ newCodeLine = markWords(newWords, newCodeLine, "ins");
return "" +
" | " + oldLine + " | " +
" " + newLine + " | " +
- " " + escape(line.content) + " | " +
+ " " + newCodeLine + " | " +
"
";
}).join("\n");
}).join("\n");
};
+ var markWords = function(words, line, clazz) {
+ var newLine = line;
+ words.forEach(function(word) {
+ newLine = newLine.replace(word, "<" + clazz + ">" + word + "" + clazz + ">");
+ });
+
+ return newLine;
+ };
+
var escape = function(str) {
return str
.replace(/&/g, "&")
diff --git a/style.css b/style.css
index 4298065..33e2eb3 100644
--- a/style.css
+++ b/style.css
@@ -150,8 +150,6 @@ td, th {
vertical-align: top;
white-space: pre;
overflow: visible;
- padding-top: 4px;
- padding-bottom: 4px;
}
.delete {
@@ -172,3 +170,19 @@ td, th {
color: rgba(0,0,0,0.3);
border-color: #d5e4f2;
}
+
+.code-line del {
+ display: inline-block;
+ margin-top: -1px;
+ text-decoration: none;
+ background-color: #ffb6ba;
+ font-weight: 700;
+}
+
+.code-line ins {
+ display: inline-block;
+ margin-top: -1px;
+ text-decoration: none;
+ background-color: #97f295;
+ font-weight: 700;
+}
diff --git a/template.html b/template.html
index 746cc33..dd5a384 100644
--- a/template.html
+++ b/template.html
@@ -13,6 +13,7 @@
+
diff --git a/word-diff-parser.js b/word-diff-parser.js
new file mode 100644
index 0000000..26938e2
--- /dev/null
+++ b/word-diff-parser.js
@@ -0,0 +1,136 @@
+/*
+ *
+ * Word Diff Parser (word-diff-parser.js)
+ * Author: rtfpessoa
+ * Date: Saturday 30 August 2014
+ *
+ */
+
+(function($, window) {
+ var ClassVariable;
+
+ ClassVariable = (function() {
+
+ function WordDiffParser() {}
+
+ WordDiffParser.prototype.generateChangedWords = function(wordDiffInput) {
+ return wordDiffInput ? parseChangedWords(wordDiffInput) : null;
+ };
+
+ var parseChangedWords = function(wordDiffInput) {
+ var files = [],
+ currentFile = null,
+ oldLine = null,
+ newLine = null;
+
+ wordDiffInput.split("\n").forEach(function(line) {
+ // Unmerged paths, and possibly other non-diffable files
+ // https://github.com/scottgonzalez/pretty-diff/issues/11
+ // Also, remove some useless lines
+ if (!line || line.charAt(0) === "*" ||
+ line.indexOf("new") === 0 ||
+ line.indexOf("index") === 0 ||
+ line.indexOf("---") === 0 ||
+ line.indexOf("+++") === 0) {
+ return;
+ }
+
+ if (line.indexOf("diff") === 0) {
+ /* File Diff Line */
+
+ /* add previous file(if exists) before start a new one */
+ if (currentFile &&
+ (currentFile.addedWords.length || currentFile.deletedWords.length)) {
+ files.push(currentFile);
+ currentFile = null;
+ }
+
+ /* create file structure */
+ currentFile = {};
+ currentFile.addedWords = [];
+ currentFile.deletedWords = [];
+
+ /* save file paths, before and after the diff */
+ var values = /^diff --git a\/(\S+) b\/(\S+).*$/.exec(line);
+ currentFile.oldName = values[1];
+ currentFile.newName = values[2];
+
+ } else if (line.indexOf("@@") === 0) {
+ /* Diff Block Header Line */
+
+ var values = /^(@@ -(\d+),(\d+) \+(\d+),(\d+) @@).*/.exec(line);
+
+ oldLine = values[2];
+ newLine = values[4];
+
+ } else {
+ /* Regular Diff Line */
+
+ var addedWords = [];
+ if (addedWords = line.match(/\{\+(.+?)\+\}/g)) {
+ addedWords = addedWords.map(function(word) {
+ return cleanWordMatch(word);
+ });
+ } else {
+ addedWords = [];
+ }
+
+ var deletedWords = [];
+ if (deletedWords = line.match(/\[-(.+?)-\]/g)) {
+ deletedWords = deletedWords.map(function(word) {
+ return cleanWordMatch(word);
+ });
+ } else {
+ deletedWords = [];
+ }
+
+ if (!addedWords.length && !deletedWords.length) {
+ oldLine++;
+ newLine++;
+ } else {
+ if (addedWords.length) {
+ currentFile.addedWords[newLine] = addedWords;
+ newLine++;
+ }
+
+ if (deletedWords.length) {
+ currentFile.deletedWords[oldLine] = deletedWords;
+ oldLine++;
+ }
+ }
+ }
+ });
+
+ /* add previous file(if exists) before start a new one */
+ if (currentFile &&
+ (currentFile.addedWords.length || currentFile.deletedWords.length)) {
+ files.push(currentFile);
+ currentFile = null;
+ }
+
+ return files;
+ };
+
+ var cleanWordMatch = function(str) {
+ return str.substr(2, str.length - 4);
+ };
+
+ /* singleton pattern */
+ var instance;
+ return {
+ getInstance: function() {
+ if (instance === undefined) {
+ instance = new WordDiffParser();
+ /* Hide the constructor so the returned objected can't be new'd */
+ instance.constructor = null;
+ }
+ return instance;
+ }
+ };
+
+ })();
+
+ window.WordDiffParser = ClassVariable;
+ return window.WordDiffParser;
+
+})(jQuery, window);