Skip to content

Commit 10b658a

Browse files
enhanced copy button functionality
1 parent 6178f34 commit 10b658a

File tree

3 files changed

+232
-11
lines changed

3 files changed

+232
-11
lines changed

layouts/partials/scripts.html

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,76 @@
11
<!-- Code for copy to clipboard button -->
22
<script>
3+
// Smart copy processing function to handle shell prompts
4+
function smartCopyProcessing(text) {
5+
const lines = text.split('\n');
6+
const processedLines = [];
7+
let inMultiLineCommand = false;
8+
let currentCommand = '';
9+
10+
// Regex patterns for different shell prompts
11+
const promptPatterns = [
12+
/^\s*\$\s+(.+)$/, // $ command
13+
/^\s*#\s+(.+)$/, // # command (root)
14+
/^\s*[\w.-]+>\s+(.+)$/, // redis-cli>, rladmin>, etc.
15+
/^\s*[\d.:]+>\s+(.+)$/, // 127.0.0.1:6379> command
16+
];
17+
18+
for (let line of lines) {
19+
let isPromptLine = false;
20+
let commandPart = '';
21+
22+
// Check if this line matches any prompt pattern
23+
for (let pattern of promptPatterns) {
24+
const match = line.match(pattern);
25+
if (match) {
26+
isPromptLine = true;
27+
commandPart = match[1];
28+
break;
29+
}
30+
}
31+
32+
if (isPromptLine) {
33+
// Handle multi-line commands with backslash continuation
34+
if (commandPart.endsWith('\\')) {
35+
inMultiLineCommand = true;
36+
currentCommand = commandPart.slice(0, -1).trim() + ' ';
37+
} else {
38+
if (inMultiLineCommand) {
39+
// End of multi-line command
40+
currentCommand += commandPart;
41+
processedLines.push(currentCommand.trim());
42+
inMultiLineCommand = false;
43+
currentCommand = '';
44+
} else {
45+
// Single line command
46+
processedLines.push(commandPart);
47+
}
48+
}
49+
} else if (inMultiLineCommand) {
50+
// Continuation line of a multi-line command
51+
const trimmedLine = line.trim();
52+
if (trimmedLine.endsWith('\\')) {
53+
currentCommand += trimmedLine.slice(0, -1).trim() + ' ';
54+
} else {
55+
currentCommand += trimmedLine;
56+
processedLines.push(currentCommand.trim());
57+
inMultiLineCommand = false;
58+
currentCommand = '';
59+
}
60+
} else {
61+
// Regular line (output, comments, etc.) - copy as-is
62+
processedLines.push(line);
63+
}
64+
}
65+
66+
// Handle case where multi-line command was not completed
67+
if (inMultiLineCommand && currentCommand) {
68+
processedLines.push(currentCommand.trim());
69+
}
70+
71+
return processedLines.join('\n');
72+
}
73+
374
document.addEventListener("DOMContentLoaded", function () {
475

576
// Add copy buttons to code blocks (but skip those inside codetabs)
@@ -48,9 +119,12 @@
48119
// Handle copy logic
49120
button.addEventListener('click', () => {
50121
const lines = block.querySelectorAll('span.cl');
51-
const text = Array.from(lines).map(line => line.textContent).join('');
122+
const rawText = Array.from(lines).map(line => line.textContent).join('');
123+
124+
// Smart copy: detect shell prompts and extract commands
125+
const processedText = smartCopyProcessing(rawText);
52126

53-
navigator.clipboard.writeText(text).then(() => {
127+
navigator.clipboard.writeText(processedText).then(() => {
54128
tooltip.style.display = 'block';
55129
setTimeout(() => {
56130
tooltip.style.display = 'none';

static/js/agent-builder.js

Lines changed: 79 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -823,27 +823,101 @@ public class ${formData.agentName.replace(/\s+/g, '')}
823823
return `${cleanName}_agent${extensions[formData.programmingLanguage]}`;
824824
}
825825

826+
// Smart copy processing function to handle shell prompts
827+
function smartCopyProcessing(text) {
828+
const lines = text.split('\n');
829+
const processedLines = [];
830+
let inMultiLineCommand = false;
831+
let currentCommand = '';
832+
833+
// Regex patterns for different shell prompts
834+
const promptPatterns = [
835+
/^\s*\$\s+(.+)$/, // $ command
836+
/^\s*#\s+(.+)$/, // # command (root)
837+
/^\s*[\w.-]+>\s+(.+)$/, // redis-cli>, rladmin>, etc.
838+
/^\s*[\d.:]+>\s+(.+)$/, // 127.0.0.1:6379> command
839+
];
840+
841+
for (let line of lines) {
842+
let isPromptLine = false;
843+
let commandPart = '';
844+
845+
// Check if this line matches any prompt pattern
846+
for (let pattern of promptPatterns) {
847+
const match = line.match(pattern);
848+
if (match) {
849+
isPromptLine = true;
850+
commandPart = match[1];
851+
break;
852+
}
853+
}
854+
855+
if (isPromptLine) {
856+
// Handle multi-line commands with backslash continuation
857+
if (commandPart.endsWith('\\')) {
858+
inMultiLineCommand = true;
859+
currentCommand = commandPart.slice(0, -1).trim() + ' ';
860+
} else {
861+
if (inMultiLineCommand) {
862+
// End of multi-line command
863+
currentCommand += commandPart;
864+
processedLines.push(currentCommand.trim());
865+
inMultiLineCommand = false;
866+
currentCommand = '';
867+
} else {
868+
// Single line command
869+
processedLines.push(commandPart);
870+
}
871+
}
872+
} else if (inMultiLineCommand) {
873+
// Continuation line of a multi-line command
874+
const trimmedLine = line.trim();
875+
if (trimmedLine.endsWith('\\')) {
876+
currentCommand += trimmedLine.slice(0, -1).trim() + ' ';
877+
} else {
878+
currentCommand += trimmedLine;
879+
processedLines.push(currentCommand.trim());
880+
inMultiLineCommand = false;
881+
currentCommand = '';
882+
}
883+
} else {
884+
// Regular line (output, comments, etc.) - copy as-is
885+
processedLines.push(line);
886+
}
887+
}
888+
889+
// Handle case where multi-line command was not completed
890+
if (inMultiLineCommand && currentCommand) {
891+
processedLines.push(currentCommand.trim());
892+
}
893+
894+
return processedLines.join('\n');
895+
}
896+
826897
function copyCode() {
827898
// Get the raw code from the dataset (not the highlighted version)
828-
const code = elements.codeSection.dataset.code;
899+
const rawCode = elements.codeSection.dataset.code;
829900
const copyBtn = document.getElementById('copy-code-btn');
830901

831-
if (!code) {
902+
if (!rawCode) {
832903
alert('No code available to copy');
833904
return;
834905
}
835906

907+
// Process the code with smart copy functionality
908+
const processedCode = smartCopyProcessing(rawCode);
909+
836910
// Try to copy to clipboard
837911
if (navigator.clipboard && navigator.clipboard.writeText) {
838-
navigator.clipboard.writeText(code).then(() => {
912+
navigator.clipboard.writeText(processedCode).then(() => {
839913
showCopyFeedback(copyBtn, true);
840914
}).catch(err => {
841915
console.error('Failed to copy to clipboard:', err);
842-
fallbackCopyToClipboard(code, copyBtn);
916+
fallbackCopyToClipboard(processedCode, copyBtn);
843917
});
844918
} else {
845919
// Fallback for older browsers
846-
fallbackCopyToClipboard(code, copyBtn);
920+
fallbackCopyToClipboard(processedCode, copyBtn);
847921
}
848922
}
849923

static/js/codetabs.js

Lines changed: 77 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,81 @@
11
// TODO: URI-able tabs
22

3+
// Smart copy processing function to handle shell prompts
4+
function smartCopyProcessing(text) {
5+
const lines = text.split('\n');
6+
const processedLines = [];
7+
let inMultiLineCommand = false;
8+
let currentCommand = '';
9+
10+
// Regex patterns for different shell prompts
11+
const promptPatterns = [
12+
/^\s*\$\s+(.+)$/, // $ command
13+
/^\s*#\s+(.+)$/, // # command (root)
14+
/^\s*[\w.-]+>\s+(.+)$/, // redis-cli>, rladmin>, etc.
15+
/^\s*[\d.:]+>\s+(.+)$/, // 127.0.0.1:6379> command
16+
];
17+
18+
for (let line of lines) {
19+
let isPromptLine = false;
20+
let commandPart = '';
21+
22+
// Check if this line matches any prompt pattern
23+
for (let pattern of promptPatterns) {
24+
const match = line.match(pattern);
25+
if (match) {
26+
isPromptLine = true;
27+
commandPart = match[1];
28+
break;
29+
}
30+
}
31+
32+
if (isPromptLine) {
33+
// Handle multi-line commands with backslash continuation
34+
if (commandPart.endsWith('\\')) {
35+
inMultiLineCommand = true;
36+
currentCommand = commandPart.slice(0, -1).trim() + ' ';
37+
} else {
38+
if (inMultiLineCommand) {
39+
// End of multi-line command
40+
currentCommand += commandPart;
41+
processedLines.push(currentCommand.trim());
42+
inMultiLineCommand = false;
43+
currentCommand = '';
44+
} else {
45+
// Single line command
46+
processedLines.push(commandPart);
47+
}
48+
}
49+
} else if (inMultiLineCommand) {
50+
// Continuation line of a multi-line command
51+
const trimmedLine = line.trim();
52+
if (trimmedLine.endsWith('\\')) {
53+
currentCommand += trimmedLine.slice(0, -1).trim() + ' ';
54+
} else {
55+
currentCommand += trimmedLine;
56+
processedLines.push(currentCommand.trim());
57+
inMultiLineCommand = false;
58+
currentCommand = '';
59+
}
60+
} else {
61+
// Regular line (output, comments, etc.) - copy as-is
62+
processedLines.push(line);
63+
}
64+
}
65+
66+
// Handle case where multi-line command was not completed
67+
if (inMultiLineCommand && currentCommand) {
68+
processedLines.push(currentCommand.trim());
69+
}
70+
71+
return processedLines.join('\n');
72+
}
73+
374
function copyCodeToClipboard(panelId) {
475
// Get the last <code>, path depends on highlighter options
5-
const code = [...document.querySelectorAll(`${panelId} code`)].pop().textContent;
6-
navigator.clipboard.writeText(code);
76+
const rawCode = [...document.querySelectorAll(`${panelId} code`)].pop().textContent;
77+
const processedCode = smartCopyProcessing(rawCode);
78+
navigator.clipboard.writeText(processedCode);
779

880
// Toggle tooltip
981
const tooltip = document.querySelector(`${panelId} .tooltiptext`);
@@ -22,8 +94,9 @@ function copyCodeToClipboardForCodetabs(button) {
2294
if (!visiblePanel) return;
2395

2496
// Get the code from the visible panel
25-
const code = [...visiblePanel.querySelectorAll('code')].pop().textContent;
26-
navigator.clipboard.writeText(code);
97+
const rawCode = [...visiblePanel.querySelectorAll('code')].pop().textContent;
98+
const processedCode = smartCopyProcessing(rawCode);
99+
navigator.clipboard.writeText(processedCode);
27100

28101
// Toggle tooltip
29102
const tooltip = button.querySelector('.tooltiptext');

0 commit comments

Comments
 (0)