Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add copy code to clipboard button for rustdoc #119929

Closed
wants to merge 9 commits into from
8 changes: 8 additions & 0 deletions src/librustdoc/html/markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ use crate::html::highlight;
use crate::html::length_limit::HtmlWithLimit;
use crate::html::render::small_url_encode;
use crate::html::toc::TocBuilder;
use crate::html::static_files;
use crate::html::layout::Page;

use pulldown_cmark::{
html, BrokenLink, CodeBlockKind, CowStr, Event, LinkType, OffsetIter, Options, Parser, Tag,
Expand Down Expand Up @@ -270,9 +272,15 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
format!(
"<div class=\"example-wrap\">\
<pre class=\"{lang_string}{whitespace}{added_classes}\">\
<button class=\"copy-code\">
<img src=\"{static_root_path}{clipboard_svg}\" width=\"15\" height=\"15\"\
alt=\"Copy to clipboard\">\
</button>\
<code>{text}</code>\
</pre>\
</div>",
static_root_path = &get_static_root_path(),
clipboard_svg = &static_files::STATIC_FILES.clipboard_svg,
added_classes = added_classes.join(" "),
text = Escape(&original_text),
)
Expand Down
5 changes: 4 additions & 1 deletion src/librustdoc/html/sources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::error::Error;
use crate::html::format;
use crate::html::highlight;
use crate::html::layout;
use crate::html::Page;
use crate::html::render::Context;
use crate::visit::DocVisitor;

Expand Down Expand Up @@ -315,6 +316,7 @@ pub(crate) fn print_src(
needs_expansion: bool,
lines: RangeInclusive<usize>,
code_html: Code,
static_root_path: &'a str,
}
let lines = s.lines().count();
let (embedded, needs_expansion, lines) = match source_context {
Expand All @@ -335,5 +337,6 @@ pub(crate) fn print_src(
);
Ok(())
});
Source { embedded, needs_expansion, lines, code_html: code }.render_into(&mut writer).unwrap();
let static_root_path = get_static_root_path();
Source { embedded, needs_expansion, lines, code_html: code, static_root_path }.render_into(&mut writer).unwrap();
}
2 changes: 1 addition & 1 deletion src/librustdoc/html/static/css/noscript.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ rules.
margin-left: 0 !important;
}

#copy-path, #sidebar-button, .sidebar-resizer {
#copy-path, #sidebar-button, .sidebar-resizer, .copy-code {
/* It requires JS to work so no need to display it in this case. */
display: none !important;
}
Expand Down
21 changes: 21 additions & 0 deletions src/librustdoc/html/static/css/rustdoc.css
Original file line number Diff line number Diff line change
Expand Up @@ -1596,6 +1596,24 @@ a.tooltip:hover::after {
height: 22px;
}

.copy-code {
width: 32px;
height: 30px;
float: right;
opacity: 0;
transition: opacity ease 0.3s;
background: var(--code-block-background-color);
outline: 1px solid var(--main-color);
border-radius: 5px;
padding: 5px 7px 4px 8px;
z-index: 1;
position: sticky;
}

.copy-code > img {
filter: var(--copy-code-img-filter);
}

#copy-path {
color: var(--copy-path-button-color);
background: var(--main-background-color);
Expand Down Expand Up @@ -2329,6 +2347,7 @@ in src-script.js and main.js
--copy-path-button-color: #999;
--copy-path-img-filter: invert(50%);
--copy-path-img-hover-filter: invert(35%);
--copy-code-img-filter: invert(20%);
--codeblock-error-hover-color: rgb(255, 0, 0);
--codeblock-error-color: rgba(255, 0, 0, .5);
--codeblock-ignore-hover-color: rgb(255, 142, 0);
Expand Down Expand Up @@ -2434,6 +2453,7 @@ in src-script.js and main.js
--copy-path-button-color: #999;
--copy-path-img-filter: invert(50%);
--copy-path-img-hover-filter: invert(65%);
--copy-code-img-filter: invert(50%);
--codeblock-error-hover-color: rgb(255, 0, 0);
--codeblock-error-color: rgba(255, 0, 0, .5);
--codeblock-ignore-hover-color: rgb(255, 142, 0);
Expand Down Expand Up @@ -2546,6 +2566,7 @@ Original by Dempfi (https://github.com/dempfi/ayu)
--copy-path-button-color: #fff;
--copy-path-img-filter: invert(70%);
--copy-path-img-hover-filter: invert(100%);
--copy-code-img-filter: invert(50%);
--codeblock-error-hover-color: rgb(255, 0, 0);
--codeblock-error-color: rgba(255, 0, 0, .5);
--codeblock-ignore-hover-color: rgb(255, 142, 0);
Expand Down
31 changes: 31 additions & 0 deletions src/librustdoc/html/static/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -1734,6 +1734,37 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
resizer.addEventListener("pointerdown", initResize, false);
}());

// This section handles the copy buttons that appears in top right corner of the code blocks
(function() {
let preElements = document.querySelectorAll("pre:has(code)");
Copy link
Member

@fmease fmease Jan 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:has is not supported in Firefox Mobile: https://caniuse.com/css-has

preElements.forEach(function(pre, index) {
let resetTimeout = null;
let copyBtn = pre.querySelector("button[class='copy-code']");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let copyBtn = pre.querySelector("button[class='copy-code']");
let copyBtn = pre.querySelector("button.copy-code");

let icon = copyBtn.innerHTML;
pre.addEventListener("mouseenter", function() {
copyBtn.style.opacity = "1";
Copy link
Member

@fmease fmease Jan 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be able to express this in pure CSS with:

pre:hover > button.copy-code { opacity: 1; }

copyBtn.addEventListener("click", function() {
let code = pre.querySelector("code");
let summary = code.querySelector("summary");
let content = code.textContent;
content = content.replace(summary.textContent, "");
navigator.clipboard.writeText(content).then(function() {
copyBtn.textContent = "✓";
if (resetTimeout !== null) {
clearTimeout(resetTimeout);
}
resetTimeout = setTimeout(function() {
copyBtn.innerHTML = icon;
}, 1000);
});
});
});
pre.addEventListener("mouseleave", function() {
copyBtn.style.opacity = "0";
});
});
}());

// This section handles the copy button that appears next to the path breadcrumbs
(function() {
let reset_button_timeout = null;
Expand Down
5 changes: 5 additions & 0 deletions src/librustdoc/html/templates/source.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@
{% endfor %}
</pre></div> {# #}
<pre class="rust"> {# #}
<button class="copy-code" title="Copy to clipboard"> {# #}
<img src="{{static_root_path|safe}}{{files.clipboard_svg}}" {#+ #}
width="15" height="15" {#+ #}
alt="Copy to clipboard"> {# #}
</button> {# #}
<code>
{% if needs_expansion %}
<button class="expand">&varr;</button>
Expand Down
Loading