From d3b4027f5926569cb9371b2ea62b6be9387ea650 Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Fri, 5 Jun 2026 21:08:07 +0800 Subject: Add example pages and sync-examples tool for docs --- dev_tools/src/bin/ci.rs | 1 + dev_tools/src/bin/sync-examples.rs | 134 +++++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 dev_tools/src/bin/sync-examples.rs (limited to 'dev_tools/src/bin') diff --git a/dev_tools/src/bin/ci.rs b/dev_tools/src/bin/ci.rs index 86b930c..a90c413 100644 --- a/dev_tools/src/bin/ci.rs +++ b/dev_tools/src/bin/ci.rs @@ -123,6 +123,7 @@ fn docs_refresh() -> Result<(), i32> { run_cmd!("cargo run --manifest-path dev_tools/Cargo.toml --bin docsify-sidebar-gen")?; run_cmd!("cargo run --manifest-path dev_tools/Cargo.toml --bin refresh-docs")?; run_cmd!("cargo run --manifest-path dev_tools/Cargo.toml --bin refresh-feature-mod")?; + run_cmd!("cargo run --manifest-path dev_tools/Cargo.toml --bin sync-examples")?; Ok(()) } diff --git a/dev_tools/src/bin/sync-examples.rs b/dev_tools/src/bin/sync-examples.rs new file mode 100644 index 0000000..c317af6 --- /dev/null +++ b/dev_tools/src/bin/sync-examples.rs @@ -0,0 +1,134 @@ +use std::fs; +use std::path::Path; + +use serde::{Deserialize, Serialize}; +use tools::println_cargo_style; + +#[derive(Serialize)] +struct ExampleMeta { + id: String, + name: String, + icon: String, + category: String, + desc: String, + tags: Vec, + files: Vec, +} + +#[derive(Deserialize)] +struct PageToml { + example: PageTomlExample, +} + +#[derive(Deserialize)] +struct PageTomlExample { + id: String, + #[serde(default)] + name: String, + #[serde(default = "default_icon")] + icon: String, + #[serde(default)] + category: String, + #[serde(default)] + desc: String, + #[serde(default)] + tags: Vec, + #[serde(default = "default_files")] + files: Vec, +} + +fn default_icon() -> String { + "📦".to_string() +} + +fn default_files() -> Vec { + vec!["Cargo.toml".to_string(), "src/main.rs".to_string()] +} + +fn main() { + #[cfg(windows)] + let _ = colored::control::set_virtual_terminal(true); + + let examples_dir = Path::new("examples"); + let output_dir = Path::new("docs/example-pages"); + fs::create_dir_all(output_dir).expect("failed to create docs/example-pages"); + + let mut examples: Vec = Vec::new(); + + let entries = fs::read_dir(examples_dir).expect("failed to read examples/"); + for entry in entries.flatten() { + let path = entry.path(); + if !path.is_dir() { + continue; + } + + let dir_name = path.file_name().and_then(|n| n.to_str()).unwrap_or(""); + if !dir_name.starts_with("example-") { + continue; + } + + let id = dir_name.to_string(); + let page_toml_path = path.join("page.toml"); + + let meta = if page_toml_path.exists() { + match fs::read_to_string(&page_toml_path) + .map_err(|e| e.to_string()) + .and_then(|content| toml::from_str::(&content).map_err(|e| e.to_string())) + { + Ok(page) => { + let ex = page.example; + ExampleMeta { + id: if ex.id.is_empty() { id.clone() } else { ex.id }, + name: if ex.name.is_empty() { + id.clone() + } else { + ex.name + }, + icon: ex.icon, + category: ex.category, + desc: ex.desc, + tags: ex.tags, + files: if ex.files.is_empty() { + default_files() + } else { + ex.files + }, + } + } + Err(e) => { + eprintln!( + "Warning: failed to parse {}: {}", + page_toml_path.display(), + e + ); + continue; + } + } + } else { + continue; + }; + + examples.push(meta); + } + + // Sort: basic first, then alphabetical + examples.sort_by(|a, b| { + if a.id == "example-basic" { + return std::cmp::Ordering::Less; + } + if b.id == "example-basic" { + return std::cmp::Ordering::Greater; + } + a.id.cmp(&b.id) + }); + + let json = serde_json::to_string_pretty(&examples).expect("failed to serialize"); + let output_path = output_dir.join("examples.json"); + fs::write(&output_path, &json).expect("failed to write examples.json"); + + println_cargo_style!( + "Sync: {} examples -> {}", + examples.len(), + output_path.display() + ); +} -- cgit