Support hidden lines in languages other than Rust
Co-Authored-By: thecodewarrior <5467669+thecodewarrior@users.noreply.github.com>
This commit is contained in:
parent
3a51abfcad
commit
7df1d8c838
|
@ -17,6 +17,9 @@ edit-url-template = "https://github.com/rust-lang/mdBook/edit/master/guide/{path
|
||||||
editable = true
|
editable = true
|
||||||
line-numbers = true
|
line-numbers = true
|
||||||
|
|
||||||
|
[output.html.code.hidelines]
|
||||||
|
python = "~"
|
||||||
|
|
||||||
[output.html.search]
|
[output.html.search]
|
||||||
limit-results = 20
|
limit-results = 20
|
||||||
use-boolean-and = true
|
use-boolean-and = true
|
||||||
|
|
|
@ -223,6 +223,17 @@ runnable = true # displays a run button for rust code
|
||||||
|
|
||||||
[Ace]: https://ace.c9.io/
|
[Ace]: https://ace.c9.io/
|
||||||
|
|
||||||
|
### `[output.html.code]`
|
||||||
|
|
||||||
|
The `[output.html.code]` table provides options for controlling code blocks.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[output.html.code]
|
||||||
|
# A prefix string per language (one or more chars).
|
||||||
|
# Any line starting with whitespace+prefix is hidden.
|
||||||
|
hidelines = { python = "~" }
|
||||||
|
```
|
||||||
|
|
||||||
### `[output.html.search]`
|
### `[output.html.search]`
|
||||||
|
|
||||||
The `[output.html.search]` table provides options for controlling the built-in text [search].
|
The `[output.html.search]` table provides options for controlling the built-in text [search].
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
There is a feature in mdBook that lets you hide code lines by prepending them
|
There is a feature in mdBook that lets you hide code lines by prepending them
|
||||||
with a `#` [like you would with Rustdoc][rustdoc-hide].
|
with a `#` [like you would with Rustdoc][rustdoc-hide].
|
||||||
This currently only works with Rust language code blocks.
|
|
||||||
|
|
||||||
[rustdoc-hide]: https://doc.rust-lang.org/stable/rustdoc/documentation-tests.html#hiding-portions-of-the-example
|
[rustdoc-hide]: https://doc.rust-lang.org/stable/rustdoc/documentation-tests.html#hiding-portions-of-the-example
|
||||||
|
|
||||||
|
@ -30,6 +29,46 @@ Will render as
|
||||||
|
|
||||||
The code block has an eyeball icon (<i class="fa fa-eye"></i>) which will toggle the visibility of the hidden lines.
|
The code block has an eyeball icon (<i class="fa fa-eye"></i>) which will toggle the visibility of the hidden lines.
|
||||||
|
|
||||||
|
By default, this only works for code examples that are annotated with `rust`.
|
||||||
|
However, you can define custom prefixes for other languages by adding a new line-hiding prefix in your `book.toml` with the language name and prefix character(s):
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[output.html.code.hidelines]
|
||||||
|
python = "~"
|
||||||
|
```
|
||||||
|
|
||||||
|
The prefix will hide any lines that begin with the given prefix. With the python prefix shown above, this:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
~hidden()
|
||||||
|
nothidden():
|
||||||
|
~ hidden()
|
||||||
|
~hidden()
|
||||||
|
nothidden()
|
||||||
|
```
|
||||||
|
|
||||||
|
will render as
|
||||||
|
|
||||||
|
```python
|
||||||
|
~hidden()
|
||||||
|
nothidden():
|
||||||
|
~ hidden()
|
||||||
|
~hidden()
|
||||||
|
nothidden()
|
||||||
|
```
|
||||||
|
|
||||||
|
This behavior can be overridden locally with a different prefix. This has the same effect as above:
|
||||||
|
|
||||||
|
~~~bash
|
||||||
|
```python,hidelines=!!!
|
||||||
|
!!!hidden()
|
||||||
|
nothidden():
|
||||||
|
!!! hidden()
|
||||||
|
!!!hidden()
|
||||||
|
nothidden()
|
||||||
|
```
|
||||||
|
~~~
|
||||||
|
|
||||||
## Rust Playground
|
## Rust Playground
|
||||||
|
|
||||||
Rust language code blocks will automatically get a play button (<i class="fa fa-play"></i>) which will execute the code and display the output just below the code block.
|
Rust language code blocks will automatically get a play button (<i class="fa fa-play"></i>) which will execute the code and display the output just below the code block.
|
||||||
|
|
|
@ -77,38 +77,6 @@ the `theme` folder of your book.
|
||||||
|
|
||||||
Now your theme will be used instead of the default theme.
|
Now your theme will be used instead of the default theme.
|
||||||
|
|
||||||
## Hiding code lines
|
|
||||||
|
|
||||||
There is a feature in mdBook that lets you hide code lines by prepending them
|
|
||||||
with a `#`.
|
|
||||||
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# fn main() {
|
|
||||||
let x = 5;
|
|
||||||
let y = 6;
|
|
||||||
|
|
||||||
println!("{}", x + y);
|
|
||||||
# }
|
|
||||||
```
|
|
||||||
|
|
||||||
Will render as
|
|
||||||
|
|
||||||
```rust
|
|
||||||
# fn main() {
|
|
||||||
let x = 5;
|
|
||||||
let y = 7;
|
|
||||||
|
|
||||||
println!("{}", x + y);
|
|
||||||
# }
|
|
||||||
```
|
|
||||||
|
|
||||||
**At the moment, this only works for code examples that are annotated with
|
|
||||||
`rust`. Because it would collide with semantics of some programming languages.
|
|
||||||
In the future, we want to make this configurable through the `book.toml` so that
|
|
||||||
everyone can benefit from it.**
|
|
||||||
|
|
||||||
|
|
||||||
## Improve default theme
|
## Improve default theme
|
||||||
|
|
||||||
If you think the default theme doesn't look quite right for a specific language,
|
If you think the default theme doesn't look quite right for a specific language,
|
||||||
|
|
|
@ -504,6 +504,8 @@ pub struct HtmlConfig {
|
||||||
/// Playground settings.
|
/// Playground settings.
|
||||||
#[serde(alias = "playpen")]
|
#[serde(alias = "playpen")]
|
||||||
pub playground: Playground,
|
pub playground: Playground,
|
||||||
|
/// Code settings.
|
||||||
|
pub code: Code,
|
||||||
/// Print settings.
|
/// Print settings.
|
||||||
pub print: Print,
|
pub print: Print,
|
||||||
/// Don't render section labels.
|
/// Don't render section labels.
|
||||||
|
@ -556,6 +558,7 @@ impl Default for HtmlConfig {
|
||||||
additional_js: Vec::new(),
|
additional_js: Vec::new(),
|
||||||
fold: Fold::default(),
|
fold: Fold::default(),
|
||||||
playground: Playground::default(),
|
playground: Playground::default(),
|
||||||
|
code: Code::default(),
|
||||||
print: Print::default(),
|
print: Print::default(),
|
||||||
no_section_label: false,
|
no_section_label: false,
|
||||||
search: None,
|
search: None,
|
||||||
|
@ -642,6 +645,22 @@ impl Default for Playground {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Configuration for tweaking how the the HTML renderer handles code blocks.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(default, rename_all = "kebab-case")]
|
||||||
|
pub struct Code {
|
||||||
|
/// A prefix string to hide lines per language (one or more chars).
|
||||||
|
pub hidelines: HashMap<String, String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Code {
|
||||||
|
fn default() -> Code {
|
||||||
|
Code {
|
||||||
|
hidelines: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Configuration of the search functionality of the HTML renderer.
|
/// Configuration of the search functionality of the HTML renderer.
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(default, rename_all = "kebab-case")]
|
#[serde(default, rename_all = "kebab-case")]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::book::{Book, BookItem};
|
use crate::book::{Book, BookItem};
|
||||||
use crate::config::{BookConfig, Config, HtmlConfig, Playground, RustEdition};
|
use crate::config::{BookConfig, Code, Config, HtmlConfig, Playground, RustEdition};
|
||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
use crate::renderer::html_handlebars::helpers;
|
use crate::renderer::html_handlebars::helpers;
|
||||||
use crate::renderer::{RenderContext, Renderer};
|
use crate::renderer::{RenderContext, Renderer};
|
||||||
|
@ -110,7 +110,12 @@ impl HtmlHandlebars {
|
||||||
debug!("Render template");
|
debug!("Render template");
|
||||||
let rendered = ctx.handlebars.render("index", &ctx.data)?;
|
let rendered = ctx.handlebars.render("index", &ctx.data)?;
|
||||||
|
|
||||||
let rendered = self.post_process(rendered, &ctx.html_config.playground, ctx.edition);
|
let rendered = self.post_process(
|
||||||
|
rendered,
|
||||||
|
&ctx.html_config.playground,
|
||||||
|
&ctx.html_config.code,
|
||||||
|
ctx.edition,
|
||||||
|
);
|
||||||
|
|
||||||
// Write to file
|
// Write to file
|
||||||
debug!("Creating {}", filepath.display());
|
debug!("Creating {}", filepath.display());
|
||||||
|
@ -121,8 +126,12 @@ impl HtmlHandlebars {
|
||||||
ctx.data.insert("path_to_root".to_owned(), json!(""));
|
ctx.data.insert("path_to_root".to_owned(), json!(""));
|
||||||
ctx.data.insert("is_index".to_owned(), json!(true));
|
ctx.data.insert("is_index".to_owned(), json!(true));
|
||||||
let rendered_index = ctx.handlebars.render("index", &ctx.data)?;
|
let rendered_index = ctx.handlebars.render("index", &ctx.data)?;
|
||||||
let rendered_index =
|
let rendered_index = self.post_process(
|
||||||
self.post_process(rendered_index, &ctx.html_config.playground, ctx.edition);
|
rendered_index,
|
||||||
|
&ctx.html_config.playground,
|
||||||
|
&ctx.html_config.code,
|
||||||
|
ctx.edition,
|
||||||
|
);
|
||||||
debug!("Creating index.html from {}", ctx_path);
|
debug!("Creating index.html from {}", ctx_path);
|
||||||
utils::fs::write_file(&ctx.destination, "index.html", rendered_index.as_bytes())?;
|
utils::fs::write_file(&ctx.destination, "index.html", rendered_index.as_bytes())?;
|
||||||
}
|
}
|
||||||
|
@ -182,8 +191,12 @@ impl HtmlHandlebars {
|
||||||
data_404.insert("title".to_owned(), json!(title));
|
data_404.insert("title".to_owned(), json!(title));
|
||||||
let rendered = handlebars.render("index", &data_404)?;
|
let rendered = handlebars.render("index", &data_404)?;
|
||||||
|
|
||||||
let rendered =
|
let rendered = self.post_process(
|
||||||
self.post_process(rendered, &html_config.playground, ctx.config.rust.edition);
|
rendered,
|
||||||
|
&html_config.playground,
|
||||||
|
&html_config.code,
|
||||||
|
ctx.config.rust.edition,
|
||||||
|
);
|
||||||
let output_file = get_404_output_file(&html_config.input_404);
|
let output_file = get_404_output_file(&html_config.input_404);
|
||||||
utils::fs::write_file(destination, output_file, rendered.as_bytes())?;
|
utils::fs::write_file(destination, output_file, rendered.as_bytes())?;
|
||||||
debug!("Creating 404.html ✓");
|
debug!("Creating 404.html ✓");
|
||||||
|
@ -195,11 +208,13 @@ impl HtmlHandlebars {
|
||||||
&self,
|
&self,
|
||||||
rendered: String,
|
rendered: String,
|
||||||
playground_config: &Playground,
|
playground_config: &Playground,
|
||||||
|
code_config: &Code,
|
||||||
edition: Option<RustEdition>,
|
edition: Option<RustEdition>,
|
||||||
) -> String {
|
) -> String {
|
||||||
let rendered = build_header_links(&rendered);
|
let rendered = build_header_links(&rendered);
|
||||||
let rendered = fix_code_blocks(&rendered);
|
let rendered = fix_code_blocks(&rendered);
|
||||||
let rendered = add_playground_pre(&rendered, playground_config, edition);
|
let rendered = add_playground_pre(&rendered, playground_config, edition);
|
||||||
|
let rendered = hide_lines(&rendered, code_config);
|
||||||
|
|
||||||
rendered
|
rendered
|
||||||
}
|
}
|
||||||
|
@ -583,8 +598,12 @@ impl Renderer for HtmlHandlebars {
|
||||||
debug!("Render template");
|
debug!("Render template");
|
||||||
let rendered = handlebars.render("index", &data)?;
|
let rendered = handlebars.render("index", &data)?;
|
||||||
|
|
||||||
let rendered =
|
let rendered = self.post_process(
|
||||||
self.post_process(rendered, &html_config.playground, ctx.config.rust.edition);
|
rendered,
|
||||||
|
&html_config.playground,
|
||||||
|
&html_config.code,
|
||||||
|
ctx.config.rust.edition,
|
||||||
|
);
|
||||||
|
|
||||||
utils::fs::write_file(destination, "print.html", rendered.as_bytes())?;
|
utils::fs::write_file(destination, "print.html", rendered.as_bytes())?;
|
||||||
debug!("Creating print.html ✓");
|
debug!("Creating print.html ✓");
|
||||||
|
@ -887,12 +906,12 @@ fn add_playground_pre(
|
||||||
let classes = &caps[2];
|
let classes = &caps[2];
|
||||||
let code = &caps[3];
|
let code = &caps[3];
|
||||||
|
|
||||||
if classes.contains("language-rust") {
|
if classes.contains("language-rust")
|
||||||
if (!classes.contains("ignore")
|
&& ((!classes.contains("ignore")
|
||||||
&& !classes.contains("noplayground")
|
&& !classes.contains("noplayground")
|
||||||
&& !classes.contains("noplaypen")
|
&& !classes.contains("noplaypen")
|
||||||
&& playground_config.runnable)
|
&& playground_config.runnable)
|
||||||
|| classes.contains("mdbook-runnable")
|
|| classes.contains("mdbook-runnable"))
|
||||||
{
|
{
|
||||||
let contains_e2015 = classes.contains("edition2015");
|
let contains_e2015 = classes.contains("edition2015");
|
||||||
let contains_e2018 = classes.contains("edition2018");
|
let contains_e2018 = classes.contains("edition2018");
|
||||||
|
@ -928,12 +947,9 @@ fn add_playground_pre(
|
||||||
format!("# #![allow(unused)]\n{}#fn main() {{\n{}#}}", attrs, code)
|
format!("# #![allow(unused)]\n{}#fn main() {{\n{}#}}", attrs, code)
|
||||||
.into()
|
.into()
|
||||||
};
|
};
|
||||||
hide_lines(&content)
|
content
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
format!("<code class=\"{}\">{}</code>", classes, hide_lines(code))
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// not language-rust, so no-op
|
// not language-rust, so no-op
|
||||||
text.to_owned()
|
text.to_owned()
|
||||||
|
@ -942,7 +958,53 @@ fn add_playground_pre(
|
||||||
.into_owned()
|
.into_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hide_lines(content: &str) -> String {
|
fn hide_lines(html: &str, code_config: &Code) -> String {
|
||||||
|
let regex = Regex::new(r##"((?s)<code[^>]?class="([^"]+)".*?>(.*?)</code>)"##).unwrap();
|
||||||
|
let language_regex = Regex::new(r"\blanguage-(\w+)\b").unwrap();
|
||||||
|
let hidelines_regex = Regex::new(r"\bhidelines=(\S+)").unwrap();
|
||||||
|
regex
|
||||||
|
.replace_all(html, |caps: &Captures<'_>| {
|
||||||
|
let text = &caps[1];
|
||||||
|
let classes = &caps[2];
|
||||||
|
let code = &caps[3];
|
||||||
|
|
||||||
|
if classes.contains("language-rust") {
|
||||||
|
format!(
|
||||||
|
"<code class=\"{}\">{}</code>",
|
||||||
|
classes,
|
||||||
|
hide_lines_rust(code)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// First try to get the prefix from the code block
|
||||||
|
let hidelines_capture = hidelines_regex.captures(classes);
|
||||||
|
let hidelines_prefix = match &hidelines_capture {
|
||||||
|
Some(capture) => Some(&capture[1]),
|
||||||
|
None => {
|
||||||
|
// Then look up the prefix by language
|
||||||
|
let language_capture = language_regex.captures(classes);
|
||||||
|
match &language_capture {
|
||||||
|
Some(capture) => {
|
||||||
|
code_config.hidelines.get(&capture[1]).map(|p| p.as_str())
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match hidelines_prefix {
|
||||||
|
Some(prefix) => format!(
|
||||||
|
"<code class=\"{}\">{}</code>",
|
||||||
|
classes,
|
||||||
|
hide_lines_with_prefix(code, prefix)
|
||||||
|
),
|
||||||
|
None => text.to_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.into_owned()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hide_lines_rust(content: &str) -> String {
|
||||||
static BORING_LINES_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"^(\s*)#(.?)(.*)$").unwrap());
|
static BORING_LINES_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"^(\s*)#(.?)(.*)$").unwrap());
|
||||||
|
|
||||||
let mut result = String::with_capacity(content.len());
|
let mut result = String::with_capacity(content.len());
|
||||||
|
@ -975,6 +1037,26 @@ fn hide_lines(content: &str) -> String {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn hide_lines_with_prefix(content: &str, prefix: &str) -> String {
|
||||||
|
let mut result = String::with_capacity(content.len());
|
||||||
|
for line in content.lines() {
|
||||||
|
if line.trim_start().starts_with(prefix) {
|
||||||
|
let pos = line.find(prefix).unwrap();
|
||||||
|
let (ws, rest) = (&line[..pos], &line[pos + prefix.len()..]);
|
||||||
|
|
||||||
|
result += "<span class=\"boring\">";
|
||||||
|
result += ws;
|
||||||
|
result += rest;
|
||||||
|
result += "\n";
|
||||||
|
result += "</span>";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
result += line;
|
||||||
|
result += "\n";
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
fn partition_source(s: &str) -> (String, String) {
|
fn partition_source(s: &str) -> (String, String) {
|
||||||
let mut after_header = false;
|
let mut after_header = false;
|
||||||
let mut before = String::new();
|
let mut before = String::new();
|
||||||
|
@ -1010,6 +1092,7 @@ struct RenderItemContext<'a> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn original_build_header_links() {
|
fn original_build_header_links() {
|
||||||
|
@ -1065,17 +1148,17 @@ mod tests {
|
||||||
fn add_playground() {
|
fn add_playground() {
|
||||||
let inputs = [
|
let inputs = [
|
||||||
("<code class=\"language-rust\">x()</code>",
|
("<code class=\"language-rust\">x()</code>",
|
||||||
"<pre class=\"playground\"><code class=\"language-rust\"><span class=\"boring\">#![allow(unused)]\n</span><span class=\"boring\">fn main() {\n</span>x()\n<span class=\"boring\">}</span></code></pre>"),
|
"<pre class=\"playground\"><code class=\"language-rust\"># #![allow(unused)]\n#fn main() {\nx()\n#}</code></pre>"),
|
||||||
("<code class=\"language-rust\">fn main() {}</code>",
|
("<code class=\"language-rust\">fn main() {}</code>",
|
||||||
"<pre class=\"playground\"><code class=\"language-rust\">fn main() {}</code></pre>"),
|
"<pre class=\"playground\"><code class=\"language-rust\">fn main() {}</code></pre>"),
|
||||||
("<code class=\"language-rust editable\">let s = \"foo\n # bar\n\";</code>",
|
("<code class=\"language-rust editable\">let s = \"foo\n # bar\n\";</code>",
|
||||||
"<pre class=\"playground\"><code class=\"language-rust editable\">let s = \"foo\n<span class=\"boring\"> bar\n</span>\";</code></pre>"),
|
|
||||||
("<code class=\"language-rust editable\">let s = \"foo\n ## bar\n\";</code>",
|
|
||||||
"<pre class=\"playground\"><code class=\"language-rust editable\">let s = \"foo\n # bar\n\";</code></pre>"),
|
"<pre class=\"playground\"><code class=\"language-rust editable\">let s = \"foo\n # bar\n\";</code></pre>"),
|
||||||
|
("<code class=\"language-rust editable\">let s = \"foo\n ## bar\n\";</code>",
|
||||||
|
"<pre class=\"playground\"><code class=\"language-rust editable\">let s = \"foo\n ## bar\n\";</code></pre>"),
|
||||||
("<code class=\"language-rust editable\">let s = \"foo\n # bar\n#\n\";</code>",
|
("<code class=\"language-rust editable\">let s = \"foo\n # bar\n#\n\";</code>",
|
||||||
"<pre class=\"playground\"><code class=\"language-rust editable\">let s = \"foo\n<span class=\"boring\"> bar\n</span><span class=\"boring\">\n</span>\";</code></pre>"),
|
"<pre class=\"playground\"><code class=\"language-rust editable\">let s = \"foo\n # bar\n#\n\";</code></pre>"),
|
||||||
("<code class=\"language-rust ignore\">let s = \"foo\n # bar\n\";</code>",
|
("<code class=\"language-rust ignore\">let s = \"foo\n # bar\n\";</code>",
|
||||||
"<code class=\"language-rust ignore\">let s = \"foo\n<span class=\"boring\"> bar\n</span>\";</code>"),
|
"<code class=\"language-rust ignore\">let s = \"foo\n # bar\n\";</code>"),
|
||||||
("<code class=\"language-rust editable\">#![no_std]\nlet s = \"foo\";\n #[some_attr]</code>",
|
("<code class=\"language-rust editable\">#![no_std]\nlet s = \"foo\";\n #[some_attr]</code>",
|
||||||
"<pre class=\"playground\"><code class=\"language-rust editable\">#![no_std]\nlet s = \"foo\";\n #[some_attr]</code></pre>"),
|
"<pre class=\"playground\"><code class=\"language-rust editable\">#![no_std]\nlet s = \"foo\";\n #[some_attr]</code></pre>"),
|
||||||
];
|
];
|
||||||
|
@ -1095,7 +1178,7 @@ mod tests {
|
||||||
fn add_playground_edition2015() {
|
fn add_playground_edition2015() {
|
||||||
let inputs = [
|
let inputs = [
|
||||||
("<code class=\"language-rust\">x()</code>",
|
("<code class=\"language-rust\">x()</code>",
|
||||||
"<pre class=\"playground\"><code class=\"language-rust edition2015\"><span class=\"boring\">#![allow(unused)]\n</span><span class=\"boring\">fn main() {\n</span>x()\n<span class=\"boring\">}</span></code></pre>"),
|
"<pre class=\"playground\"><code class=\"language-rust edition2015\"># #![allow(unused)]\n#fn main() {\nx()\n#}</code></pre>"),
|
||||||
("<code class=\"language-rust\">fn main() {}</code>",
|
("<code class=\"language-rust\">fn main() {}</code>",
|
||||||
"<pre class=\"playground\"><code class=\"language-rust edition2015\">fn main() {}</code></pre>"),
|
"<pre class=\"playground\"><code class=\"language-rust edition2015\">fn main() {}</code></pre>"),
|
||||||
("<code class=\"language-rust edition2015\">fn main() {}</code>",
|
("<code class=\"language-rust edition2015\">fn main() {}</code>",
|
||||||
|
@ -1119,7 +1202,7 @@ mod tests {
|
||||||
fn add_playground_edition2018() {
|
fn add_playground_edition2018() {
|
||||||
let inputs = [
|
let inputs = [
|
||||||
("<code class=\"language-rust\">x()</code>",
|
("<code class=\"language-rust\">x()</code>",
|
||||||
"<pre class=\"playground\"><code class=\"language-rust edition2018\"><span class=\"boring\">#![allow(unused)]\n</span><span class=\"boring\">fn main() {\n</span>x()\n<span class=\"boring\">}</span></code></pre>"),
|
"<pre class=\"playground\"><code class=\"language-rust edition2018\"># #![allow(unused)]\n#fn main() {\nx()\n#}</code></pre>"),
|
||||||
("<code class=\"language-rust\">fn main() {}</code>",
|
("<code class=\"language-rust\">fn main() {}</code>",
|
||||||
"<pre class=\"playground\"><code class=\"language-rust edition2018\">fn main() {}</code></pre>"),
|
"<pre class=\"playground\"><code class=\"language-rust edition2018\">fn main() {}</code></pre>"),
|
||||||
("<code class=\"language-rust edition2015\">fn main() {}</code>",
|
("<code class=\"language-rust edition2015\">fn main() {}</code>",
|
||||||
|
@ -1143,7 +1226,7 @@ mod tests {
|
||||||
fn add_playground_edition2021() {
|
fn add_playground_edition2021() {
|
||||||
let inputs = [
|
let inputs = [
|
||||||
("<code class=\"language-rust\">x()</code>",
|
("<code class=\"language-rust\">x()</code>",
|
||||||
"<pre class=\"playground\"><code class=\"language-rust edition2021\"><span class=\"boring\">#![allow(unused)]\n</span><span class=\"boring\">fn main() {\n</span>x()\n<span class=\"boring\">}</span></code></pre>"),
|
"<pre class=\"playground\"><code class=\"language-rust edition2021\"># #![allow(unused)]\n#fn main() {\nx()\n#}</code></pre>"),
|
||||||
("<code class=\"language-rust\">fn main() {}</code>",
|
("<code class=\"language-rust\">fn main() {}</code>",
|
||||||
"<pre class=\"playground\"><code class=\"language-rust edition2021\">fn main() {}</code></pre>"),
|
"<pre class=\"playground\"><code class=\"language-rust edition2021\">fn main() {}</code></pre>"),
|
||||||
("<code class=\"language-rust edition2015\">fn main() {}</code>",
|
("<code class=\"language-rust edition2015\">fn main() {}</code>",
|
||||||
|
@ -1163,4 +1246,60 @@ mod tests {
|
||||||
assert_eq!(&*got, *should_be);
|
assert_eq!(&*got, *should_be);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hide_lines_language_rust() {
|
||||||
|
let inputs = [
|
||||||
|
(
|
||||||
|
"<pre class=\"playground\"><code class=\"language-rust\">\n# #![allow(unused)]\n#fn main() {\nx()\n#}</code></pre>",
|
||||||
|
"<pre class=\"playground\"><code class=\"language-rust\">\n<span class=\"boring\">#![allow(unused)]\n</span><span class=\"boring\">fn main() {\n</span>x()\n<span class=\"boring\">}</span></code></pre>",),
|
||||||
|
(
|
||||||
|
"<pre class=\"playground\"><code class=\"language-rust\">fn main() {}</code></pre>",
|
||||||
|
"<pre class=\"playground\"><code class=\"language-rust\">fn main() {}</code></pre>",),
|
||||||
|
(
|
||||||
|
"<pre class=\"playground\"><code class=\"language-rust editable\">let s = \"foo\n # bar\n\";</code></pre>",
|
||||||
|
"<pre class=\"playground\"><code class=\"language-rust editable\">let s = \"foo\n<span class=\"boring\"> bar\n</span>\";</code></pre>",),
|
||||||
|
(
|
||||||
|
"<pre class=\"playground\"><code class=\"language-rust editable\">let s = \"foo\n ## bar\n\";</code></pre>",
|
||||||
|
"<pre class=\"playground\"><code class=\"language-rust editable\">let s = \"foo\n # bar\n\";</code></pre>",),
|
||||||
|
(
|
||||||
|
"<pre class=\"playground\"><code class=\"language-rust editable\">let s = \"foo\n # bar\n#\n\";</code></pre>",
|
||||||
|
"<pre class=\"playground\"><code class=\"language-rust editable\">let s = \"foo\n<span class=\"boring\"> bar\n</span><span class=\"boring\">\n</span>\";</code></pre>",),
|
||||||
|
(
|
||||||
|
"<code class=\"language-rust ignore\">let s = \"foo\n # bar\n\";</code>",
|
||||||
|
"<code class=\"language-rust ignore\">let s = \"foo\n<span class=\"boring\"> bar\n</span>\";</code>",),
|
||||||
|
(
|
||||||
|
"<pre class=\"playground\"><code class=\"language-rust editable\">#![no_std]\nlet s = \"foo\";\n #[some_attr]</code></pre>",
|
||||||
|
"<pre class=\"playground\"><code class=\"language-rust editable\">#![no_std]\nlet s = \"foo\";\n #[some_attr]</code></pre>",),
|
||||||
|
];
|
||||||
|
for (src, should_be) in &inputs {
|
||||||
|
let got = hide_lines(src, &Code::default());
|
||||||
|
assert_eq!(&*got, *should_be);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hide_lines_language_other() {
|
||||||
|
let inputs = [
|
||||||
|
(
|
||||||
|
"<code class=\"language-python\">~hidden()\nnothidden():\n~ hidden()\n ~hidden()\n nothidden()</code>",
|
||||||
|
"<code class=\"language-python\"><span class=\"boring\">hidden()\n</span>nothidden():\n<span class=\"boring\"> hidden()\n</span><span class=\"boring\"> hidden()\n</span> nothidden()\n</code>",),
|
||||||
|
(
|
||||||
|
"<code class=\"language-python hidelines=!!!\">!!!hidden()\nnothidden():\n!!! hidden()\n !!!hidden()\n nothidden()</code>",
|
||||||
|
"<code class=\"language-python hidelines=!!!\"><span class=\"boring\">hidden()\n</span>nothidden():\n<span class=\"boring\"> hidden()\n</span><span class=\"boring\"> hidden()\n</span> nothidden()\n</code>",),
|
||||||
|
];
|
||||||
|
for (src, should_be) in &inputs {
|
||||||
|
let got = hide_lines(
|
||||||
|
src,
|
||||||
|
&Code {
|
||||||
|
hidelines: {
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
map.insert("python".to_string(), "~".to_string());
|
||||||
|
map
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
assert_eq!(&*got, *should_be);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -179,7 +179,7 @@ function playground_text(playground, hidden = true) {
|
||||||
// even if highlighting doesn't apply
|
// even if highlighting doesn't apply
|
||||||
code_nodes.forEach(function (block) { block.classList.add('hljs'); });
|
code_nodes.forEach(function (block) { block.classList.add('hljs'); });
|
||||||
|
|
||||||
Array.from(document.querySelectorAll("code.language-rust")).forEach(function (block) {
|
Array.from(document.querySelectorAll("code.hljs")).forEach(function (block) {
|
||||||
|
|
||||||
var lines = Array.from(block.querySelectorAll('.boring'));
|
var lines = Array.from(block.querySelectorAll('.boring'));
|
||||||
// If no lines were hidden, return
|
// If no lines were hidden, return
|
||||||
|
|
Loading…
Reference in New Issue