Show coloured diffs in blogs
A quick Google search for JavaScript code to format context-diffs as coloured side-by-side diffs didn't turn up anything obvious (admittedly I haven't the slightest clue where to look for this sort of stuff on the 'net).
So I went and quickly wrote my own formatting function which formats a given context diff and returns a table-formatted side-by-side diff:
function formatDiff(textContent) { "use strict"; function E(name, attrs) { var arg, elem = document.createElement(name), prop; for (prop in attrs) { elem.setAttribute(prop, attrs[prop]); } for (arg = 2; arg != arguments.length; ++arg) { elem.appendChild(arguments[arg]); } return elem; } var td = E.bind(undefined, "td"); var th = E.bind(undefined, "th", {}); var tr = E.bind(undefined, "tr", {}); var T = document.createTextNode.bind(document); var res = E("table", {"class": "diff"}); var sects = {"unchanged": [], "removed": [], "added": []}; var lines = textContent.split("\n"); lines.push(""); lines.forEach(function (l) { var leftAttrs = {}, rightAttrs = {}; var lineType = !l.length ? "eof" : "--- " === l.substr(0, 4) ? "oldfile" : "+++ " === l.substr(0, 4) ? "newfile" : "@@ " === l.substr(0, 3) ? "range" : "-" === l[0] ? "removed" : "+" === l[0] ? "added" : "unchanged"; /* * An "unchanged" section ends at a line that isn't "unchanged". */ if (sects["unchanged"].length && "unchanged" !== lineType) { res.appendChild(tr( td({}, T(sects["unchanged"].join("\n"))), td({}, T(sects["unchanged"].join("\n"))) )); sects["unchanged"].length = 0; } /* * An added/removed section ends * o at a line that isn't "added" if there are "added" lines, * o at a line that isn't "added" or "removed" if there are "removed" lines. */ if (sects["added"].length && "added" !== lineType || sects["removed"].length && "removed" !== lineType && "added" !== lineType) { if (sects["added"].length && sects["removed"].length) { leftAttrs["class"] = rightAttrs["class"] = "diff-changed"; } else if (sects["removed"].length) { leftAttrs["class"] = "diff-removed"; } else { rightAttrs["class"] = "diff-added"; } res.appendChild(tr( td(leftAttrs, T(sects["removed"].join("\n"))), td(rightAttrs, T(sects["added"].join("\n"))) )); sects["added"].length = sects["removed"].length = 0; } if ("oldfile" === lineType) { res.appendChild(tr(th(T(l.substring(4))))); } else if ("newfile" === lineType) { res.lastChild.appendChild(th(T(l.substring(4)))); } else if ("range" === lineType) { var ds = td( {"class": "diff-section", "colspan": 2}, T(l.split("@@").join(" ")) ); res.appendChild(tr(ds)); } else if ("eof" !== lineType) { sects[lineType].push(l.substring(1)); } }); return res; } // Clone the HTML node collection before modifying the DOM. var diffs = Array.prototype.slice.call(document.getElementsByClassName("diff")); diffs.forEach(function (diff) { diff.replaceChild(formatDiff(diff.firstChild.textContent), diff.firstChild); });The code at the bottom reformats any elements of class
diff
: see it in action!
Here's a small unit test:
--- file1
+++ file2
@@ -0,+1 @@ something
0
1
-2
+2
+3
-3
-4
+4
-5
6
+7
8
There are already various source code highlighters out there so arguably this posting could be made to look a lot nicer. :-)
Comments
Post a Comment