docs: Add copy buttons to all the codeblocks

This uses a bit of javascript to add copy buttons, so you can directly
copy all the code in a given block to the clipboard!

For codeblocks without prompts, it just copies all the code, for
blocks with prompts, it copies all the lines after prompts, under the
assumption that that's the code to be executed.

It would give you *all* the lines, so the output wouldn't be
interleaved like it is in the html, but good enough.

The buttons appear on hover, so they aren't usable on phones, but
since you won't really have a clipboard on phones and I have no idea
how to make them not always in front of the text otherwise: Eh.

I'm not in love with the javascript here, but it'll do.
This commit is contained in:
Fabian Homborg 2021-08-13 18:50:38 +02:00
parent e2fef7b392
commit 7f34b8ab53
2 changed files with 74 additions and 0 deletions

View file

@ -58,4 +58,58 @@
{% trans sphinx_version=sphinx_version|e %}Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> {{ sphinx_version }}.{% endtrans %}
</div>
</div>
<script type="text/javascript">
function copy_to_clipboard(it) {
// Find the pre tag we're interested in.
var pre = it.target;
while (pre.tagName != "PRE") pre = pre.parentNode;
var txt = "";
// Cheesy: If we have a prompt,
// we only copy prompted lines,
// by splitting and matching and stuff
if (pre.querySelector('span.gp')) {
var texts= [];
for (var line of pre.innerText.split('\n')) {
if (line.match(/^>_?.*/)) {
texts.push(line.replace(/^>_?/, ""));
}
}
txt = texts.join("\n");
} else {
// Even cheesier: If we don't have a prompt, we remove the button text from the end.
var txt = pre.innerText.substring(0, pre.innerText.length - it.target.innerText.length).trim();
}
navigator.clipboard.writeText(txt).then(function() {
// Success - set the text to indicate it,
// then set it back after 2 seconds.
var span = pre.querySelector("button span");
if (span) {
var oldText = span.innerText;
span.innerText = "COPIED!";
setTimeout(function() {
span.innerText = oldText;
}, 2000);
}
}, function() {
});
}
(function () {
// Add copy buttons to all the codeblocks.
var codeblocks = document.querySelectorAll('div > pre');
var button = document.createElement('button');
var span = document.createElement('span');
span.innerText = "COPY";
button.appendChild(span);
for (var i of codeblocks) {
var newButton = button.cloneNode(true);
newButton.addEventListener('click', copy_to_clipboard);
i.appendChild(newButton);
}
})();
</script>
{% endblock %}

View file

@ -164,6 +164,26 @@ div.body pre {
border: 1px solid #ac9;
}
div.highlight {
/* For the button to be positionable inside us */
position: relative;
}
div.highlight pre {
padding: 10px;
}
pre button {
position: absolute;
top: 4px;
right: 4px;
opacity: 0;
}
div.highlight pre:hover > button {
opacity: 1;
}
div.body div.admonition, div.body div.impl-detail {
border-radius: 3px;
}