From 83faaeff27e51ed6ef28983ad7cd6f52532822c2 Mon Sep 17 00:00:00 2001 From: Amp Date: Tue, 27 Oct 2026 17:14:31 +0000 Subject: [PATCH] fix: copy the whole code block from a folded commit preview Closes #1161 Amp-Thread-ID: https://ampcode.com/threads/T-01a17e54-550b-7555-a31c-4f59a6d3fedb Co-authored-by: Nuno Maduro --- resources/js/components/code-block.tsx | 13 ++++++++++++- resources/js/components/commit-body.tsx | 25 ++++++++++++++++++++++++- resources/js/types/commit.ts | 8 +++++++- 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/resources/js/components/code-block.tsx b/resources/js/components/code-block.tsx index cf04563d3..96e2b0486 100644 --- a/resources/js/components/code-block.tsx +++ b/resources/js/components/code-block.tsx @@ -7,10 +7,12 @@ import { cn } from '@/lib/utils'; export function CodeBlock({ html, + fullHtml, language, isCopyable = true, }: { html: string; + fullHtml?: string; language: string | null; isCopyable?: boolean; }) { @@ -34,7 +36,16 @@ export function CodeBlock({ return; } - if (await copy(codeRef.current.textContent ?? '')) { + let code = codeRef.current.textContent ?? ''; + + if (fullHtml !== undefined) { + // The server escapes the code while highlighting it, and a template runs nothing. + const template = document.createElement('template'); + template.innerHTML = fullHtml; + code = template.content.textContent ?? ''; + } + + if (await copy(code)) { setIsCopied(true); return; diff --git a/resources/js/components/commit-body.tsx b/resources/js/components/commit-body.tsx index fac23d0a0..6ecabe883 100644 --- a/resources/js/components/commit-body.tsx +++ b/resources/js/components/commit-body.tsx @@ -91,6 +91,7 @@ export function BodySegments({ @@ -147,7 +148,11 @@ export function FoldedCommitBody({ return (
@@ -165,6 +170,24 @@ export function FoldedCommitBody({ ); } +/** + * The preview is the start of the body, so its code blocks are the body's first ones, in order. The last may be cut + * to its first lines; each gets the whole block to copy. + */ +function withFullBlocks( + previewSegments: BodySegment[], + segments: BodySegment[], +): BodySegment[] { + const blocks = segments.filter((segment) => segment.type === 'block'); + let index = 0; + + return previewSegments.map((segment) => + segment.type === 'block' + ? { ...segment, fullHtml: blocks[index++]?.html } + : segment, + ); +} + export function CommitBodyExcerpt({ segments, previewSegments = null, diff --git a/resources/js/types/commit.ts b/resources/js/types/commit.ts index 12790e4d3..4e6b99583 100644 --- a/resources/js/types/commit.ts +++ b/resources/js/types/commit.ts @@ -50,7 +50,13 @@ export type CommitImage = { export type BodySegment = | { type: 'text'; text: string } | { type: 'code'; code: string } - | { type: 'block'; language: string | null; html: string }; + | { + type: 'block'; + language: string | null; + html: string; + // The whole block, when a preview shows only its first lines, so copying it still copies all of it. + fullHtml?: string; + }; export type CommitTranslation = { language: string;