// If we run from a Safari instance, we don't
// have a Controller object. Instead, we fake it by
// using the console
if (typeof Controller == 'undefined') {
Controller = console;
Controller.log_ = console.log;
}
var highlightDiff = function(diff, element, callbacks) {
if (!diff || diff == "")
return;
if (!callbacks)
callbacks = {};
var start = new Date().getTime();
element.className = "diff"
var content = diff.escapeHTML().replace(/\t/g, " ");;
var file_index = 0;
var startname = "";
var endname = "";
var line1 = "";
var line2 = "";
var diffContent = "";
var finalContent = "";
var lines = content.split('\n');
var binary = false;
var mode_change = false;
var old_mode = "";
var new_mode = "";
var hunk_start_line_1 = -1;
var hunk_start_line_2 = -1;
var header = false;
var finishContent = function()
{
if (!file_index)
{
file_index++;
return;
}
if (callbacks["newfile"])
callbacks["newfile"](startname, endname, "file_index_" + (file_index - 1), mode_change, old_mode, new_mode);
var title = startname;
var binaryname = endname;
if (endname == "/dev/null") {
binaryname = startname;
title = startname;
}
else if (startname == "/dev/null")
title = endname;
else if (startname != endname)
title = startname + " renamed to " + endname;
if (binary && endname == "/dev/null") { // in cases of a deleted binary file, there is no diff/file to display
line1 = "";
line2 = "";
diffContent = "";
file_index++;
startname = "";
endname = "";
return; // so printing the filename in the file-list is enough
}
if (diffContent != "" || binary) {
finalContent += '
' +
'';
}
if (!binary && (diffContent != "")) {
finalContent += '
' +
'
' + line1 + "
" +
'
' + line2 + "
" +
'
' + diffContent + "
" +
'
';
}
else {
if (binary) {
if (callbacks["binaryFile"])
finalContent += callbacks["binaryFile"](binaryname);
else
finalContent += "
Binary file differs
";
}
}
if (diffContent != "" || binary)
finalContent += '
';
line1 = "";
line2 = "";
diffContent = "";
file_index++;
startname = "";
endname = "";
}
for (var lineno = 0, lindex = 0; lineno < lines.length; lineno++) {
var l = lines[lineno];
var firstChar = l.charAt(0);
if (firstChar == "d" && l.charAt(1) == "i") { // "diff", i.e. new file, we have to reset everything
header = true; // diff always starts with a header
finishContent(); // Finish last file
binary = false;
mode_change = false;
if(match = l.match(/^diff --git (a\/)+(.*) (b\/)+(.*)$/)) { // there are cases when we need to capture filenames from
startname = match[2]; // the diff line, like with mode-changes.
endname = match[4]; // this can get overwritten later if there is a diff or if
} // the file is binary
continue;
}
if (header) {
if (firstChar == "n") {
if (l.match(/^new file mode .*$/))
startname = "/dev/null";
if (match = l.match(/^new mode (.*)$/)) {
mode_change = true;
new_mode = match[1];
}
continue;
}
if (firstChar == "o") {
if (match = l.match(/^old mode (.*)$/)) {
mode_change = true;
old_mode = match[1];
}
continue;
}
if (firstChar == "d") {
if (l.match(/^deleted file mode .*$/))
endname = "/dev/null";
continue;
}
if (firstChar == "-") {
if (match = l.match(/^--- (a\/)?(.*)$/))
startname = match[2];
continue;
}
if (firstChar == "+") {
if (match = l.match(/^\+\+\+ (b\/)?(.*)$/))
endname = match[2];
continue;
}
// If it is a complete rename, we don't know the name yet
// We can figure this out from the 'rename from.. rename to.. thing
if (firstChar == 'r')
{
if (match = l.match(/^rename (from|to) (.*)$/))
{
if (match[1] == "from")
startname = match[2];
else
endname = match[2];
}
continue;
}
if (firstChar == "B") // "Binary files .. and .. differ"
{
binary = true;
// We might not have a diff from the binary file if it's new.
// So, we use a regex to figure that out
if (match = l.match(/^Binary files (a\/)?(.*) and (b\/)?(.*) differ$/))
{
startname = match[2];
endname = match[4];
}
}
// Finish the header
if (firstChar == "@")
header = false;
else
continue;
}
sindex = "index=" + lindex.toString() + " ";
if (firstChar == "+") {
// Highlight trailing whitespace
if (m = l.match(/\s+$/))
l = l.replace(/\s+$/, "" + m + "");
line1 += "\n";
line2 += ++hunk_start_line_2 + "\n";
diffContent += "" + l + "
";
} else if (firstChar == "-") {
line1 += ++hunk_start_line_1 + "\n";
line2 += "\n";
diffContent += "" + l + "
";
} else if (firstChar == "@") {
if (header) {
header = false;
}
if (m = l.match(/@@ \-([0-9]+),?\d* \+(\d+),?\d* @@/))
{
hunk_start_line_1 = parseInt(m[1]) - 1;
hunk_start_line_2 = parseInt(m[2]) - 1;
}
line1 += "...\n";
line2 += "...\n";
diffContent += "" + l + "
";
} else if (firstChar == " ") {
line1 += ++hunk_start_line_1 + "\n";
line2 += ++hunk_start_line_2 + "\n";
diffContent += "" + l + "
";
}
lindex++;
}
finishContent();
// This takes about 7ms
element.innerHTML = finalContent;
// TODO: Replace this with a performance pref call
if (false)
Controller.log_("Total time:" + (new Date().getTime() - start));
}