Skip to content

Commit 33380dd

Browse files
committed
update original
1 parent 0d5ffe2 commit 33380dd

File tree

13 files changed

+1141
-657
lines changed

13 files changed

+1141
-657
lines changed

rustbook-en/listings/ch14-more-about-cargo/listing-14-07/add/adder/src/main.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use add_one;
2-
31
fn main() {
42
let num = 10;
53
println!("Hello, world! {num} plus one is {}!", add_one::add_one(num));

rustbook-en/nostarch/book.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,8 @@ output-mode = "simple"
1919
[preprocessor.trpl-figure]
2020
output-mode = "simple"
2121

22+
[preprocessor.trpl-heading]
23+
output-mode = "simple"
24+
2225
[rust]
2326
edition = "2021"

rustbook-en/nostarch/chapter21.md

Lines changed: 751 additions & 627 deletions
Large diffs are not rendered by default.

rustbook-en/packages/mdbook-trpl/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ path = "src/bin/note.rs"
1111
name = "mdbook-trpl-listing"
1212
path = "src/bin/listing.rs"
1313

14+
[[bin]]
15+
name = "mdbook-trpl-heading"
16+
path = "src/bin/heading.rs"
17+
1418
[[bin]]
1519
name = "mdbook-trpl-figure"
1620
path = "src/bin/figure.rs"
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use std::io;
2+
3+
use clap::{self, Parser, Subcommand};
4+
use mdbook::preprocess::{CmdPreprocessor, Preprocessor};
5+
6+
use mdbook_trpl::Heading;
7+
8+
fn main() -> Result<(), String> {
9+
let cli = Cli::parse();
10+
if let Some(Command::Supports { renderer }) = cli.command {
11+
return if Heading.supports_renderer(&renderer) {
12+
Ok(())
13+
} else {
14+
Err(format!("Renderer '{renderer}' is unsupported"))
15+
};
16+
}
17+
18+
let (ctx, book) = CmdPreprocessor::parse_input(io::stdin())
19+
.map_err(|e| format!("{e}"))?;
20+
let processed = Heading.run(&ctx, book).map_err(|e| format!("{e}"))?;
21+
serde_json::to_writer(io::stdout(), &processed).map_err(|e| format!("{e}"))
22+
}
23+
24+
/// A simple preprocessor for semantic markup for code listings in _The Rust
25+
/// Programming Language_.
26+
#[derive(Parser, Debug)]
27+
struct Cli {
28+
#[command(subcommand)]
29+
command: Option<Command>,
30+
}
31+
32+
#[derive(Subcommand, Debug)]
33+
enum Command {
34+
/// Is the renderer supported?
35+
///
36+
/// This supports the HTML
37+
Supports { renderer: String },
38+
}

rustbook-en/packages/mdbook-trpl/src/config/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use mdbook::preprocess::PreprocessorContext;
44

5-
#[derive(Debug, Clone, Copy)]
5+
#[derive(Debug, Clone, Copy, PartialEq)]
66
pub enum Mode {
77
Default,
88
Simple,

rustbook-en/packages/mdbook-trpl/src/figure/mod.rs

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use mdbook::{book::Book, preprocess::Preprocessor, BookItem};
55
use pulldown_cmark::Event;
66
use pulldown_cmark_to_cmark::cmark;
77

8-
use crate::config::Mode;
8+
use crate::{config::Mode, CompositeError};
99

1010
/// A simple preprocessor to rewrite `<figure>`s with `<img>`s.
1111
///
@@ -74,19 +74,6 @@ impl Preprocessor for TrplFigure {
7474
}
7575
}
7676

77-
#[derive(Debug, thiserror::Error)]
78-
struct CompositeError(Vec<anyhow::Error>);
79-
80-
impl std::fmt::Display for CompositeError {
81-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82-
write!(
83-
f,
84-
"Error(s) rewriting input: {}",
85-
self.0.iter().map(|e| format!("{e:?}")).collect::<String>()
86-
)
87-
}
88-
}
89-
9077
const OPEN_FIGURE: &'static str = "<figure>";
9178
const CLOSE_FIGURE: &'static str = "</figure>";
9279

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
use anyhow::anyhow;
2+
use mdbook::{
3+
book::Book,
4+
preprocess::{Preprocessor, PreprocessorContext},
5+
BookItem,
6+
};
7+
use pulldown_cmark::{Event, Tag, TagEnd};
8+
use pulldown_cmark_to_cmark::cmark;
9+
10+
use crate::{CompositeError, Mode};
11+
12+
pub struct TrplHeading;
13+
14+
impl Preprocessor for TrplHeading {
15+
fn name(&self) -> &str {
16+
"trpl-heading"
17+
}
18+
19+
fn run(
20+
&self,
21+
ctx: &PreprocessorContext,
22+
mut book: Book,
23+
) -> anyhow::Result<Book> {
24+
let mode = Mode::from_context(ctx, self.name())?;
25+
26+
let mut errors = vec![];
27+
book.for_each_mut(|item| {
28+
if let BookItem::Chapter(ref mut chapter) = item {
29+
match rewrite_headings(&chapter.content, mode) {
30+
Ok(rewritten) => chapter.content = rewritten,
31+
Err(reason) => errors.push(reason),
32+
}
33+
}
34+
});
35+
36+
if errors.is_empty() {
37+
Ok(book)
38+
} else {
39+
Err(CompositeError(errors).into())
40+
}
41+
}
42+
43+
fn supports_renderer(&self, renderer: &str) -> bool {
44+
renderer == "html" || renderer == "markdown" || renderer == "test"
45+
}
46+
}
47+
48+
fn rewrite_headings(src: &str, mode: Mode) -> anyhow::Result<String> {
49+
// Don't rewrite anything for the default mode.
50+
if mode == Mode::Default {
51+
return Ok(src.into());
52+
}
53+
54+
#[derive(Default)]
55+
struct State<'e> {
56+
in_heading: bool,
57+
events: Vec<Event<'e>>,
58+
}
59+
60+
let final_state: State = crate::parser(src).try_fold(
61+
State::default(),
62+
|mut state, event| -> anyhow::Result<State> {
63+
if state.in_heading {
64+
match event {
65+
// When we see the start or end of any of the inline tags
66+
// (emphasis, strong emphasis, or strikethrough), or any
67+
// inline HTML tags, we just skip emitting them. As dumb as
68+
// that may seem, it does the job!
69+
Event::Start(
70+
Tag::Emphasis | Tag::Strong | Tag::Strikethrough,
71+
)
72+
| Event::End(
73+
TagEnd::Emphasis
74+
| TagEnd::Strong
75+
| TagEnd::Strikethrough,
76+
)
77+
| Event::InlineHtml(_) => { /* skip */ }
78+
79+
// For code, we just emit the body of the inline code block,
80+
// unchanged (the wrapping backticks are not present here).
81+
Event::Code(code) => {
82+
state.events.push(Event::Text(code));
83+
}
84+
85+
// Assume headings are well-formed; you cannot have a nested
86+
// headings, so we don't have to check heading level.
87+
Event::End(TagEnd::Heading(_)) => {
88+
state.in_heading = false;
89+
state.events.push(event);
90+
}
91+
_ => state.events.push(event),
92+
}
93+
} else if matches!(event, Event::Start(Tag::Heading { .. })) {
94+
state.events.push(event);
95+
state.in_heading = true;
96+
} else {
97+
state.events.push(event);
98+
}
99+
100+
Ok(state)
101+
},
102+
)?;
103+
104+
if final_state.in_heading {
105+
return Err(anyhow!("Unclosed heading"));
106+
}
107+
108+
let mut rewritten = String::new();
109+
cmark(final_state.events.into_iter(), &mut rewritten)?;
110+
Ok(rewritten)
111+
}
112+
113+
#[cfg(test)]
114+
mod tests;

0 commit comments

Comments
 (0)