<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Varynth Diff Viewer</title>
<style>
:root {
--void: #07090b;
--panel: #10161c;
--line: #1d3a3a;
--teal: #2ec4b6;
--coral: #ff6b4a;
--mist: #c9d6d4;
--dim: #6f8582;
--ink: #e8f2ef;
--accent: #7E57C2;
--add-bg: #0d211d;
--add-ink: #9fe8df;
--del-bg: #26120c;
--del-ink: #ffb59e;
}
* { box-sizing: border-box; }
html, body { height: 100%; margin: 0; background: var(--void); color: var(--ink);
font-family: "IBM Plex Sans", "Segoe UI", sans-serif; }
header { display: flex; align-items: center; gap: 12px; padding: 10px 18px;
border-bottom: 1px solid var(--line); }
.mark { width: 22px; height: 22px; }
header b { font-weight: 600; letter-spacing: .08em; font-size: 13px; }
header span { color: var(--dim); font-size: 11px; }
.controls { padding: 12px 18px; display: flex; gap: 10px; align-items: stretch;
border-bottom: 1px solid var(--line); }
textarea { flex: 1; height: 96px; resize: vertical; background: #0a1014; color: var(--ink);
border: 1px solid var(--line); padding: 8px 10px;
font: 12px/1.5 "IBM Plex Mono", ui-monospace, monospace; }
textarea:focus { outline: 1px solid var(--accent); }
button.go { background: var(--accent); color: #fff; border: 0; padding: 0 20px;
font-weight: 650; letter-spacing: .04em; cursor: pointer; }
button.go:hover { filter: brightness(1.15); }
button.ghost { background: transparent; color: var(--dim); border: 1px solid var(--line);
padding: 0 14px; font-size: 11px; cursor: pointer; }
button.ghost:hover { color: var(--accent); border-color: var(--accent); }
.out { flex: 1; overflow: auto; min-height: 0; }
table { border-collapse: collapse; width: 100%;
font: 12px/1.6 "IBM Plex Mono", ui-monospace, monospace; }
td { vertical-align: top; padding: 0 8px; white-space: pre-wrap; word-break: break-word; }
td.no { color: #4b5f5c; text-align: right; user-select: none; width: 1%; min-width: 44px; }
td.sign { user-select: none; width: 1%; color: var(--dim); }
td.sign.add { color: var(--teal); }
td.sign.del { color: var(--coral); }
td.src.add { background: var(--add-bg); color: var(--add-ink); }
td.src.del { background: var(--del-bg); color: var(--del-ink); }
tr.hunk td { color: var(--accent); background: #171226; padding-top: 4px; padding-bottom: 4px; }
tr.file td { color: var(--mist); background: var(--panel); font-weight: 600; }
td.gap { background: #0b0f12; padding: 0; }
.empty { color: var(--dim); padding: 24px 18px; font-size: 13px; }
</style>
</head>
<body>
<header>
<svg class="mark" viewBox="0 0 32 32" aria-hidden="true">
<path d="M4 28 L16 4 L28 28" fill="none" stroke="#7E57C2" stroke-width="2.2"/>
<circle cx="16" cy="18" r="3" fill="#2ec4b6"/>
</svg>
<div><b>VARYNTH</b> <span>diff · paste a unified diff or pass ?diff=<urlencoded></span></div>
</header>
<div class="controls">
<textarea id="input" placeholder="diff --git a/x.rs b/x.rs --- a/x.rs +++ b/x.rs @@ -1,3 +1,4 @@ context -removed +added"></textarea>
<button type="button" class="go" id="render">RENDER</button>
<button type="button" class="ghost" id="example">example</button>
</div>
<div class="out" id="out"><div class="empty">Nothing to show yet — paste a unified diff above.</div></div>
<script>
const HUNK_RE = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
function td(cls, text) {
const el = document.createElement('td');
if (cls) el.className = cls;
if (text !== null) el.textContent = text;
return el;
}
function side(kind, no, sign, text) {
return [
td('no', no),
td('sign' + (kind ? ' ' + kind : ''), sign),
td('src' + (kind ? ' ' + kind : ''), text),
];
}
function appendHalf(tr, cells) {
for (const el of cells) tr.appendChild(el);
tr.appendChild(td('gap', null));
}
function appendEmptyHalf(tr) {
appendHalf(tr, side('', '', '', ''));
}
function renderDiff(text) {
const lines = text.split(/\r?\n/);
const tbody = document.createElement('tbody');
let oldNo = 0, newNo = 0;
let openRows = []; for (const line of lines) {
const hunk = line.match(HUNK_RE);
if (hunk) {
oldNo = parseInt(hunk[1], 10) - 1;
newNo = parseInt(hunk[3], 10) - 1;
openRows = [];
const tr = document.createElement('tr');
tr.className = 'hunk';
appendHalf(tr, side('', '', '', ''));
appendHalf(tr, side('', '', '', line));
tbody.appendChild(tr);
} else if (line.startsWith('--- ') || line.startsWith('+++ ')) {
openRows = [];
const isOld = line.startsWith('--- ');
const label = line.slice(4);
const tr = document.createElement('tr');
tr.className = 'file';
if (isOld) {
appendHalf(tr, side('', '', '', label));
appendEmptyHalf(tr);
} else {
const last = tbody.lastElementChild;
if (last && last.className === 'file' && last.children[6].textContent === '') {
last.children[6].textContent = label;
} else {
appendEmptyHalf(tr);
appendHalf(tr, side('', '', '', label));
}
tbody.appendChild(tr);
}
if (isOld) tbody.appendChild(tr);
openRows = [];
} else if (
line.startsWith('diff ') || line.startsWith('index ') ||
line.startsWith('old mode') || line.startsWith('new mode') ||
line.startsWith('new file') || line.startsWith('deleted file') ||
line.startsWith('rename ') || line.startsWith('similarity') ||
line.startsWith('Binary files')
) {
openRows = [];
const tr = document.createElement('tr');
tr.className = 'file';
appendHalf(tr, side('', '', '', ''));
appendHalf(tr, side('', '', '', line));
tbody.appendChild(tr);
} else if (line.startsWith('-')) {
oldNo++;
const tr = document.createElement('tr');
appendHalf(tr, side('del', oldNo, '-', line.slice(1)));
appendEmptyHalf(tr);
tbody.appendChild(tr);
openRows.push(tr);
} else if (line.startsWith('+')) {
newNo++;
const openRow = openRows.shift();
if (openRow) {
const cells = side('add', newNo, '+', line.slice(1));
openRow.replaceChild(cells[0], openRow.children[4]);
openRow.replaceChild(cells[1], openRow.children[5]);
openRow.replaceChild(cells[2], openRow.children[6]);
} else {
const tr = document.createElement('tr');
appendEmptyHalf(tr);
appendHalf(tr, side('add', newNo, '+', line.slice(1)));
tbody.appendChild(tr);
}
} else if (line.startsWith(' ') || line === '') {
openRows = [];
oldNo++;
newNo++;
const tr = document.createElement('tr');
appendHalf(tr, side('', oldNo, '', line.slice(1)));
appendHalf(tr, side('', newNo, '', line.slice(1)));
tbody.appendChild(tr);
} else if (line.startsWith('\\')) {
openRows = [];
const tr = document.createElement('tr');
tr.className = 'hunk';
appendHalf(tr, side('', '', '', ''));
appendHalf(tr, side('', '', '', line));
tbody.appendChild(tr);
} else {
openRows = [];
const tr = document.createElement('tr');
tr.className = 'file';
appendHalf(tr, side('', '', '', line));
appendEmptyHalf(tr);
tbody.appendChild(tr);
}
}
const table = document.createElement('table');
table.appendChild(tbody);
const out = document.getElementById('out');
out.innerHTML = '';
out.appendChild(table);
out.scrollTop = 0;
}
function renderFromBox() {
const text = document.getElementById('input').value;
if (!text.trim()) {
document.getElementById('out').innerHTML =
'<div class="empty">Nothing to show yet — paste a unified diff above.</div>';
return;
}
renderDiff(text);
}
document.getElementById('render').onclick = renderFromBox;
document.getElementById('input').addEventListener('keydown', function (e) {
if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') renderFromBox();
});
document.getElementById('example').onclick = function () {
document.getElementById('input').value = [
'diff --git a/src/gateway.rs b/src/gateway.rs',
'--- a/src/gateway.rs',
'+++ b/src/gateway.rs',
'@@ -1,5 +1,6 @@',
' //! WebSocket agent gateway',
' use axum::Router;',
'+pub const EVENT_CAPACITY: usize = 1024;',
'+pub const RELAY_CAPACITY: usize = 64;',
' ',
' impl Gateway {',
' fn route() -> &\'static str {'
].join('\n');
renderFromBox();
};
const passed = new URLSearchParams(location.search).get('diff');
if (passed) {
document.getElementById('input').value = passed;
renderFromBox();
}
</script>
</body>
</html>