Skip to content

Add "copy to clipboard" for all code blocks and "expand" buttons #86892

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

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 74 additions & 13 deletions src/librustdoc/html/highlight.rs
Original file line number Diff line number Diff line change
@@ -9,15 +9,17 @@ use crate::clean::PrimitiveType;
use crate::html::escape::Escape;
use crate::html::render::Context;

use std::fmt::{Display, Write};
use std::iter::Peekable;
use std::borrow::Cow;
use std::fmt::{Debug, Display, Write};
use std::iter::{once, Peekable};

use rustc_lexer::{LiteralKind, TokenKind};
use rustc_span::edition::Edition;
use rustc_span::symbol::Symbol;
use rustc_span::{BytePos, Span, DUMMY_SP};

use super::format::{self, Buffer};
use super::markdown::Line;
use super::render::LinkFromSrc;

/// This type is needed in case we want to render links on items to allow to go to their definition.
@@ -31,7 +33,7 @@ crate struct ContextInfo<'a, 'b, 'c> {
}

/// Highlights `src`, returning the HTML output.
crate fn render_with_highlighting(
crate fn render_source_with_highlighting(
src: &str,
out: &mut Buffer,
class: Option<&str>,
@@ -41,7 +43,31 @@ crate fn render_with_highlighting(
extra_content: Option<Buffer>,
context_info: Option<ContextInfo<'_, '_, '_>>,
) {
debug!("highlighting: ================\n{}\n==============", src);
render_with_highlighting(
once(Line::Shown(Cow::Borrowed(src))),
out,
class,
playground_button,
tooltip,
edition,
extra_content,
context_info,
)
}

/// Highlights `src` containing potential hidden lines, returning the HTML output. If you don't have
/// hidden lines, use [`render_source_with_highlighting`] instead.
crate fn render_with_highlighting<'a>(
src: impl Iterator<Item = Line<'a>> + Debug,
out: &mut Buffer,
class: Option<&str>,
playground_button: Option<&str>,
tooltip: Option<(Option<Edition>, &str)>,
edition: Edition,
extra_content: Option<Buffer>,
context_info: Option<ContextInfo<'_, '_, '_>>,
) {
debug!("highlighting: ================\n{:?}\n==============", src);
if let Some((edition_info, class)) = tooltip {
write!(
out,
@@ -56,8 +82,8 @@ crate fn render_with_highlighting(
}

write_header(out, class, extra_content);
write_code(out, &src, edition, context_info);
write_footer(out, playground_button);
let expand = write_code(out, src, edition, context_info);
write_footer(out, playground_button, expand);
}

fn write_header(out: &mut Buffer, class: Option<&str>, extra_content: Option<Buffer>) {
@@ -86,24 +112,59 @@ fn write_header(out: &mut Buffer, class: Option<&str>, extra_content: Option<Buf
/// More explanations about spans and how we use them here are provided in the
fn write_code(
out: &mut Buffer,
src: &str,
src: impl Iterator<Item = Line<'a>>,
edition: Edition,
context_info: Option<ContextInfo<'_, '_, '_>>,
) {
// This replace allows to fix how the code source with DOS backline characters is displayed.
let src = src.replace("\r\n", "\n");
Classifier::new(&src, edition, context_info.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP))
) -> bool {
let mut iter = src.peekable();
let mut expand = false;

// For each `Line`, we replace DOS backlines with '\n'. This replace allows to fix how the code
// source with DOS backline characters is displayed.
while let Some(line) = iter.next() {
let (before, text, after) = match line {
Line::Hidden(text) => {
expand = true;
("<span class=\"hidden\">", text.replace("\r\n", "\n"), "</span>")
}
Line::Shown(text) => ("", text.replace("\r\n", "\n"), ""),
};
if !before.is_empty() {
out.push_str(before);
}
Classifier::new(
&text.replace("\r\n", "\n"),
edition,
context_info.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP),
)
.highlight(&mut |highlight| {
match highlight {
Highlight::Token { text, class } => string(out, Escape(text), class, &context_info),
Highlight::EnterSpan { class } => enter_span(out, class),
Highlight::ExitSpan => exit_span(out),
};
});
if iter.peek().is_some() && !text.ends_with('\n') {
out.push_str("\n");
}
if !after.is_empty() {
out.push_str(after);
}
}
expand
}

fn write_footer(out: &mut Buffer, playground_button: Option<&str>) {
writeln!(out, "</code></pre>{}</div>", playground_button.unwrap_or_default());
fn write_footer(out: &mut Buffer, playground_button: Option<&str>, expand: bool) {
writeln!(
out,
"</code></pre>\
<div class=\"code-buttons\">\
{}{}<button class=\"copy-code\" onclick=\"copyCode(this)\"></button>\
</div>\
</div>",
playground_button.unwrap_or_default(),
if expand { "<button class=\"expand\" onclick=\"expandCode(this)\"></button>" } else { "" },
);
}

/// How a span of text is classified. Mostly corresponds to token kinds.
7 changes: 7 additions & 0 deletions src/librustdoc/html/highlight/tests.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
use super::write_code;
use crate::html::format::Buffer;
use crate::html::markdown::Line;
use expect_test::expect_file;
use rustc_span::create_default_session_globals_then;
use rustc_span::edition::Edition;

use std::borrow::Cow;
use std::iter::once;

const STYLE: &str = r#"
<style>
.kw { color: #8959A8; }
@@ -20,6 +24,7 @@ const STYLE: &str = r#"
fn test_html_highlighting() {
create_default_session_globals_then(|| {
let src = include_str!("fixtures/sample.rs");
let src = once(Line::Shown(Cow::Borrowed(src)));
let html = {
let mut out = Buffer::new();
write_code(&mut out, src, Edition::Edition2018, None);
@@ -35,6 +40,7 @@ fn test_dos_backline() {
let src = "pub fn foo() {\r\n\
println!(\"foo\");\r\n\
}\r\n";
let src = once(Line::Shown(Cow::Borrowed(src)));
let mut html = Buffer::new();
write_code(&mut html, src, Edition::Edition2018, None);
expect_file!["fixtures/dos_line.html"].assert_eq(&html.into_inner());
@@ -49,6 +55,7 @@ use self::whatever;
let x = super::b::foo;
let y = Self::whatever;";

let src = once(Line::Shown(Cow::Borrowed(src)));
let mut html = Buffer::new();
write_code(&mut html, src, Edition::Edition2018, None);
expect_file!["fixtures/highlight.html"].assert_eq(&html.into_inner());
19 changes: 6 additions & 13 deletions src/librustdoc/html/markdown.rs
Original file line number Diff line number Diff line change
@@ -123,20 +123,14 @@ impl ErrorCodes {
/// Controls whether a line will be hidden or shown in HTML output.
///
/// All lines are used in documentation tests.
enum Line<'a> {
#[derive(Debug)]
crate enum Line<'a> {
Hidden(&'a str),
Shown(Cow<'a, str>),
}

impl<'a> Line<'a> {
fn for_html(self) -> Option<Cow<'a, str>> {
match self {
Line::Shown(l) => Some(l),
Line::Hidden(_) => None,
}
}

fn for_code(self) -> Cow<'a, str> {
crate fn for_code(self) -> Cow<'a, str> {
match self {
Line::Shown(l) => l,
Line::Hidden(l) => Cow::Borrowed(l),
@@ -229,8 +223,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
_ => {}
}
}
let lines = origtext.lines().filter_map(|l| map_line(l).for_html());
let text = lines.collect::<Vec<Cow<'_, str>>>().join("\n");
let lines = origtext.lines().map(map_line);

let parse_result = match kind {
CodeBlockKind::Fenced(ref lang) => {
@@ -243,7 +236,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
<pre class=\"language-{}\"><code>{}</code></pre>\
</div>",
lang,
Escape(&text),
Escape(&origtext),
)
.into(),
));
@@ -326,7 +319,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
let mut s = Buffer::new();
s.push_str("\n");
highlight::render_with_highlighting(
&text,
lines,
&mut s,
Some(&format!(
"rust-example-rendered{}",
2 changes: 1 addition & 1 deletion src/librustdoc/html/render/print_item.rs
Original file line number Diff line number Diff line change
@@ -1115,7 +1115,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum

fn item_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Macro) {
wrap_into_docblock(w, |w| {
highlight::render_with_highlighting(
highlight::render_source_with_highlighting(
&t.source,
w,
Some("macro"),
9 changes: 9 additions & 0 deletions src/librustdoc/html/render/write_shared.rs
Original file line number Diff line number Diff line change
@@ -179,6 +179,7 @@ pub(super) fn write_shared(
cx.write_shared(SharedResource::InvocationSpecific { basename: p }, content, &options.emit)
};

// This is required because the name of the image changes based on the current toolchain.
fn add_background_image_to_css(
cx: &Context<'_>,
css: &mut String,
@@ -218,6 +219,12 @@ pub(super) fn write_shared(

// Add all the static files. These may already exist, but we just
// overwrite them anyway to make sure that they're fresh and up-to-date.
let mut rustdoc_css = static_files::RUSTDOC_CSS.to_owned();
add_background_image_to_css(cx, &mut rustdoc_css, ".copy-code", "clipboard.svg");
add_background_image_to_css(cx, &mut rustdoc_css, ".expand", "eye.svg");
add_background_image_to_css(cx, &mut rustdoc_css, ".collapse", "eye-slash.svg");
write_minify("rustdoc.css", rustdoc_css, cx, options)?;

write_minify("settings.css", static_files::SETTINGS_CSS, cx, options)?;
write_minify("noscript.css", static_files::NOSCRIPT_CSS, cx, options)?;

@@ -259,6 +266,8 @@ pub(super) fn write_shared(
write_toolchain("down-arrow.svg", static_files::DOWN_ARROW_SVG)?;
write_toolchain("toggle-minus.svg", static_files::TOGGLE_MINUS_PNG)?;
write_toolchain("toggle-plus.svg", static_files::TOGGLE_PLUS_PNG)?;
write_toolchain("eye.svg", static_files::EXPAND_SVG)?;
write_toolchain("eye-slash.svg", static_files::COLLAPSE_SVG)?;

let mut themes: Vec<&String> = themes.iter().collect();
themes.sort();
2 changes: 1 addition & 1 deletion src/librustdoc/html/sources.rs
Original file line number Diff line number Diff line change
@@ -264,7 +264,7 @@ fn print_src(
writeln!(line_numbers, "<span id=\"{0}\">{0:1$}</span>", i, cols);
}
line_numbers.write_str("</pre>");
highlight::render_with_highlighting(
highlight::render_source_with_highlighting(
s,
buf,
None,
2 changes: 1 addition & 1 deletion src/librustdoc/html/static/css/noscript.css
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ rules.
margin-left: 0 !important;
}

#copy-path {
#copy-path, .copy-code, .expand, .collapse {
/* It requires JS to work so no need to display it in this case. */
display: none;
}
34 changes: 27 additions & 7 deletions src/librustdoc/html/static/css/rustdoc.css
Original file line number Diff line number Diff line change
@@ -190,7 +190,8 @@ details.undocumented > summary::before,
div.impl-items > div:not(.docblock):not(.item-info),
.content ul.crate a.crate, a.srclink,
/* This selector is for the items listed in the "all items" page. */
#main > ul.docblock > li > a {
#main > ul.docblock > li > a,
.copy-code {
font-family: "Fira Sans", Arial, sans-serif;
}

@@ -240,7 +241,7 @@ details:not(.rustdoc-toggle) summary {
margin-bottom: .6em;
}

code, pre, a.test-arrow, .code-header {
code, pre, div.code-buttons, .code-header {
font-family: "Source Code Pro", monospace;
}
.docblock code, .docblock-short code {
@@ -1039,19 +1040,33 @@ pre.rust .question-mark {
font-weight: bold;
}

a.test-arrow {
display: inline-block;
.code-buttons {
display: flex;
position: absolute;
padding: 5px 10px 5px 10px;
border-radius: 5px;
font-size: 130%;
top: 5px;
right: 5px;
z-index: 1;
font-size: 130%;
}
a.test-arrow {
border-radius: 5px;
padding: 5px 10px 5px 10px;
display: inline-block;
}
a.test-arrow:hover{
text-decoration: none;
}
.copy-code, .expand, .collapse {
width: 21px;
background-size: contain;
background-color: transparent;
background-repeat: no-repeat;
border: 0;
background-position: center;
border-radius: 4px;
cursor: pointer;
margin-left: 7px;
}

.section-header:hover a:before {
position: absolute;
@@ -1242,6 +1257,11 @@ pre.rust {
-moz-tab-size: 4;
}

pre .data-hidden {
width: 100%;
display: block;
}

.search-failed {
text-align: center;
margin-top: 20px;
13 changes: 12 additions & 1 deletion src/librustdoc/html/static/css/themes/ayu.css
Original file line number Diff line number Diff line change
@@ -57,6 +57,10 @@ pre, .rustdoc.source .example-wrap {
background-color: #191f26;
}

pre .data-hidden {
background-color: #313942;
}

.sidebar {
background-color: #14191f;
}
@@ -331,12 +335,19 @@ a.test-arrow {
border-radius: 4px;
background-color: rgba(57, 175, 215, 0.09);
}

a.test-arrow:hover {
background-color: rgba(57, 175, 215, 0.368);
color: #c5c5c5;
}

.copy-code, .expand, .collapse {
filter: invert(70%);
color: #fff;
}
.copy-code:hover, .expand:hover, .collapse:hover {
filter: invert(100%);
}

.toggle-label,
.code-attribute {
color: #999;
11 changes: 11 additions & 0 deletions src/librustdoc/html/static/css/themes/dark.css
Original file line number Diff line number Diff line change
@@ -28,6 +28,10 @@ pre, .rustdoc.source .example-wrap {
background-color: #2A2A2A;
}

pre .data-hidden {
background-color: #373636;
}

.sidebar {
background-color: #505050;
}
@@ -190,6 +194,13 @@ body.source .example-wrap pre.rust a {
a.test-arrow {
color: #dedede;
}
.copy-code, .expand, .collapse {
filter: invert(50%);
color: #999;
}
.copy-code:hover, .expand:hover, .collapse:hover {
filter: invert(65%);
}

details.rustdoc-toggle > summary.hideme > span,
details.rustdoc-toggle > summary::before,
11 changes: 11 additions & 0 deletions src/librustdoc/html/static/css/themes/light.css
Original file line number Diff line number Diff line change
@@ -30,6 +30,10 @@ pre, .rustdoc.source .example-wrap {
background-color: #F5F5F5;
}

pre .data-hidden {
background-color: #E6E4E4;
}

.sidebar {
background-color: #F1F1F1;
}
@@ -185,6 +189,13 @@ body.source .example-wrap pre.rust a {
a.test-arrow {
color: #f5f5f5;
}
.copy-code, .expand, .collapse {
filter: invert(50%);
color: #999;
}
.copy-code:hover, .expand:hover, .collapse:hover {
filter: invert(35%);
}

details.rustdoc-toggle > summary.hideme > span,
details.rustdoc-toggle > summary::before,
1 change: 1 addition & 0 deletions src/librustdoc/html/static/eye-slash.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/librustdoc/html/static/eye.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
240 changes: 162 additions & 78 deletions src/librustdoc/html/static/js/main.js
Original file line number Diff line number Diff line change
@@ -822,41 +822,50 @@ function hideThemeButtonState() {
}
}());

(function() {
// To avoid checking on "rustdoc-line-numbers" value on every loop...
var lineNumbersFunc = function() {};
if (getSettingValue("line-numbers") === "true") {
lineNumbersFunc = function(x) {
var count = x.textContent.split("\n").length;
var elems = [];
for (var i = 0; i < count; ++i) {
elems.push(i + 1);
// To avoid checking on "rustdoc-line-numbers" value on every loop...
var lineNumbersFunc = function() {};
if (getSettingValue("line-numbers") === "true") {
lineNumbersFunc = function(x) {
var count = 0;
var last = "";
onEachLazy(x.getElementsByTagName("code")[0].childNodes, function(e) {
if (e.nodeType !== Node.TEXT_NODE && hasClass(e, "hidden")) {
return;
}
var node = document.createElement("pre");
addClass(node, "line-number");
node.innerHTML = elems.join("\n");
x.parentNode.insertBefore(node, x);
};
}
onEachLazy(document.getElementsByClassName("rust-example-rendered"), function(e) {
if (hasClass(e, "compile_fail")) {
e.addEventListener("mouseover", function() {
this.parentElement.previousElementSibling.childNodes[0].style.color = "#f00";
});
e.addEventListener("mouseout", function() {
this.parentElement.previousElementSibling.childNodes[0].style.color = "";
});
} else if (hasClass(e, "ignore")) {
e.addEventListener("mouseover", function() {
this.parentElement.previousElementSibling.childNodes[0].style.color = "#ff9200";
});
e.addEventListener("mouseout", function() {
this.parentElement.previousElementSibling.childNodes[0].style.color = "";
});
count += e.textContent.split("\n").length - 1;
last = e.textContent;
});
if (!last.endsWith("\n")) {
count += 1;
}
lineNumbersFunc(e);
});
}());
var elems = [];
for (var i = 0; i < count; ++i) {
elems.push(i + 1);
}
var node = document.createElement("pre");
addClass(node, "line-number");
node.innerHTML = elems.join("\n");
x.parentNode.insertBefore(node, x);
};
}
onEachLazy(document.getElementsByClassName("rust-example-rendered"), function(e) {
if (hasClass(e, "compile_fail")) {
e.addEventListener("mouseover", function() {
this.parentElement.previousElementSibling.childNodes[0].style.color = "#f00";
});
e.addEventListener("mouseout", function() {
this.parentElement.previousElementSibling.childNodes[0].style.color = "";
});
} else if (hasClass(e, "ignore")) {
e.addEventListener("mouseover", function() {
this.parentElement.previousElementSibling.childNodes[0].style.color = "#ff9200";
});
e.addEventListener("mouseout", function() {
this.parentElement.previousElementSibling.childNodes[0].style.color = "";
});
}
lineNumbersFunc(e);
});

function handleClick(id, f) {
var elem = document.getElementById(id);
@@ -970,60 +979,135 @@ function hideThemeButtonState() {
onHashChange(null);
window.addEventListener("hashchange", onHashChange);
searchState.setup();
}());

(function () {
var reset_button_timeout = null;
(function () {
var buttons_timeout = new WeakMap();

function copyContentToClipboard(content) {
var el = document.createElement('textarea');
el.value = content;
el.setAttribute('readonly', '');
// To not make it appear on the screen.
el.style.position = 'absolute';
el.style.left = '-9999px';

document.body.appendChild(el);
el.select();
document.execCommand('copy');
document.body.removeChild(el);
}

window.copy_path = function(but) {
var parent = but.parentElement;
var path = [];

onEach(parent.childNodes, function(child) {
if (child.tagName === 'A') {
path.push(child.textContent);
}
});

copyContentToClipboard(path.join('::'));

// There is always one children, but multiple childNodes.
but.children[0].style.display = 'none';

var tmp;
if (but.childNodes.length < 2) {
tmp = document.createTextNode('✓');
but.appendChild(tmp);
} else {
onEachLazy(but.childNodes, function(e) {
if (e.nodeType === Node.TEXT_NODE) {
tmp = e;
return true;
}
});
tmp.textContent = '✓';
}

window.copy_path = function(but) {
var parent = but.parentElement;
var path = [];
if (buttons_timeout.has(but)) {
window.clearTimeout(buttons_timeout.get(but));
}

onEach(parent.childNodes, function(child) {
if (child.tagName === 'A') {
path.push(child.textContent);
function reset_button() {
tmp.textContent = '';
buttons_timeout.delete(but);
but.children[0].style.display = "";
}
});

var el = document.createElement('textarea');
el.value = path.join('::');
el.setAttribute('readonly', '');
// To not make it appear on the screen.
el.style.position = 'absolute';
el.style.left = '-9999px';

document.body.appendChild(el);
el.select();
document.execCommand('copy');
document.body.removeChild(el);

// There is always one children, but multiple childNodes.
but.children[0].style.display = 'none';

var tmp;
if (but.childNodes.length < 2) {
tmp = document.createTextNode('✓');
but.appendChild(tmp);
} else {
onEachLazy(but.childNodes, function(e) {
if (e.nodeType === Node.TEXT_NODE) {
tmp = e;
return true;
buttons_timeout.set(but, window.setTimeout(reset_button, 1000));
};

// This part is for the code blocks buttons.
window.copyCode = function(but) {
var code = but.parentElement.previousElementSibling;
var text = "";
onEachLazy(code.childNodes, function(e) {
if (e.nodeType !== Node.TEXT_NODE && hasClass(e, "hidden")) {
return;
}
text += e.textContent;
});
tmp.textContent = '✓';
}

if (reset_button_timeout !== null) {
window.clearTimeout(reset_button_timeout);
}
copyContentToClipboard(text);

removeClass(but, 'clicked');
addClass(but, 'clicked');

function reset_button() {
tmp.textContent = '';
reset_button_timeout = null;
but.children[0].style.display = "";
if (buttons_timeout.has(but)) {
window.clearTimeout(buttons_timeout.get(but));
}

var tmp;
if (but.childNodes.length < 1) {
tmp = document.createTextNode('✓');
but.appendChild(tmp);
} else {
tmp = but.childNodes[0];
tmp.textContent = '✓';
}
but.style.backgroundSize = '0';

if (buttons_timeout.has(but)) {
window.clearTimeout(buttons_timeout.get(but));
}

function reset_button() {
but.style.backgroundSize = '';
tmp.textContent = '';
buttons_timeout.delete(but);
}

buttons_timeout.set(but, window.setTimeout(reset_button, 1000));
};

function removeLineNumbers(but) {
onEachLazy(but.getElementsByClassName("line-number"), function(e) {
e.parentElement.removeChild(e);
});
}

reset_button_timeout = window.setTimeout(reset_button, 1000);
};
window.expandCode = function(but) {
var code = but.parentElement.previousElementSibling;
if (hasClass(but, "expand")) {
onEachLazy(code.getElementsByClassName("hidden"), function(e) {
removeClass(e, "hidden");
addClass(e, "data-hidden");
});
removeClass(but, "expand");
addClass(but, "collapse");
} else {
onEachLazy(code.getElementsByClassName("data-hidden"), function(e) {
removeClass(e, "data-hidden");
addClass(e, "hidden");
});
removeClass(but, "collapse");
addClass(but, "expand");
}
// We recompute the line numbers display.
removeLineNumbers(code.parentElement);
lineNumbersFunc(code);
};
}());
}());
6 changes: 6 additions & 0 deletions src/librustdoc/html/static_files.rs
Original file line number Diff line number Diff line change
@@ -53,6 +53,12 @@ crate static TOGGLE_MINUS_PNG: &[u8] = include_bytes!("static/images/toggle-minu
/// The file contents of `toggle-plus.svg`, the icon used for closed toggles.
crate static TOGGLE_PLUS_PNG: &[u8] = include_bytes!("static/images/toggle-plus.svg");

/// The file contents of `expand.svg`, the icon used to show hidden code blocks lines.
crate static EXPAND_SVG: &[u8] = include_bytes!("static/eye.svg");

/// The file contents of `collapse.svg`, the icon used to collapse hidden code blocks lines.
crate static COLLAPSE_SVG: &[u8] = include_bytes!("static/eye-slash.svg");

/// The contents of `COPYRIGHT.txt`, the license listing for files distributed with documentation
/// output.
crate static COPYRIGHT: &[u8] = include_bytes!("static/COPYRIGHT.txt");
30 changes: 30 additions & 0 deletions src/test/rustdoc-gui/code_block_lines.goml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
goto: file://|DOC_PATH|/lib2/trait.Trait.html
// We set the parameter to display line numbers on code blocks.
local-storage: {"rustdoc-line-numbers": "true"}
// We reload the page so they're displayed.
reload:
wait-for: ".line-number"
assert: ".top-doc .line-number"
assert-text: (".top-doc .line-number", "1\n2\n3\n4")
// We check that the hidden content is present
assert: ".top-doc .rust-example-rendered span.hidden"
assert-text: (".top-doc .rust-example-rendered span.hidden", "fn main() {\n")
assert-text: (".methods .line-number", "1\n2\n3\n4\n5\n6\n7")

// Now we check the collapse/expand feature.
assert: ".top-doc .expand"
assert-false: ".top-doc .collapse"
click: ".top-doc .expand"
assert-text: (".top-doc .line-number", "1\n2\n3\n4\n5\n6\n7")
assert: ".top-doc .collapse"
assert-false: ".top-doc .expand"
click: ".top-doc .collapse"
assert-text: (".top-doc .line-number", "1\n2\n3\n4")
assert: ".top-doc .expand"
assert-false: ".top-doc .collapse"
// We now check that the button isn't present if there is no hidden lines.
assert-false: ".methods .expand"
assert-false: ".methods .collapse"

// We unset the parameter to be sure it won't affect other tests.
local-storage: {"rustdoc-line-numbers": ""}
20 changes: 20 additions & 0 deletions src/test/rustdoc-gui/src/lib2/lib.rs
Original file line number Diff line number Diff line change
@@ -25,10 +25,30 @@ impl Foo {
pub fn a_method(&self) {}
}

// This is used to ensure the line numbers are correctly set.
/// ```
/// # fn main() {
/// let x = 12;
/// let y = 13;
/// # let z = 14;
///
/// println!("hello");
/// # }
/// ```
pub trait Trait {
type X;
const Y: u32;

// This is used to ensure the line numbers are correctly set.
/// ```
/// fn main() {
/// let x = 12;
/// let y = 13;
/// let z = 14;
///
/// println!("hello");
/// }
/// ```
fn foo() {}
}

4 changes: 3 additions & 1 deletion src/test/rustdoc/hidden-line.rs
Original file line number Diff line number Diff line change
@@ -15,5 +15,7 @@
/// ```
pub fn foo() {}

// @!has hidden_line/fn.foo.html invisible
// @has hidden_line/fn.foo.html
// @has - '//span[@class="hidden"]' '#[derive(PartialEq)] // invisible'
// @has - '//span[@class="hidden"]' 'struct Foo; // invisible'
// @matches - //pre "#\[derive\(PartialEq\)\] // Bar"
4 changes: 2 additions & 2 deletions src/test/rustdoc/issue-41783.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @has issue_41783/struct.Foo.html
// @!has - 'space'
// @!has - 'comment'
// @has - '//span[@class="hidden"]' 'space'
// @has - '//span[@class="hidden"]' 'comment'
// @has - '# <span class="ident">single'
// @has - '## <span class="ident">double</span>'
// @has - '### <span class="ident">triple</span>'