Skip to content

Commit ab9e5d8

Browse files
committed
Create mdbook-rustc preprocessor
1 parent 8c66dbb commit ab9e5d8

File tree

6 files changed

+1351
-35
lines changed

6 files changed

+1351
-35
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: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
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"}

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

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
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 {
48+
tier1_host,
49+
tier1_nohost,
50+
tier2_host,
51+
tier2_nohost,
52+
tier3,
53+
}
54+
}
55+
}

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

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

0 commit comments

Comments
 (0)