Skip to content

Commit 8c1125f

Browse files
committed
Create mdbook-rustc preprocessor
1 parent 3c3f6a1 commit 8c1125f

File tree

6 files changed

+1373
-33
lines changed

6 files changed

+1373
-33
lines changed

src/doc/rustc/book.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,9 @@ use-boolean-and = true
1010

1111
[output.html.playground]
1212
runnable = false
13+
14+
[preprocessor.rustc-gen-target-tables]
15+
command = "cargo run --release --manifest-path ../../tools/mdbook-rustc/Cargo.toml"
16+
17+
[build]
18+
extra-watch-dirs = ["../../tools/mdbook-rustc"]

src/tools/mdbook-rustc/Cargo.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "mdbook-rustc"
3+
version = "0.0.0"
4+
edition = "2024"
5+
workspace = "../rustbook"
6+
7+
[dependencies]
8+
mdbook-preprocessor = "0.5.1"
9+
rustc_target = {path = "../../../compiler/rustc_target"}
10+
serde = { version = "1.0.228", features = ["serde_derive"] }
11+
serde_json = "1"

src/tools/mdbook-rustc/src/lib.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
use rustc_target::spec::{TARGETS, Target, TargetMetadata, TargetTuple};
2+
3+
pub struct AllTargets {
4+
pub tier1_host: Vec<TargetInfo>,
5+
pub tier1_nohost: Vec<TargetInfo>,
6+
pub tier2_host: Vec<TargetInfo>,
7+
pub tier2_nohost: Vec<TargetInfo>,
8+
pub tier3: Vec<TargetInfo>,
9+
}
10+
11+
pub struct TargetInfo {
12+
pub tuple: &'static str,
13+
pub meta: TargetMetadata,
14+
}
15+
16+
impl AllTargets {
17+
fn load() -> Self {
18+
let mut tier1_host = Vec::new();
19+
let mut tier1_nohost = Vec::new();
20+
let mut tier2_host = Vec::new();
21+
let mut tier2_nohost = Vec::new();
22+
let mut tier3 = Vec::new();
23+
24+
for tuple in TARGETS {
25+
let target = TargetInfo {
26+
tuple,
27+
meta: Target::expect_builtin(TargetTuple::from_tuple(target)).metadata,
28+
};
29+
let host_tools = target.meta.host_tools.unwrap_or(false);
30+
31+
match target.meta.tier {
32+
Some(1) if host_tools => tier1_host.push(target),
33+
Some(1) => tier1_nohost.push(target),
34+
Some(2) if host_tools => tier2_host.push(target),
35+
Some(2) => tier2_nohost.push(target),
36+
Some(3) => tier3.push(target),
37+
tier => panic!("unknown target tier: {tier}"),
38+
}
39+
}
40+
41+
tier1_host.sort_by_key(|t| t.tuple);
42+
tier1_nohost.sort_by_key(|t| t.tuple);
43+
tier2_host.sort_by_key(|t| t.tuple);
44+
tier2_nohost.sort_by_key(|t| t.tuple);
45+
tier3.sort_by_key(|t| t.tuple);
46+
47+
Self { tier1_host, tier1_nohost, tier2_host, tier2_nohost, tier3 }
48+
}
49+
}

