refactor(renderer): move diff rendering into its own module
views.js sat at the project's 750-line limit, so the diff cap in the previous commit pushed it over and every further change would have meant shaving comments elsewhere. That is the file asking for decomposition, which is what the architecture audit says to do. Diff rendering is self-contained: the line cap, the line classifier and the change-map illustration depend on nothing in views.js beyond ui and escapeHtml. They now live in src/renderer/diff-view.js and are registered in index.html and in the three renderer file lists that scan the bridge surface, so anything added there is covered by the existing contract tests. views.js drops from 755 to 714 lines and no source file exceeds 750 again. The nested ternary that classified a diff line became a named function with guard clauses on the way. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
5cecaa080d
commit
d77643c058
@@ -0,0 +1,40 @@
|
||||
// Rendering a unified diff is a self-contained concern with its own size
|
||||
// limits, kept out of views.js so that file stays within the project's
|
||||
// architecture budget.
|
||||
// A regenerated lock file runs into tens of thousands of lines, and one element
|
||||
// per line freezes the window. Only the rendered view is capped.
|
||||
const DIFF_RENDER_LINE_LIMIT = 2000;
|
||||
|
||||
function diffAtmosphere(diff, allLines = null) {
|
||||
if (!ui.selectedFile) return "";
|
||||
const lines = allLines || String(diff || "").split("\n");
|
||||
const additions = lines.filter(
|
||||
(line) => line.startsWith("+") && !line.startsWith("+++"),
|
||||
).length;
|
||||
const removals = lines.filter(
|
||||
(line) => line.startsWith("-") && !line.startsWith("---"),
|
||||
).length;
|
||||
const extension =
|
||||
String(ui.selectedFile).split(".").pop()?.slice(0, 8).toUpperCase() ||
|
||||
"FILE";
|
||||
return `<div class="diff-atmosphere ${lines.length > 34 ? "dense" : ""}" data-diff-atmosphere aria-hidden="true"><svg viewBox="0 0 360 260" role="presentation"><path class="code-route route-a" d="M38 195 C92 84 178 214 318 74"/><path class="code-route route-b" d="M52 74 C132 8 230 34 310 156"/><g class="code-card"><rect x="110" y="75" width="142" height="106" rx="18"/><path d="M136 108h90M136 128h58M136 148h76"/></g><g class="code-node node-one"><circle cx="48" cy="190" r="15"/><path d="m41 190 5 5 9-12"/></g><g class="code-node node-two"><circle cx="315" cy="76" r="13"/><path d="M308 76h14M315 69v14"/></g><circle class="code-packet packet-one" cx="0" cy="0" r="5"/><circle class="code-packet packet-two" cx="0" cy="0" r="4"/></svg><div class="diff-atmosphere-caption"><span>${escapeHtml(extension)} change map</span><strong><i>+${additions}</i><i>−${removals}</i></strong></div></div>`;
|
||||
}
|
||||
|
||||
function diffLineType(line) {
|
||||
if (line.startsWith("+") && !line.startsWith("+++")) return "add";
|
||||
if (line.startsWith("-") && !line.startsWith("---")) return "remove";
|
||||
return line.startsWith("@@") ? "hunk" : "";
|
||||
}
|
||||
|
||||
function renderDiff(diff) {
|
||||
if (!diff)
|
||||
return '<div class="empty-state"><div class="empty-icon">↔</div><h3>No textual diff</h3><p>Select another file or open the project folder for binary changes.</p></div>';
|
||||
const lines = String(diff).split("\n");
|
||||
const rendered = lines
|
||||
.slice(0, DIFF_RENDER_LINE_LIMIT)
|
||||
.map((line) => `<span class="diff-line ${diffLineType(line)}">${escapeHtml(line) || " "}</span>`)
|
||||
.join("");
|
||||
const hidden = Math.max(0, lines.length - DIFF_RENDER_LINE_LIMIT);
|
||||
const notice = hidden ? `<span class="diff-line hunk">… ${hidden.toLocaleString()} more line${hidden === 1 ? "" : "s"} are not shown. Copy diff and the editor still give you the complete change.</span>` : "";
|
||||
return `${rendered}${notice}${diffAtmosphere(diff, lines)}`;
|
||||
}
|
||||
@@ -21,6 +21,7 @@
|
||||
<script defer src="mock-deployment-bridge.js"></script>
|
||||
<script defer src="mock-bridge.js"></script>
|
||||
<script defer src="app.js"></script>
|
||||
<script defer src="diff-view.js"></script>
|
||||
<script defer src="views.js"></script>
|
||||
<script defer src="dialogs.js"></script>
|
||||
<script defer src="operations.js"></script>
|
||||
|
||||
@@ -206,50 +206,6 @@ function linkedWorkloadsForRepository(repository) {
|
||||
);
|
||||
}
|
||||
|
||||
// A regenerated lock file is an ordinary change and runs into tens of thousands
|
||||
// of lines. One element per line freezes the window while it is parsed and laid
|
||||
// out, so the tail is left out of the rendered view only.
|
||||
const DIFF_RENDER_LINE_LIMIT = 2000;
|
||||
|
||||
function diffAtmosphere(diff, allLines = null) {
|
||||
if (!ui.selectedFile) return "";
|
||||
const lines = allLines || String(diff || "").split("\n");
|
||||
const additions = lines.filter(
|
||||
(line) => line.startsWith("+") && !line.startsWith("+++"),
|
||||
).length;
|
||||
const removals = lines.filter(
|
||||
(line) => line.startsWith("-") && !line.startsWith("---"),
|
||||
).length;
|
||||
const extension =
|
||||
String(ui.selectedFile).split(".").pop()?.slice(0, 8).toUpperCase() ||
|
||||
"FILE";
|
||||
return `<div class="diff-atmosphere ${lines.length > 34 ? "dense" : ""}" data-diff-atmosphere aria-hidden="true"><svg viewBox="0 0 360 260" role="presentation"><path class="code-route route-a" d="M38 195 C92 84 178 214 318 74"/><path class="code-route route-b" d="M52 74 C132 8 230 34 310 156"/><g class="code-card"><rect x="110" y="75" width="142" height="106" rx="18"/><path d="M136 108h90M136 128h58M136 148h76"/></g><g class="code-node node-one"><circle cx="48" cy="190" r="15"/><path d="m41 190 5 5 9-12"/></g><g class="code-node node-two"><circle cx="315" cy="76" r="13"/><path d="M308 76h14M315 69v14"/></g><circle class="code-packet packet-one" cx="0" cy="0" r="5"/><circle class="code-packet packet-two" cx="0" cy="0" r="4"/></svg><div class="diff-atmosphere-caption"><span>${escapeHtml(extension)} change map</span><strong><i>+${additions}</i><i>−${removals}</i></strong></div></div>`;
|
||||
}
|
||||
|
||||
function renderDiff(diff) {
|
||||
if (!diff)
|
||||
return '<div class="empty-state"><div class="empty-icon">↔</div><h3>No textual diff</h3><p>Select another file or open the project folder for binary changes.</p></div>';
|
||||
const lines = String(diff).split("\n");
|
||||
const rendered = lines
|
||||
.slice(0, DIFF_RENDER_LINE_LIMIT)
|
||||
.map((line) => {
|
||||
const type =
|
||||
line.startsWith("+") && !line.startsWith("+++")
|
||||
? "add"
|
||||
: line.startsWith("-") && !line.startsWith("---")
|
||||
? "remove"
|
||||
: line.startsWith("@@")
|
||||
? "hunk"
|
||||
: "";
|
||||
return `<span class="diff-line ${type}">${escapeHtml(line) || " "}</span>`;
|
||||
})
|
||||
.join("");
|
||||
const hidden = Math.max(0, lines.length - DIFF_RENDER_LINE_LIMIT);
|
||||
const notice = hidden
|
||||
? `<span class="diff-line hunk">… ${hidden.toLocaleString()} more line${hidden === 1 ? "" : "s"} are not shown. Copy diff and the editor still give you the complete change.</span>`
|
||||
: "";
|
||||
return `${rendered}${notice}${diffAtmosphere(diff, lines)}`;
|
||||
}
|
||||
function fileStatusCode(file) {
|
||||
if (file.conflict) return "U";
|
||||
if (file.untracked) return "?";
|
||||
|
||||
Reference in New Issue
Block a user