From 4f5a4cb7efd7554c507e7d2e623727fcc7148836 Mon Sep 17 00:00:00 2001 From: andrepimenta Date: Wed, 9 Jul 2025 13:46:32 +0100 Subject: [PATCH] Copy code block --- src/ui-styles.ts | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ src/ui.ts | 52 +++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 101 insertions(+), 4 deletions(-) diff --git a/src/ui-styles.ts b/src/ui-styles.ts index 96d0134..bfb3336 100644 --- a/src/ui-styles.ts +++ b/src/ui-styles.ts @@ -856,6 +856,59 @@ const styles = ` word-break: break-word; } + /* Code block container and header */ + .code-block-container { + margin: 8px 0; + border: 1px solid var(--vscode-panel-border); + border-radius: 4px; + background-color: var(--vscode-textCodeBlock-background); + overflow: hidden; + } + + .code-block-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 4px 6px; + background-color: var(--vscode-editor-background); + border-bottom: 1px solid var(--vscode-panel-border); + font-size: 10px; + } + + .code-block-language { + color: var(--vscode-descriptionForeground); + font-family: var(--vscode-editor-font-family); + font-weight: 500; + text-transform: uppercase; + letter-spacing: 0.5px; + } + + .code-copy-btn { + background: none; + border: none; + color: var(--vscode-descriptionForeground); + cursor: pointer; + padding: 4px; + border-radius: 3px; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s ease; + opacity: 0.7; + } + + .code-copy-btn:hover { + background-color: var(--vscode-list-hoverBackground); + opacity: 1; + } + + .code-block-container .code-block { + margin: 0; + border: none; + border-radius: 0; + background: none; + } + /* Inline code */ .message-content code { background-color: var(--vscode-textCodeBlock-background); diff --git a/src/ui.ts b/src/ui.ts index 0381dea..8d9d21c 100644 --- a/src/ui.ts +++ b/src/ui.ts @@ -1815,6 +1815,32 @@ const html = ` }); } } + + function copyCodeBlock(codeId) { + const codeElement = document.getElementById(codeId); + if (codeElement) { + const rawCode = codeElement.getAttribute('data-raw-code'); + if (rawCode) { + // Decode HTML entities + const decodedCode = rawCode.replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&'); + navigator.clipboard.writeText(decodedCode).then(() => { + // Show temporary feedback + const copyBtn = codeElement.closest('.code-block-container').querySelector('.code-copy-btn'); + if (copyBtn) { + const originalInnerHTML = copyBtn.innerHTML; + copyBtn.innerHTML = ''; + copyBtn.style.color = '#4caf50'; + setTimeout(() => { + copyBtn.innerHTML = originalInnerHTML; + copyBtn.style.color = ''; + }, 1000); + } + }).catch(err => { + console.error('Failed to copy code:', err); + }); + } + } + } window.addEventListener('message', event => { const message = event.data; @@ -2263,6 +2289,9 @@ const html = ` // First, handle code blocks before line-by-line processing let processedMarkdown = markdown; + // Store code blocks temporarily to protect them from further processing + const codeBlockPlaceholders = []; + // Handle multi-line code blocks with triple backticks // Using RegExp constructor to avoid backtick conflicts in template literal const codeBlockRegex = new RegExp('\\\`\\\`\\\`(\\\\w*)\\n([\\\\s\\\\S]*?)\\\`\\\`\\\`', 'g'); @@ -2277,7 +2306,16 @@ const html = ` codeHtml += '
' + escapedLine + '
'; } - return '\\n
' + codeHtml + '
\\n'; + // Create unique ID for this code block + const codeId = 'code_' + Math.random().toString(36).substr(2, 9); + const escapedCode = escapeHtml(code); + + const codeBlockHtml = '
' + language + '
' + codeHtml + '
'; + + // Store the code block and return a placeholder + const placeholder = '__CODEBLOCK_' + codeBlockPlaceholders.length + '__'; + codeBlockPlaceholders.push(codeBlockHtml); + return placeholder; }); // Handle inline code with single backticks @@ -2292,9 +2330,9 @@ const html = ` for (let line of lines) { line = line.trim(); - // Check if this is a code block - if (line.includes('

 			if (inUnorderedList) html += '';
 			if (inOrderedList) html += '';
 
+			// Restore code block placeholders
+			for (let i = 0; i < codeBlockPlaceholders.length; i++) {
+				const placeholder = '__CODEBLOCK_' + i + '__';
+				html = html.replace(placeholder, codeBlockPlaceholders[i]);
+			}
+
 			return html;
 		}