src/tools/mdbook-rustc/src/main.rs

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
use std::collections::HashSet;
2+
use std::io;
3+
4+
use mdbook_preprocessor::errors::Error;
5+
use mdbook_preprocessor::parse_input;
6+
use mdbook_rustc::{AllTargets, TargetInfo};
7+
8+
const TIER_1_HOST_MARKER: &str = "{{TIER_1_HOST_TABLE}}";
9+
const TIER_1_NOHOST_MARKER: &str = "{{TIER_1_NOHOST_TABLE}}";
10+
const TIER_2_HOST_MARKER: &str = "{{TIER_2_HOST_TABLE}}";
11+
const TIER_2_NOHOST_MARKER: &str = "{{TIER_2_NOHOST_TABLE}}";
12+
const TIER_3_MARKER: &str = "{{TIER_3_TABLE}}";
13+
14+
const EMPTY_TIER_1_NOHOST_MSG: &str =
15+
"At this time, all Tier 1 targets are [Tier 1 with Host Tools](#tier-1-with-host-tools).\n";
16+
const EMPTY_TIER_2_NOHOST_MSG: &str =
17+
"At this time, all Tier 2 targets are [Tier 2 with Host Tools](#tier-2-with-host-tools).\n";
18+
19+
fn main() -> Result<(), Error> {
20+
let mut args = std::env::args().skip(1);
21+
match args.next().as_deref() {
22+
Some("supports") => {
23+
// Supports all renderers.
24+
return;
25+
}
26+
Some(arg) => {
27+
return Err(Error::msg("unknown argument: {arg}"));
28+
}
29+
None => {}
30+
}
31+
32+
let (ctx, book) = mdbook_preprocessor::parse_input(io::stdin().lock())?;
33+
let targets = AllTargets::load();
34+
35+
book.for_each_chapter_mut(|chapter| {
36+
if chapter.source_path.as_deref() != Some("platform-support.md") {
37+
return;
38+
}
39+
40+
let mut target_chapters = HashSet::new();
41+
42+
for target_chapter in &chapter.subitems {
43+
if let Some(path) = target_chapter.path.map(|p| p.to_str()) {
44+
target_chapters
45+
.insert(path.trim_start_matches("platform-support/").trim_end_matches(".md"));
46+
}
47+
}
48+
49+
let mut new_content = String::new();
50+
51+
for line in chapter.content.lines() {
52+
match line.trim() {
53+
TIER_1_HOST_MARKER => {
54+
write_host_table(&mut new_content, &targets.tier1_host, &target_chapters)
55+
}
56+
TIER_1_NOHOST_MARKER => write_nohost_table(
57+
&mut new_content,
58+
&targets.tier1_nohost,
59+
&target_chapters,
60+
EMPTY_TIER_1_NOHOST_MSG,
61+
),
62+
TIER_2_HOST_MARKER => {
63+
write_host_table(&mut new_content, &targets.tier2_host, &target_chapters)
64+
}
65+
TIER_2_NOHOST_MARKER => write_nohost_table(
66+
&mut new_content,
67+
&targets.tier2_nohost,
68+
&target_chapters,
69+
EMPTY_TIER_2_NOHOST_MSG,
70+
),
71+
TIER_3_MARKER => {
72+
write_tier3_table(&mut new_content, &targets.tier3, &target_chapters)
73+
}
74+
_ => {
75+
new_content.push(line);
76+
new_content.push("\n");
77+
}
78+
}
79+
}
80+
81+
chapter.content = new_content;
82+
});
83+
84+
serde_json::to_writer(io::stdout().lock(), &book)?;
85+
Ok(())
86+
}
87+
88+
fn write_host_table(out: &mut String, targets: &[TargetInfo], target_chapters: &HashSet<&str>) {
89+
out.push("target | notes\n-------|-------\n");
90+
for target in targets {
91+
write_target_tuple(out, target, target_chapters);
92+
_ = writeln!(out, " | {}", target.tuple, target.meta.description.unwrap_or(""));
93+
}
94+
}
95+
96+
fn write_nohost_table(
97+
out: &mut String,
98+
targets: &[TargetInfo],
99+
target_chapters: &HashSet<&str>,
100+
empty_msg: &str,
101+
) {
102+
if targets.is_empty() {
103+
out.push(empty_msg);
104+
return;
105+
}
106+
107+
out.push("target | std | notes\n-------|:---:|-------\n");
108+
for target in targets {
109+
write_target_tuple(out, target, target_chapters);
110+
_ = writeln!(
111+
out,
112+
" | {} | {}",
113+
target.tuple,
114+
support_symbol(target.meta.std),
115+
target.meta.description.unwrap_or("")
116+
);
117+
}
118+
}
119+
120+
fn write_tier3_table(out: &mut String, targets: &[TargetInfo], target_chapters: &HashSet<&str>) {
121+
out.push("target | std | host | notes\n-------|:---:|:----:|-------\n");
122+
for target in targets {
123+
write_target_tuple(out, target, target_chapters);
124+
_ = writeln!(
125+
out,
126+
" | {} | {} | {}",
127+
target.tuple,
128+
support_symbol(target.meta.std),
129+
support_symbol(target.meta.host_tools),
130+
target.meta.description.unwrap_or("")
131+
);
132+
}
133+
}
134+
135+
fn write_target_tuple(out: &mut String, target: &TargetInfo, target_chapters: &HashSet<&str>) {
136+
// let doc_page = target.meta.doc_page.as_deref().unwrap_or(target.tuple);
137+
let doc_page = target.tuple;
138+
139+
if target_chapters.contains(doc_page) {
140+
_ = write!(out, "[`{}`](platform-support/{}.md)", target.tuple, doc_page);
141+
} else {
142+
_ = write!(out, "`{}`", target.tuple);
143+
}
144+
}
145+
146+
fn support_symbol(support: Option<bool>) -> &'static str {
147+
match support {
148+
Some(true) => "✓",
149+
Some(false) => "*",
150+
None => "?",
151+
}
152+
}

0 commit comments

Comments
 (0)