Skip to content

Commit db50855

Browse files
committed
Improving diff display
1 parent d2dc911 commit db50855

1 file changed

Lines changed: 32 additions & 34 deletions

File tree

background.js

Lines changed: 32 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -397,8 +397,8 @@ function canonicalizeForDiff(text) {
397397
.replace(/[]/g, "'")
398398
.replace(/[\u2013\u2014]/g, '-') // en/em dash -> hyphen
399399
.replace(/\u00a0/g, ' ') // non-breaking space
400+
.replace(/\n+/g, ' ') // collapse newlines
400401
.replace(/[ \t]+/g, ' ') // collapse spaces/tabs
401-
.replace(/\n{2,}/g, '\n') // collapse blank lines
402402
.trim()
403403
.toLowerCase();
404404
}
@@ -1736,43 +1736,41 @@ function renderDiffHtml(diff) {
17361736
const escapeHtmlFragment = (str) => String(str)
17371737
.replace(/&/g, '&')
17381738
.replace(/</g, '&lt;')
1739-
.replace(/>/g, '&gt;');
1740-
const escapeWhitespace = (str) => escapeHtmlFragment(str)
1741-
.replace(/ /g, '&nbsp;')
1739+
.replace(/>/g, '&gt;')
17421740
.replace(/\t/g, '&nbsp;&nbsp;&nbsp;&nbsp;');
1743-
const opStyle = (op) => op === 1
1744-
? 'background:#e6ffe6;'
1745-
: op === -1
1746-
? 'background:#ffe6e6;text-decoration:line-through;'
1747-
: '';
1748-
const renderLeadingWhitespace = (op, chunk) => {
1749-
if (!chunk) return '';
1750-
const safe = escapeWhitespace(chunk);
1751-
if (op === 0) return safe;
1752-
return `<span class="ldiff-leading" style="${opStyle(op)}">${safe}</span>`;
1741+
const listLinePattern = /^\s*(?:\(?\d+\)|\d+[.)]|[a-zA-Z][.)]|[-*])\s+/;
1742+
const shouldForceBreak = (text, newlineIdx, runLength) => {
1743+
if (runLength !== 1) return false;
1744+
const nextSlice = text.slice(newlineIdx + 1);
1745+
const nextLine = nextSlice.split('\n', 1)[0] || '';
1746+
return listLinePattern.test(nextLine);
1747+
};
1748+
const formatDiffText = (text) => {
1749+
if (!text) return '';
1750+
let out = '';
1751+
let lastIndex = 0;
1752+
text.replace(/\n+/g, (match, idx) => {
1753+
if (idx > lastIndex) out += escapeHtmlFragment(text.slice(lastIndex, idx));
1754+
out += match.length === 1
1755+
? (shouldForceBreak(text, idx, match.length) ? '<br>' : ' ')
1756+
: '<br>'.repeat(match.length);
1757+
lastIndex = idx + match.length;
1758+
return match;
1759+
});
1760+
if (lastIndex < text.length) out += escapeHtmlFragment(text.slice(lastIndex));
1761+
return out;
17531762
};
17541763
const renderBody = (op, chunk) => {
17551764
if (!chunk) return '';
1756-
const safe = escapeHtmlFragment(chunk);
1757-
if (op === 1) return `<ins>${safe}</ins>`;
1758-
if (op === -1) return `<del>${safe}</del>`;
1759-
return `<span>${safe}</span>`;
1765+
const formatted = formatDiffText(chunk);
1766+
const whitespaceOnly = !/\S/.test(chunk);
1767+
if (op === 1 && !whitespaceOnly) return `<ins>${formatted}</ins>`;
1768+
if (op === -1 && !whitespaceOnly) return `<del>${formatted}</del>`;
1769+
if (op === 0 && !whitespaceOnly) return `<span>${formatted}</span>`;
1770+
return `<span></span>`;
17601771
};
1761-
const renderChunk = (op, text) => {
1762-
if (!text) return '';
1763-
const lines = text.split('\n');
1764-
const parts = [];
1765-
for (let i = 0; i < lines.length; i++) {
1766-
const line = lines[i];
1767-
const trimmed = line.replace(/^[ \t]+/, '');
1768-
if (trimmed.length) {
1769-
parts.push(renderBody(op, trimmed));
1770-
}
1771-
if (i < lines.length - 1) parts.push('<br>');
1772-
}
1773-
return parts.join('');
1774-
};
1775-
1776-
const html = sanitized.map(([op, data]) => renderChunk(op, data)).join('');
1772+
const viewable = sanitized; // include deletions again
1773+
if (!viewable.length) throw new Error('Empty diff after filtering viewable segments');
1774+
const html = viewable.map(([op, data]) => renderBody(op, data)).join('');
17771775
return `<div class="ldiff-output" id="outputdiv">${html}</div>`;
17781776
}

0 commit comments

Comments
 (0)