diff --git a/layouts/partials/scripts.html b/layouts/partials/scripts.html
index d294b98851..567b497099 100644
--- a/layouts/partials/scripts.html
+++ b/layouts/partials/scripts.html
@@ -49,7 +49,13 @@
// Handle copy logic
button.addEventListener('click', () => {
const lines = block.querySelectorAll('span.cl');
- const text = Array.from(lines).map(line => line.textContent).join('');
+ // Single-line blocks are almost always one command preceded by a
+ // prompt ("$ ", "> ", "127.0.0.1:6379> "). Strip that prompt so the
+ // copied text runs as-is. Multiline blocks mix commands and output,
+ // so leave them untouched.
+ const text = lines.length === 1
+ ? lines[0].textContent.replace(/^(\s*)(?:\$\s+|>\s+|127\.0\.0\.1:6379>\s+)/, '$1')
+ : Array.from(lines).map(line => line.textContent).join('');
navigator.clipboard.writeText(text).then(() => {
tooltip.style.display = 'block';
diff --git a/static/js/codetabs.js b/static/js/codetabs.js
index 16170411bb..8c31cd7089 100644
--- a/static/js/codetabs.js
+++ b/static/js/codetabs.js
@@ -72,6 +72,14 @@ function copyCodeToClipboardForCodetabs(button) {
}
}
+ // Single-line blocks are almost always one command preceded by a prompt
+ // ("$ ", "> ", "127.0.0.1:6379> "). Strip that prompt so the copied text
+ // runs as-is. Multiline blocks mix commands and output, so leave them untouched.
+ const codeLines = code.split('\n').filter(line => line !== '');
+ if (codeLines.length === 1) {
+ code = codeLines[0].replace(/^(\s*)(?:\$\s+|>\s+|127\.0\.0\.1:6379>\s+)/, '$1');
+ }
+
navigator.clipboard.writeText(code);
// Toggle tooltip