From b8081f774bf2c6f903f58c85cf4c9a14c9c27ce6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96zge=20G=C3=BCner?= Date: Thu, 13 Aug 2026 14:29:41 +0200 Subject: [PATCH] fix: don't copy line numbers when copying a section of the log MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Copying a selected section (via "Copy Selection" / getSelection().toString()) was including the gutter line numbers. `user-select: none` stops the mouse from highlighting them but does NOT keep them out of Selection.toString(), so they leaked into the clipboard. Render the line number as CSS-generated content instead of a real text node: each `.line-number` now carries the value in a `data-lineno` attribute and shows it via `.line-number::after { content: attr(data-lineno) }`. Generated content is never part of the selection, so copying a section yields the log text only — no line numbers — across every render path (main, virtualized, diff, DOM-built). Uses ::after so it doesn't collide with the diff view's ::before +/-/~ gutter markers. Also added the -webkit-user-select prefix on the gutter. Nothing reads the gutter's textContent, so no logic changes. tsc 0 · 667 tests green · bundle built. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/renderer/renderer.ts | 10 ++++++---- src/renderer/styles.css | 8 ++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/renderer/renderer.ts b/src/renderer/renderer.ts index 4e0b708..e0ef6ea 100644 --- a/src/renderer/renderer.ts +++ b/src/renderer/renderer.ts @@ -1635,7 +1635,7 @@ function secondaryRenderVisibleLines(sv: SecondaryViewerInstance): void { div.className = className; div.dataset.lineNumber = String(line.lineNumber); - const lineNumHtml = `${line.lineNumber + 1}`; + const lineNumHtml = ``; const contentHtml = `${escapeHtml(line.text)}`; div.innerHTML = lineNumHtml + contentHtml; @@ -2927,7 +2927,7 @@ function createLineElementPooled(line: LogLine): HTMLDivElement { if (isLineMuted(line.text)) div.classList.add('muted'); // Create content using innerHTML for speed (single parse) - const lineNumHtml = `${line.lineNumber + 1}`; + const lineNumHtml = ``; let displayText = applyColumnFilter(line.text); // Truncate very long lines to prevent DOM/rendering slowness @@ -2994,7 +2994,7 @@ function createPlaceholderLinePooled(displayIndex: number): HTMLDivElement { div.dataset.lineNumber = ''; const numHtml = state.isFiltered ? '' - : `${displayIndex + 1}`; + : ``; // Dim inline bar (currentColor adapts to the theme); width jittered by index so // the skeleton reads as text, not a solid block. const barWidth = 30 + (displayIndex % 7) * 8; // 30–78% @@ -3032,7 +3032,9 @@ function createLineElement(line: LogLine): HTMLDivElement { const lineNumSpan = document.createElement('span'); lineNumSpan.className = 'line-number'; - lineNumSpan.textContent = String(line.lineNumber + 1); + // Render the number via CSS ::before (data-lineno) so it's NOT real DOM text and can't + // be selected/copied — copying a section yields the log text only, no line numbers. + lineNumSpan.setAttribute('data-lineno', String(line.lineNumber + 1)); const contentSpan = document.createElement('span'); contentSpan.className = 'line-content'; diff --git a/src/renderer/styles.css b/src/renderer/styles.css index d50bc79..cd8007c 100644 --- a/src/renderer/styles.css +++ b/src/renderer/styles.css @@ -2668,11 +2668,19 @@ button.is-cancelable:hover, .btn.is-cancelable:hover { filter: brightness(1.12); color: var(--text-muted); text-align: right; padding-right: 15px; + -webkit-user-select: none; user-select: none; border-right: 1px solid var(--border-color); margin-right: 10px; } +/* Show the number as CSS-generated content (data-lineno) rather than real text, so + selecting/copying a section of the log NEVER includes the line numbers. Uses ::after + so it doesn't collide with the diff view's ::before +/-/~ gutter markers below. */ +.line-number::after { + content: attr(data-lineno); +} + .line-content { flex: 1; user-select: text;