Fix #194: gutter alignment and doubled line spacing in paste viewer
CI / test (pull_request) Successful in 45s
CI / docker (pull_request) Skipped

- paste-lines.js: join .codeline spans with no separator; newline text
  nodes between display:block spans in the white-space:pre container each
  rendered as an extra empty line box, doubling visual line spacing and
  desyncing the gutter in both wrap and no-wrap modes
- number only real lines: a paste ending in newline produced a phantom
  trailing number (6 for 5 lines)
This commit is contained in:
fen
2026-09-10 12:12:40 -05:00
parent bb72e09f8f
commit 392fa026cc
+13 -7
View File
@@ -12,8 +12,10 @@
return document.documentElement.hasAttribute('data-wrap'); return document.documentElement.hasAttribute('data-wrap');
}; };
// Wrap each logical line (split on newline; spans never contain newlines // #194: join with NO separator. .codeline is display:block, so a '\n'
// because HighlightCode highlights per line) in a .codeline block. // text node between spans is an extra line box in the white-space:pre
// container — that doubled the visual line spacing and desynced the
// gutter in BOTH modes.
function splitLines() { function splitLines() {
var html = body.innerHTML; var html = body.innerHTML;
var parts = html.split('\n'); var parts = html.split('\n');
@@ -21,13 +23,17 @@
for (var i = 0; i < parts.length; i++) { for (var i = 0; i < parts.length; i++) {
out.push('<span class="codeline">' + parts[i] + '</span>'); out.push('<span class="codeline">' + parts[i] + '</span>');
} }
body.innerHTML = out.join('\n'); body.innerHTML = out.join('');
} }
function renumber() { function renumber() {
var lines = body.querySelectorAll('.codeline'); var lines = body.querySelectorAll('.codeline');
// #194: a paste ending in '\n' produces one trailing empty .codeline;
// number only real lines (like every editor) so the count matches.
var count = lines.length;
if (count > 1 && lines[count - 1].textContent === '') count--;
var s = ''; var s = '';
if (wrapOn() && lines.length) { if (wrapOn() && count) {
// Each logical line block occupies rows = height / line-height when // Each logical line block occupies rows = height / line-height when
// wrapped; its number sits on the first row and the remaining rows get // wrapped; its number sits on the first row and the remaining rows get
// blank gutter lines so numbers stay aligned with line starts. // blank gutter lines so numbers stay aligned with line starts.
@@ -37,7 +43,7 @@
var lh = parseFloat(getComputedStyle(body).lineHeight) || 1; var lh = parseFloat(getComputedStyle(body).lineHeight) || 1;
gutter.textContent = ''; gutter.textContent = '';
var frag = document.createDocumentFragment(); var frag = document.createDocumentFragment();
for (var i = 0; i < lines.length; i++) { for (var i = 0; i < count; i++) {
var num = document.createElement('span'); var num = document.createElement('span');
num.className = 'gutline'; num.className = 'gutline';
num.textContent = String(i + 1); num.textContent = String(i + 1);
@@ -52,8 +58,8 @@
} }
gutter.appendChild(frag); gutter.appendChild(frag);
} else { } else {
for (var k = 1; k <= lines.length; k++) s += k + '\n'; for (var k = 1; k <= count; k++) s += k + '\n';
gutter.textContent = lines.length ? s.slice(0, -1) : '1'; gutter.textContent = count ? s.slice(0, -1) : '1';
} }
} }