From 5d258482fb84d58c966a7ccc1b467708278d28ad Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Fri, 10 Jul 2026 16:54:57 +0800 Subject: refactor(devtools): rename dev_tools to .run and replace run-tools scripts Replace the old run-tools.ps1/run-tools.sh scripts with a new unified run.ps1/run.sh launcher that supports multiple languages (PowerShell, Rust, Python, Go, C#, Nim, Perl, Ruby, Zig, and arbitrary binaries) from the `.run/src/bin` directory. Move all development tools from `dev_tools/` to `.run/`, update Cargo workspace config and relevant documentation references. --- .run/src/bin/refresh-docs.rs | 178 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 .run/src/bin/refresh-docs.rs (limited to '.run/src/bin/refresh-docs.rs') diff --git a/.run/src/bin/refresh-docs.rs b/.run/src/bin/refresh-docs.rs new file mode 100644 index 0000000..82ef906 --- /dev/null +++ b/.run/src/bin/refresh-docs.rs @@ -0,0 +1,178 @@ +use std::path::Path; + +use just_fmt::snake_case; +use just_template::{Template, tmpl}; +use tools::println_cargo_style; + +const EXAMPLE_ROOT: &str = "./examples/"; +const OUTPUT_PATH: &str = "./mingling/src/example_docs.rs"; + +const TEMPLATE_CONTENT: &str = include_str!("../../../mingling/src/example_docs.rs.tmpl"); + +fn main() { + gen_example_doc_module(); +} + +fn gen_example_doc_module() { + let mut template = Template::from(TEMPLATE_CONTENT); + let repo_root = find_git_repo().unwrap(); + let example_root = repo_root.join(EXAMPLE_ROOT); + let mut examples = Vec::new(); + if let Ok(entries) = std::fs::read_dir(&example_root) { + for entry in entries.flatten() { + if let Ok(file_type) = entry.file_type() + && file_type.is_dir() + { + let example_name = entry.file_name().to_string_lossy().to_string(); + // Ignore directories that don't start with "example-" + if !example_name.starts_with("example-") { + continue; + } + let example_content = ExampleContent::read(&example_name); + examples.push(example_content); + } + } + } + + examples.sort(); + + for example in examples { + tmpl!(template += { + examples { + ( + example_header = example.header, + example_import = example.cargo_toml, + example_code = example.code, + example_name = snake_case!(&example.name) + ) + } + }); + println_cargo_style!("Refresh: {}", example.name); + } + + let template_str = template.to_string(); + let template_str = template_str + .lines() + .map(str::trim_end) + .collect::>() + .join("\n") + + "\n"; + std::fs::write(repo_root.join(OUTPUT_PATH), template_str).unwrap(); +} + +struct ExampleContent { + name: String, + header: String, + code: String, + cargo_toml: String, +} + +impl PartialOrd for ExampleContent { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for ExampleContent { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.name.cmp(&other.name) + } +} + +impl PartialEq for ExampleContent { + fn eq(&self, other: &Self) -> bool { + self.name == other.name + } +} + +impl Eq for ExampleContent {} + +impl ExampleContent { + pub fn read(name: &str) -> Self { + let repo = find_git_repo().unwrap(); + let cargo_toml = Self::read_cargo_toml(&repo, name); + let (header, code) = Self::read_header_and_code(&repo, name); + + let cargo_toml = cargo_toml + .lines() + .map(|line| format!("/// {line}")) + .collect::>() + .join("\n"); + + let header = header + .lines() + .map(|line| format!("/// {line}")) + .collect::>() + .join("\n"); + + let code = code + .lines() + .map(|line| format!("/// {line}")) + .collect::>() + .join("\n"); + + ExampleContent { + name: name.to_string(), + header, + code, + cargo_toml, + } + } + + fn read_header_and_code(repo: &Path, name: &str) -> (String, String) { + let file_path = repo + .join(EXAMPLE_ROOT) + .join(name) + .join("src") + .join("main.rs"); + let content = std::fs::read_to_string(&file_path).unwrap_or_default(); + let mut lines = content.lines(); + let mut header = String::new(); + let mut code = String::new(); + + // Collect header lines (starting with //!) + for line in lines.by_ref() { + if line.trim_start().starts_with("//!") { + let trimmed = line.trim_start_matches("//!"); + header.push_str(trimmed); + header.push('\n'); + } else { + // First non-header line found, start collecting code + code.push_str(line); + code.push('\n'); + break; + } + } + + // Collect remaining code lines + for line in lines { + code.push_str(line); + code.push('\n'); + } + + (header.trim().to_string(), code.trim().to_string()) + } + + fn read_cargo_toml(repo: &Path, name: &str) -> String { + let file_path = repo.join(EXAMPLE_ROOT).join(name).join("Cargo.toml"); + + std::fs::read_to_string(&file_path).unwrap_or_default() + } +} + +fn find_git_repo() -> Option { + let mut current_dir = std::env::current_dir().ok()?; + + loop { + let git_dir = current_dir.join(".git"); + if git_dir.exists() && git_dir.is_dir() { + return Some(current_dir); + } + + if !current_dir.pop() { + break; + } + } + + None +} -- cgit