Skip to content

Commit 84a2ab0

Browse files
benediktwernerDylan-DPC
authored andcommitted
Reapply: Move hiding of boring lines into static content (#846) (#1065)
* Move hiding of boring lines into static content (#846) * Fix test for hidden code
1 parent d63ef83 commit 84a2ab0

File tree

4 files changed

+83
-61
lines changed

4 files changed

+83
-61
lines changed

src/renderer/html_handlebars/hbs_renderer.rs

+71-15
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::renderer::{RenderContext, Renderer};
66
use crate::theme::{self, playpen_editor, Theme};
77
use crate::utils;
88

9+
use std::borrow::Cow;
910
use std::collections::BTreeMap;
1011
use std::collections::HashMap;
1112
use std::fs;
@@ -584,6 +585,7 @@ fn fix_code_blocks(html: &str) -> String {
584585
}
585586

586587
fn add_playpen_pre(html: &str, playpen_config: &Playpen) -> String {
588+
let boring_line_regex = Regex::new(r"^(\s*)#(#|.)(.*)$").unwrap();
587589
let regex = Regex::new(r##"((?s)<code[^>]?class="([^"]+)".*?>(.*?)</code>)"##).unwrap();
588590
regex
589591
.replace_all(html, |caps: &Captures<'_>| {
@@ -597,21 +599,51 @@ fn add_playpen_pre(html: &str, playpen_config: &Playpen) -> String {
597599
|| classes.contains("mdbook-runnable")
598600
{
599601
// wrap the contents in an external pre block
600-
if playpen_config.editable && classes.contains("editable")
601-
|| text.contains("fn main")
602-
|| text.contains("quick_main!")
603-
{
604-
format!("<pre class=\"playpen\">{}</pre>", text)
605-
} else {
606-
// we need to inject our own main
607-
let (attrs, code) = partition_source(code);
608-
609-
format!(
610-
"<pre class=\"playpen\"><code class=\"{}\">\n# \
611-
#![allow(unused_variables)]\n{}#fn main() {{\n{}#}}</code></pre>",
612-
classes, attrs, code
613-
)
614-
}
602+
format!(
603+
"<pre class=\"playpen\"><code class=\"{}\">{}</code></pre>",
604+
classes,
605+
{
606+
let content: Cow<'_, str> = if playpen_config.editable
607+
&& classes.contains("editable")
608+
|| text.contains("fn main")
609+
|| text.contains("quick_main!")
610+
{
611+
code.into()
612+
} else {
613+
// we need to inject our own main
614+
let (attrs, code) = partition_source(code);
615+
616+
format!(
617+
"\n# #![allow(unused_variables)]\n{}#fn main() {{\n{}#}}",
618+
attrs, code
619+
)
620+
.into()
621+
};
622+
let mut prev_line_hidden = false;
623+
let mut result = String::with_capacity(content.len());
624+
for line in content.lines() {
625+
if let Some(caps) = boring_line_regex.captures(line) {
626+
if !prev_line_hidden && &caps[2] != "#" {
627+
result += "<span class=\"boring\">";
628+
prev_line_hidden = true;
629+
}
630+
result += &caps[1];
631+
if &caps[2] != " " {
632+
result += &caps[2];
633+
}
634+
result += &caps[3];
635+
} else {
636+
if prev_line_hidden {
637+
result += "</span>";
638+
prev_line_hidden = false;
639+
}
640+
result += line;
641+
}
642+
result += "\n";
643+
}
644+
result
645+
}
646+
)
615647
} else {
616648
// not language-rust, so no-op
617649
text.to_owned()
@@ -687,4 +719,28 @@ mod tests {
687719
assert_eq!(got, should_be);
688720
}
689721
}
722+
723+
#[test]
724+
fn add_playpen() {
725+
let inputs = [
726+
("<code class=\"language-rust\">x()</code>",
727+
"<pre class=\"playpen\"><code class=\"language-rust\">\n<span class=\"boring\">#![allow(unused_variables)]\nfn main() {\n</span>x()\n<span class=\"boring\">}\n</code></pre>"),
728+
("<code class=\"language-rust\">fn main() {}</code>",
729+
"<pre class=\"playpen\"><code class=\"language-rust\">fn main() {}\n</code></pre>"),
730+
("<code class=\"language-rust editable\">let s = \"foo\n # bar\n\";</code>",
731+
"<pre class=\"playpen\"><code class=\"language-rust editable\">let s = \"foo\n<span class=\"boring\"> bar\n</span>\";\n</code></pre>"),
732+
("<code class=\"language-rust editable\">let s = \"foo\n ## bar\n\";</code>",
733+
"<pre class=\"playpen\"><code class=\"language-rust editable\">let s = \"foo\n # bar\n\";\n</code></pre>"),
734+
];
735+
for (src, should_be) in &inputs {
736+
let got = add_playpen_pre(
737+
src,
738+
&Playpen {
739+
editable: true,
740+
..Playpen::default()
741+
},
742+
);
743+
assert_eq!(&*got, *should_be);
744+
}
745+
}
690746
}

src/theme/book.js

+6-44
Original file line numberDiff line numberDiff line change
@@ -170,72 +170,34 @@ function playpen_text(playpen) {
170170

171171
Array.from(document.querySelectorAll("code.language-rust")).forEach(function (block) {
172172

173-
var code_block = block;
174-
var pre_block = block.parentNode;
175-
// hide lines
176-
var lines = code_block.innerHTML.split("\n");
177-
var first_non_hidden_line = false;
178-
var lines_hidden = false;
179-
var trimmed_line = "";
180-
181-
for (var n = 0; n < lines.length; n++) {
182-
trimmed_line = lines[n].trim();
183-
if (trimmed_line[0] == hiding_character && trimmed_line[1] != hiding_character) {
184-
if (first_non_hidden_line) {
185-
lines[n] = "<span class=\"hidden\">" + "\n" + lines[n].replace(/(\s*)# ?/, "$1") + "</span>";
186-
}
187-
else {
188-
lines[n] = "<span class=\"hidden\">" + lines[n].replace(/(\s*)# ?/, "$1") + "\n" + "</span>";
189-
}
190-
lines_hidden = true;
191-
}
192-
else if (first_non_hidden_line) {
193-
lines[n] = "\n" + lines[n];
194-
}
195-
else {
196-
first_non_hidden_line = true;
197-
}
198-
if (trimmed_line[0] == hiding_character && trimmed_line[1] == hiding_character) {
199-
lines[n] = lines[n].replace("##", "#")
200-
}
201-
}
202-
code_block.innerHTML = lines.join("");
203-
173+
var lines = Array.from(block.querySelectorAll('.boring'));
204174
// If no lines were hidden, return
205-
if (!lines_hidden) { return; }
175+
if (!lines.length) { return; }
176+
block.classList.add("hide-boring");
206177

207178
var buttons = document.createElement('div');
208179
buttons.className = 'buttons';
209180
buttons.innerHTML = "<button class=\"fa fa-expand\" title=\"Show hidden lines\" aria-label=\"Show hidden lines\"></button>";
210181

211182
// add expand button
183+
var pre_block = block.parentNode;
212184
pre_block.insertBefore(buttons, pre_block.firstChild);
213185

214186
pre_block.querySelector('.buttons').addEventListener('click', function (e) {
215187
if (e.target.classList.contains('fa-expand')) {
216-
var lines = pre_block.querySelectorAll('span.hidden');
217-
218188
e.target.classList.remove('fa-expand');
219189
e.target.classList.add('fa-compress');
220190
e.target.title = 'Hide lines';
221191
e.target.setAttribute('aria-label', e.target.title);
222192

223-
Array.from(lines).forEach(function (line) {
224-
line.classList.remove('hidden');
225-
line.classList.add('unhidden');
226-
});
193+
block.classList.remove('hide-boring');
227194
} else if (e.target.classList.contains('fa-compress')) {
228-
var lines = pre_block.querySelectorAll('span.unhidden');
229-
230195
e.target.classList.remove('fa-compress');
231196
e.target.classList.add('fa-expand');
232197
e.target.title = 'Show hidden lines';
233198
e.target.setAttribute('aria-label', e.target.title);
234199

235-
Array.from(lines).forEach(function (line) {
236-
line.classList.remove('unhidden');
237-
line.classList.add('hidden');
238-
});
200+
block.classList.add('hide-boring');
239201
}
240202
});
241203
});

src/theme/css/general.css

+2-1
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ code {
2222

2323
.left { float: left; }
2424
.right { float: right; }
25+
.boring { opacity: 0.6; }
26+
.hide-boring .boring { display: none; }
2527
.hidden { display: none; }
26-
.play-button.hidden { display: none; }
2728

2829
h2, h3 { margin-top: 2.5em; }
2930
h4, h5 { margin-top: 2em; }

tests/rendered_output.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,10 @@ fn rustdoc_include_hides_the_unspecified_part_of_the_file() {
168168
md.build().unwrap();
169169

170170
let nested = temp.path().join("book/first/nested.html");
171-
let text = vec!["# fn some_function() {", "# fn some_other_function() {"];
171+
let text = vec![
172+
"<span class=\"boring\">fn some_function() {",
173+
"<span class=\"boring\">fn some_other_function() {",
174+
];
172175

173176
assert_contains_strings(nested, &text);
174177
}

0 commit comments

Comments
 (0)