Created
July 28, 2022 01:57
-
-
Save stevemk14ebr/41a95bd1e47f9efd520ce30b0fb2cfc5 to your computer and use it in GitHub Desktop.
Explain git .patch https://github.com/megatops/PatchViewer/blob/master/PatchViewer.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | |
<html xmlns="http://www.w3.org/1999/xhtml"> | |
<head> | |
<meta content="text/html; charset=UTF-8" http-equiv="content-type" /> | |
<title>Patch Viewer</title> | |
<style type="text/css"> | |
body, h1, h2, h3, p { | |
font-family: sans-serif; | |
} | |
pre { | |
white-space:pre-wrap; | |
word-break: break-all; | |
word-wrap: break-word; | |
padding: 0; | |
margin: 0; | |
} | |
td { | |
padding: 0; | |
margin: 0; | |
} | |
textarea { | |
margin: 0; | |
padding: 0; | |
width: 100%; | |
-webkit-box-sizing: border-box; | |
-moz-box-sizing: border-box; | |
box-sizing: border-box; | |
} | |
.result_table { | |
padding: 0; | |
margin: 0; | |
border: 0.1em; | |
border-spacing: 0; | |
border-left-style: solid; | |
border-right-style: none; | |
border-top-style: none; | |
border-bottom-style: solid; | |
border-color: #BFBFBF; | |
color: black; | |
width: 100%; | |
} | |
.code_row { | |
width: 100%; | |
} | |
.linenum_cell { | |
width: 0%; | |
border-right-style: solid; | |
border-right-width: 0.1em; | |
border-color: #F0F0F0; | |
background-color: #F7F7F7; | |
color: #999999; | |
text-align: right; | |
padding-left: 0.2em; | |
padding-right: 0.2em; | |
user-select: none; | |
} | |
.linenum_text { | |
white-space: nowrap; | |
word-break: normal; | |
word-wrap: normal; | |
} | |
.diff_basic { | |
width: 50%; | |
border-right-style: solid; | |
border-right-width: 0.1em; | |
border-color: #BFBFBF; | |
} | |
.diff_context { | |
background-color: white; | |
color: #4D4D4D; | |
} | |
.diff_add { | |
background-color: #C0FFC0; | |
} | |
.diff_mod { | |
background-color: #FFFFB0; | |
} | |
.diff_del { | |
background-color: #FFD0D0; | |
color: #4D4D4D; | |
/* text-decoration: line-through; */ | |
} | |
.diff_pad { | |
background-color: #F0F0F0; | |
} | |
.diff_info { | |
padding-top: 0.1em; | |
padding-bottom: 0.1em; | |
padding-left: 0.4em; | |
padding-right: 0.4em; | |
} | |
.diff_split { | |
background-color: #EEEEEE; | |
color: #4D4D4D; | |
text-align: center; | |
border-top-style: solid; | |
border-top-width: 0.1em; | |
border-bottom-style: solid; | |
border-bottom-width: 0.1em; | |
} | |
.diff_sec_title { | |
width: 100%; | |
background-color: #DDDDCC; | |
color: #4D4D4D; | |
font-weight: bold; | |
border-top-style: solid; | |
border-top-width: 0.1em; | |
} | |
.toolbar { | |
background-color: #EEEEEE; | |
padding: 0.6em; | |
border-radius: 0.6em; | |
} | |
.nav_filename { | |
font-weight: bold; | |
font-size: large; | |
} | |
.nav_filename_bar { | |
padding-top: 0.5em; | |
padding-bottom: 0.5em; | |
} | |
.nav_link { | |
text-decoration: none; | |
color: black; | |
font-family: monospace; | |
padding-left: 0.3em; | |
padding-right: 0.3em; | |
} | |
.nav_link_bar { | |
background: #EEEEEE; | |
border-radius: 0.4em; | |
border-style: solid; | |
border-width: 0.1em; | |
border-color: #BFBFBF; | |
} | |
.nav_filelist { | |
font-family: monospace; | |
} | |
.nav_filelist_bar { | |
padding-top: 0.5em; | |
} | |
</style> | |
<script type="text/javascript" language="JavaScript"> | |
function diffRender(diff, node) { | |
// Common rendering engine STM states | |
var LINE_CONTEXT = 0; // unmodified context block, should copy to both sideA & B | |
var LINE_ADD = 1; // + block, sideB only | |
var LINE_DEL = 2; // - block, sideA only | |
var LINE_MOD = 3; // ! block | |
var LINE_SPLIT = 4; // section split, should be start line number | |
var LINE_SEC_TITLE = 5; // section title, sideA only | |
// Line buffers to hold the file parse result | |
var sideA = new Array(); | |
var sideB = new Array(); | |
// Add Navigation bar into DOM node. | |
function addNav(node, prefix, name) { | |
function newNavLink(href, inner, name) { | |
var link = document.createElement("a"); | |
link.setAttribute("href", href); | |
link.innerHTML = inner; | |
link.setAttribute("class", "nav_link"); | |
if (name != null) { | |
link.setAttribute("name", name); | |
} | |
return (link); | |
} | |
var fileNames = node.getElementsByClassName("nav_filename"); | |
if (fileNames.length <= 1) { | |
return; | |
} | |
// create file navigation bar | |
var defaultItem = document.createElement("option"); | |
defaultItem.setAttribute("value", "#" + prefix + "TOP"); | |
defaultItem.setAttribute("selected", "selected"); | |
defaultItem.appendChild(document.createTextNode("< Jump to ... >")); | |
var title = document.createElement("span"); | |
title.innerHTML = "<a name=" + prefix + "TOP></a><b>File List: </b>"; | |
var list = document.createElement("select"); | |
list.setAttribute("onchange", "location.href = this.options[this.selectedIndex].value;"); | |
list.setAttribute("class", "nav_filelist"); | |
list.appendChild(defaultItem); | |
var bar = document.createElement("div"); | |
bar.setAttribute("class", "nav_filelist_bar"); | |
bar.appendChild(list); | |
bar.insertBefore(title, list); | |
for (var i = fileNames.length - 1; i >= 0; i--) { | |
var fileName = fileNames[i]; | |
var fileNum = i + 1; | |
// Add file name into select list | |
var item = document.createElement("option"); | |
item.setAttribute("value", "#" + prefix + fileNum); | |
item.appendChild(document.createTextNode(fileName.textContent)); | |
list.insertBefore(item, list.firstChild); | |
// Add Prev/Next/Tops links before each title, set anchor on TOPS link | |
var smallbar = document.createElement("span"); | |
smallbar.setAttribute("class", "nav_link_bar"); | |
smallbar.appendChild(newNavLink("#" + prefix + (fileNum - 1), "«", null)); | |
smallbar.appendChild(newNavLink("#" + prefix + (fileNum + 1), "»", null)); | |
smallbar.appendChild(newNavLink("#" + prefix + "TOP", "⇑", prefix + fileNum)); | |
// insert the small nav bar before the file name, and add a space between them | |
fileName.parentNode.insertBefore(smallbar, fileName); | |
fileName.insertBefore(document.createTextNode(" "), fileName.firstChild); | |
} | |
// Insert the navigation bar before the first item, and place the default item to first | |
list.removeChild(defaultItem); | |
list.insertBefore(defaultItem, list.firstChild); | |
node.insertBefore(bar, node.firstChild); | |
} // addNav | |
// Render a file buffer | |
function renderFile(fileName, node) { | |
var sideALn; | |
var sideBLn; | |
var sect_title = null; | |
// insert file name | |
function insertFilename(node, fileName) { | |
var title = document.createElement("span"); | |
title.setAttribute("class", "nav_filename"); | |
title.appendChild(document.createTextNode((fileName == "") ? "Unknown" : fileName)); | |
var bar = document.createElement("div"); | |
bar.setAttribute("class", "nav_filename_bar"); | |
bar.appendChild(title); | |
node.appendChild(bar); | |
} | |
// rendering STM state handler | |
function processState(tb, parseState) { | |
// render a row | |
function insertRow(tb, codeA, codeB, type) { | |
// create a line number table cell | |
function newLineNumCell(count, type) { | |
var td = document.createElement("td"); | |
var pre = document.createElement("pre"); | |
td.setAttribute("class", "linenum_cell"); | |
pre.setAttribute("class", "linenum_text"); | |
pre.appendChild(document.createTextNode(count)); | |
td.appendChild(pre); | |
return (td); | |
} | |
// create a table cell for code | |
function newCodeCell(isSideB, text, type) { | |
var td = document.createElement("td"); | |
var pre = document.createElement("pre"); | |
switch (type) { | |
case LINE_CONTEXT: | |
td.setAttribute("class", "diff_basic diff_context"); | |
break; | |
case LINE_SPLIT: | |
td.setAttribute("class", "diff_basic diff_info diff_split"); | |
td.setAttribute("colspan", "2"); | |
break; | |
case LINE_SEC_TITLE: | |
td.setAttribute("class", "diff_basic diff_info diff_sec_title"); | |
td.setAttribute("colspan", "4"); | |
text = "Section: " + text; | |
break; | |
case LINE_ADD: | |
if (isSideB) { | |
td.setAttribute("class", "diff_basic diff_add"); | |
} else { | |
td.setAttribute("class", "diff_basic diff_del"); | |
} | |
break; | |
case LINE_DEL: | |
td.setAttribute("class", "diff_basic diff_pad"); | |
td.setAttribute("colspan", "2"); | |
break; | |
case LINE_MOD: | |
if (text == null) { | |
td.setAttribute("class", "diff_basic diff_pad"); | |
td.setAttribute("colspan", "2"); | |
} else { | |
td.setAttribute("class", "diff_basic diff_mod"); | |
} | |
break; | |
default: | |
} | |
if (text == null) { | |
text = ""; | |
} | |
pre.appendChild(document.createTextNode(text)); | |
td.appendChild(pre); | |
return (td); | |
} // newCodeCell() | |
// check if we need to create line number cells in this side | |
function needLineNum(text, type) { | |
if ((type == LINE_SPLIT) || (type == LINE_SEC_TITLE)) { | |
return (false); | |
} | |
return (text != null); | |
} | |
// skip the dummy end mark | |
if ((type == LINE_SPLIT) && (codeA == null) && (codeB == null)) { | |
return; | |
} | |
var tr = document.createElement("tr"); | |
var typeA = type, typeB = type; | |
switch (type) { | |
case LINE_ADD: | |
typeA = LINE_DEL; | |
break; | |
case LINE_DEL: | |
typeA = LINE_ADD; | |
break; | |
default: | |
} | |
tr.setAttribute("class", "code_row"); | |
if (needLineNum(codeA, type)) { | |
tr.appendChild(newLineNumCell(sideALn, typeA)); | |
sideALn++; | |
} | |
tr.appendChild(newCodeCell(false, codeA, typeA)); | |
if (type != LINE_SEC_TITLE) { | |
if (needLineNum(codeB, type)) { | |
tr.appendChild(newLineNumCell(sideBLn, typeA)); | |
sideBLn++; | |
} | |
tr.appendChild(newCodeCell(true, codeB, typeB)); | |
} | |
tb.appendChild(tr); | |
} // insertRow() | |
var lineA = sideA[0]; | |
var lineB = sideB[0]; | |
// process current work first | |
switch (parseState) { | |
// Just sync between diff segments | |
case LINE_SPLIT: | |
// print sec title if we have one | |
var hasTitle = (sect_title != null); | |
if (hasTitle) { | |
insertRow(tb, sect_title, null, LINE_SEC_TITLE); | |
} | |
sect_title = null; | |
// Update the line number from the split text | |
var lnA = parseInt(lineA.text); | |
var lnB = parseInt(lineB.text); | |
// check if we can convert line number to skipped line | |
var skipped = lnA - sideALn; | |
if ((lnA > sideALn) && (skipped == (lnB - sideBLn))) { | |
var split_text = skipped + " unchanged line" | |
+ ((skipped == 1) ? "" : "s") | |
+ " skipped..."; | |
insertRow(tb, split_text, split_text, parseState); | |
} else { | |
if ((lnA == 0) || (lnA == 1) || (lnB == 0) || (lnB == 1)) { | |
// Don't print the split | |
if (!hasTitle) { | |
tb.setAttribute("style", "border-top-style: solid"); | |
} | |
} else { | |
insertRow(tb, lineA.text, lineB.text, parseState); | |
} | |
} | |
sideALn = lnA; | |
sideBLn = lnB; | |
sideA.shift(); | |
sideB.shift(); | |
break; | |
// section title (diffs attached in DDTS have such title) | |
case LINE_SEC_TITLE: | |
// cache the section title, will print it after reached next split | |
sect_title = lineA.text; | |
sideA.shift(); | |
break; | |
// we are in the context section of diff | |
case LINE_CONTEXT: | |
if (lineB.state != LINE_CONTEXT) { | |
// only left side has the context (del only) | |
insertRow(tb, lineA.text, lineA.text, parseState); | |
sideA.shift(); | |
break; | |
} | |
if (lineA.state != LINE_CONTEXT) { | |
// only right side has the context (add only) | |
insertRow(tb, lineB.text, lineB.text, parseState); | |
sideB.shift(); | |
break; | |
} | |
// both have context (modify) | |
// in normal the context should be the same, but we'd better | |
// to check that | |
if (lineA.text == lineB.text) { | |
insertRow(tb, lineA.text, lineB.text, parseState); | |
sideA.shift(); | |
sideB.shift(); | |
} else { | |
// not quite sure what happened, but just display context | |
// from left first | |
insertRow(tb, lineA.text, lineA.text, parseState); | |
sideA.shift(); | |
} | |
break; | |
// we are in the add section of diff, it could only be in the right side | |
case LINE_ADD: | |
insertRow(tb, null, lineB.text, parseState); | |
sideB.shift(); | |
break; | |
// we are in the del section of diff, it could only be in the left side | |
case LINE_DEL: | |
insertRow(tb, lineA.text, null, parseState); | |
sideA.shift(); | |
break; | |
// we are in the modified section of diff | |
case LINE_MOD: | |
var modA = null, modB = null; | |
if (lineA.state == LINE_MOD) { | |
modA = lineA.text; | |
sideA.shift(); | |
} | |
if (lineB.state == LINE_MOD) { | |
modB = lineB.text; | |
sideB.shift(); | |
} | |
insertRow(tb, modA, modB, parseState); | |
break; | |
default: | |
} | |
} // processState() | |
// detect the next FSM state for rendering engine | |
function detectNextState() { | |
// now let's decide next state, make sure we have end-marks in both sides | |
if (sideA.length == 0) { | |
pushLineTo(sideA, null, LINE_SPLIT); | |
} | |
if (sideB.length == 0) { | |
pushLineTo(sideB, null, LINE_SPLIT); | |
} | |
var lineA = sideA[0]; | |
var lineB = sideB[0]; | |
// left reached the end | |
if (lineA.state == LINE_SPLIT) { | |
return (lineB.state); | |
} | |
// right reached the end | |
if (lineB.state == LINE_SPLIT) { | |
return (lineA.state); | |
} | |
// the priority is : | |
// SectionTitle > Del > Add > Modify > Context | |
if ((lineA.state == LINE_SEC_TITLE) | |
|| (lineA.state == LINE_DEL)) { | |
return (lineA.state); | |
} | |
if (lineB.state == LINE_ADD) { | |
return (lineB.state); | |
} | |
if ((lineA.state == LINE_MOD) || (lineB.state == LINE_MOD)) { | |
return (LINE_MOD); | |
} | |
return (LINE_CONTEXT); | |
} // detectNextState() | |
if (bufferEmpty()) { | |
return; | |
} | |
sideALn = 1; | |
sideBLn = 1; | |
var tb = document.createElement("table"); | |
while ((sideA.length > 0) || (sideB.length > 0)) { | |
processState(tb, detectNextState()); | |
} | |
tb.setAttribute("class", "result_table"); | |
insertFilename(node, fileName); | |
node.appendChild(tb); | |
} // renderFile() | |
// Push a line to file buffer | |
function pushLineTo(side, lineText, lineState) { | |
var lineObj = new Object(); | |
lineObj.text = lineText; | |
lineObj.state = lineState; | |
side.push(lineObj); | |
} | |
// Check if file buffer is empty | |
function bufferEmpty() { | |
return ((sideA.length == 0) && (sideB.length == 0)); | |
} | |
// Parse the diff generated by Cisco acme/cctools | |
// Supports common context diff format as well | |
function contextDiffParser(diff, node) { | |
// Patch file parser STM states | |
var ST_IN_META = 100; // meta (Index: xxx, ***, etc) | |
var ST_IN_ORG = 200; // orignal file (sideA) | |
var ST_IN_NEW = 300; // new file (sideB) | |
var state = ST_IN_META; | |
// push line to the correct side by current parser FSM state | |
function pushLine(lineText, lineState) { | |
if (lineState == LINE_SEC_TITLE) { | |
pushLineTo(sideA, lineText, lineState); | |
return; | |
} | |
switch (state) { | |
case ST_IN_ORG: | |
pushLineTo(sideA, lineText, lineState); | |
break; | |
case ST_IN_NEW: | |
pushLineTo(sideB, lineText, lineState); | |
break; | |
default: | |
} | |
} | |
var lines = diff.split("\n"); | |
var fileName = ""; | |
var fileNameSrc = ""; // Where the file name from | |
for (var i = 0; i < lines.length; i++) { | |
var line = lines[i]; | |
var result; | |
// - xxxxx (removed lines) | |
if (((result = /^- ([^\n]*)/.exec(line)) != null) | |
|| ((result = /^-($)/.exec(line)) != null)) { | |
pushLine(result[1], LINE_DEL); | |
continue; | |
} | |
// + xxxxx (added lines) | |
if (((result = /^\+ ([^\n]*)/.exec(line)) != null) | |
|| ((result = /^\+($)/.exec(line)) != null)) { | |
pushLine(result[1], LINE_ADD); | |
continue; | |
} | |
// ! xxxxx (modified lines) | |
if (((result = /^! ([^\n]*)/.exec(line)) != null) | |
|| ((result = /^!($)/.exec(line)) != null)) { | |
pushLine(result[1], LINE_MOD); | |
continue; | |
} | |
// *** 5,20 **** (sideA line number) | |
if ((result = /^\*{3} ([0-9]+)[0-9,]* \*{3}/.exec(line)) != null) { | |
state = ST_IN_ORG; | |
pushLine(result[1], LINE_SPLIT); | |
continue; | |
} | |
// --- 11,20 ---- (sideB line number) | |
if ((result = /^-{3} ([0-9]+)[0-9,]* -{3}/.exec(line)) != null) { | |
state = ST_IN_NEW; | |
pushLine(result[1], LINE_SPLIT); | |
continue; | |
} | |
// For indexed diff: | |
// Index: filename | |
// | |
// For unified diff filename: | |
// *** /path/to/original | |
// --- /path/to/new | |
if (((result = /^Index: ([^\n]*)/.exec(line)) != null) | |
|| ((result = /^\*{3} ([^\n]*)/.exec(line)) != null) | |
|| ((result = /^\-{3} ([^\n]*)/.exec(line)) != null)) { | |
if (!bufferEmpty()) { | |
// this should be the file split | |
renderFile(fileName, node); | |
fileName = ""; | |
fileNameSrc = ""; | |
} | |
// if we have not get the file name yet, or the previous file name | |
// was parsed from the same source (index/left/right), and current | |
// file name is valid, use it. | |
if (((fileName == "") || (fileNameSrc == line.charAt(0))) | |
&& (result[1] != "") | |
&& (result[1] != "/dev/null")) { | |
fileName = result[1]; | |
fileNameSrc = line.charAt(0); | |
} | |
state = ST_IN_META; | |
continue; | |
} | |
// context lines | |
if (((result = /^ ([^\n]*)/.exec(line)) != null) | |
|| ((result = /^ ($)/.exec(line)) != null)) { | |
pushLine(result[1], LINE_CONTEXT); | |
continue; | |
} | |
// *************** (optional section title) | |
if ((result = /^\*{15} ([^\n]*)/.exec(line)) != null) { | |
pushLine(result[1], LINE_SEC_TITLE); | |
continue; | |
} | |
state = ST_IN_META; | |
} | |
// for last file | |
renderFile(fileName, node); | |
} // contextDiffParser() | |
// Parse the diff generated by git | |
// Supports common unified diff format as well | |
function unifiedDiffParser(diff, node) { | |
// Patch file parser STM states | |
var ST_IN_META = 100; // meta (Index: xxx, +++, ---, etc) | |
var ST_IN_DIFF = 200; // valid diff (incl. @@, +, -, etc) | |
// Substate for diff part | |
var ST_IN_DIFF_CTX = 220; // context lines | |
var ST_IN_DIFF_ADD = 230; // +xxxxx | |
var ST_IN_DIFF_DEL = 240; // -xxxxx | |
var ST_IN_DIFF_MOD = 250; // modified block (- block followed by a + block) | |
var state = ST_IN_META; | |
var subState = 0; | |
// Push buffered - block to sideA with final block property | |
function pushDels(endDel, isModify) { | |
if (lastDel == -1) { | |
return; | |
} | |
for (var i = lastDel; i < endDel; i++) { | |
if (lines[i].substr(0, 1) == "-") { | |
pushLineTo(sideA, lines[i].substr(1), (isModify ? LINE_MOD : LINE_DEL)); | |
} | |
} | |
lastDel = -1; | |
} | |
// Set the substate of parser STM. Will push buffered del block to file buffer | |
// when needed, or just update the del block start line. | |
function setSubState(newSubState, currLine) { | |
if (subState == newSubState) { | |
return; | |
} | |
if (subState == ST_IN_DIFF_DEL) { | |
pushDels(currLine, (newSubState == ST_IN_DIFF_MOD)); | |
} else if ((state == ST_IN_DIFF) && (newSubState == ST_IN_DIFF_DEL)) { | |
lastDel = i; | |
} | |
subState = newSubState; | |
} | |
var lines = diff.split("\n"); | |
var fileName = ""; | |
var fileNameSrc = ""; // Where the file name from | |
var lastDel = -1; | |
for (var i = 0; i < lines.length; i++) { | |
var line = lines[i]; | |
var result; | |
// For indexed diff: | |
// Index: filename | |
// | |
// For git diff: | |
// diff --git a/filepath b/filepath | |
// | |
// For unified diff filename: | |
// --- /path/to/original ''timestamp'' | |
// +++ /path/to/new ''timestamp'' | |
if (((result = /^Index: ([^\n]*)/.exec(line)) != null) | |
|| ((result = /^diff --git .*? b\/([^\n]*)/.exec(line)) != null) | |
|| ((state == ST_IN_META) // avoid conflict with the real +/- lines | |
&& (((result = /^\-{3} ([^\n]*)/.exec(line)) != null) | |
|| ((result = /^\+{3} ([^\n]*)/.exec(line)) != null)))) { | |
setSubState(0, i); | |
if (!bufferEmpty()) { | |
// this should be the file split | |
renderFile(fileName, node); | |
fileName = ""; | |
fileNameSrc = ""; | |
} | |
// if we have not get the file name yet, or the previous file name | |
// was parsed from the same source (index/left/right), and current | |
// file name is valid, use it. | |
if (((fileName == "") || (fileNameSrc == line.charAt(0))) | |
&& (result[1] != "") | |
&& (result[1] != "/dev/null")) { | |
fileName = result[1]; | |
fileNameSrc = line.charAt(0); | |
} | |
state = ST_IN_META; | |
continue; | |
} | |
// -xxxxxx (removed lines) | |
if (((result = /^-([^\n]*)/.exec(line)) != null) | |
&& (state == ST_IN_DIFF)) { | |
// the unified diff only use -/+ but no modified sign (!), so | |
// we have to see if there is + block next to current - block. | |
// If so, it should be render as modified block. We have to | |
// cache the - lines until we know the final block property. | |
setSubState(ST_IN_DIFF_DEL, i); | |
continue; | |
} | |
// +xxxxx (added lines) | |
if (((result = /^\+([^\n]*)/.exec(line)) != null) | |
&& (state == ST_IN_DIFF)) { | |
// If current + block just next to previous - block, both should be | |
// modified blocks. Or it just a normal + block. | |
var isModify = ((subState == ST_IN_DIFF_DEL) | |
|| (subState == ST_IN_DIFF_MOD)); | |
setSubState((isModify ? ST_IN_DIFF_MOD : ST_IN_DIFF_ADD), i); | |
pushLineTo(sideB, result[1], (isModify ? LINE_MOD : LINE_ADD)); | |
continue; | |
} | |
// \ No newline at end of file | |
if (((result = /^\\ ([^\n]*)/.exec(line)) != null) | |
&& (state == ST_IN_DIFF)) { | |
continue; | |
} | |
// @@ -184,3 +184,41 @@ (Optional section title) | |
if ((result = /^@@ \-([0-9]+)[0-9,]* \+([0-9]+)[0-9,]* @@ *([^\n]*)/.exec(line)) != null) { | |
setSubState(0, i); | |
state = ST_IN_DIFF; | |
// parse section title | |
if (result[3] != "") { | |
pushLineTo(sideA, result[3], LINE_SEC_TITLE); | |
} | |
// parse line number | |
pushLineTo(sideA, result[1], LINE_SPLIT); | |
pushLineTo(sideB, result[2], LINE_SPLIT); | |
continue; | |
} | |
// context lines | |
if (((result = /^ ([^\n]*)/.exec(line)) != null) | |
&& (state == ST_IN_DIFF)) { | |
setSubState(ST_IN_DIFF_CTX, i); | |
pushLineTo(sideA, result[1], LINE_CONTEXT); | |
pushLineTo(sideB, result[1], LINE_CONTEXT); | |
continue; | |
} | |
setSubState(0, i); | |
state = ST_IN_META; | |
} | |
// for last file | |
renderFile(fileName, node); | |
} // unifiedDiffParser() | |
// normalize the line endings | |
diff = diff.replace(/\r\n?/g, "\n"); | |
// expand tab to 8 spaces | |
// diff = diff.replace(/\t/g, " "); | |
node.innerHTML = ""; | |
if (diff.search(/(^|\n)@@ \-[0-9,]+ \+[0-9,]+ @@/) != -1) { | |
unifiedDiffParser(diff, node); | |
} else { | |
contextDiffParser(diff, node); | |
} | |
// Generate navigation bar and file list | |
addNav(node, "navFile"); | |
} // diffRender() | |
function loadDiff(node) { | |
if (!window.FileReader) { | |
alert("This feature is not supported in this browser. \n" | |
+ "Run in Chrome/Firefox/Opera is highly recommended."); | |
return; | |
} | |
var files = document.getElementById("diff_file").files; | |
if (files.length == 0) { | |
alert("Please select a valid patch file."); | |
return; | |
} | |
var file = files[0]; | |
var reader = new FileReader(); | |
reader.readAsText(file); | |
reader.onload = function(e) { | |
diffRender(this.result, node); | |
} | |
} | |
</script> | |
</head> | |
<body onload = "form_diff.reset()"> | |
<h2>Side-by-Side Patch Viewer v0.5</h2> | |
<form id = "form_diff"> | |
<div class = "toolbar"> | |
Paste your diff snippet below then | |
<button | |
type = "button" | |
onclick = "diffRender(document.getElementById('diffText').value, document.getElementById('diffResult'))"> | |
START | |
</button> | |
; or load from a file: | |
<input | |
id = "diff_file" type = "file" autocomplete = "off" | |
onchange = "loadDiff(document.getElementById('diffResult'))"/> | |
<div style = "padding-top: 0.3em"> | |
<textarea rows = "8" id = "diffText"></textarea> | |
</div> | |
</div> | |
</form> | |
<div id = "diffResult" class = "context"></div> | |
<div> | |
<ul> | |
<li>Run in Chrome/Firefox/Opera is highly recommended. Internet Explorer might not support all the features of this tool.</li> | |
<li>Use the "Save As..." to save the side-by-side view of current patch.</li> | |
<li>Parsing large file might freeze your browser for minutes.</li> | |
<li>For any issues please contact Ding Zhaojie (<a href = "mailto:[email protected]">[email protected]</a>)</li> | |
</ul> | |
</div> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment