⚠️ 变更过大,已跳过渲染
共 ${files.length} 个文件,
+${totalAdd}
-${totalDel}
渲染大量变更可能导致浏览器卡顿
`;
document.getElementById(id).addEventListener('click', onExpand);
},
// ── Incremental rendering pipeline ──────────────────────────────
// Render diff with file tree sidebar — incremental, non-blocking
renderDiff(diffString, options = {}) {
if (!this.container) return;
// Cancel any in-progress incremental render
this._cancelRender();
this.rawDiff = diffString;
this._onRenderComplete = options.onComplete || null;
// Parse files for tree (fast — just regex + string ops)
this.files = this._parseDiffFiles(diffString);
// Guard: if diff is too large, show warning instead of rendering
if (!options.forceRender && this._isTooLarge(this.files)) {
const totalAdd = this.files.reduce((s, f) => s + f.additions, 0);
const totalDel = this.files.reduce((s, f) => s + f.deletions, 0);
const self = this;
this._renderTooLargeWarning(this.files, totalAdd, totalDel, function () {
self.renderDiff(diffString, { ...options, forceRender: true });
});
return;
}
const tree = this._buildTree(this.files);
// Split diff into per-file chunks for incremental rendering
this._chunks = this._splitDiffIntoChunks(diffString);
this._chunkIndex = 0;
this._renderedCount = 0;
// Determine initial mode
const outputFormat = options.outputFormat ||
(this.currentMode === 'unified' ? 'line-by-line' : 'side-by-side');
this.currentMode = outputFormat === 'line-by-line' ? 'unified' : 'side-by-side';
// Build layout shell: sidebar + empty diff area
const treeHtml = this._renderFileTree(tree);
this.container.innerHTML = `