diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-01-12 04:28:28 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-01-12 04:51:34 +0800 |
| commit | c5fb22694e95f12c24b8d8af76999be7aea3fcec (patch) | |
| tree | 399d8a24ce491fb635f3d09f2123290fe784059e /docs/build.rs | |
| parent | 444754489aca0454eb54e15a49fb8a6db0b68a07 (diff) | |
Reorganize crate structure and move documentation files
Diffstat (limited to 'docs/build.rs')
| -rw-r--r-- | docs/build.rs | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/docs/build.rs b/docs/build.rs new file mode 100644 index 0000000..53679db --- /dev/null +++ b/docs/build.rs @@ -0,0 +1,196 @@ +use std::env; +use std::fs; +use std::io::{self, Write}; +use std::path::Path; + +// Template markers for code generation +const TEMPLATE_DOCUMENT_BEGIN: &str = "--- TEMPLATE DOCUMENT BEGIN ---"; +const TEMPLATE_DOCUMENT_END: &str = "--- TEMPLATE DOCUMENT END ---"; +const TEMPLATE_FUNC_BEGIN: &str = "--- TEMPLATE FUNC BEGIN ---"; +const TEMPLATE_FUNC_END: &str = "--- TEMPLATE FUNC END ---"; +const TEMPLATE_LIST_BEGIN: &str = "--- TEMPLATE LIST BEGIN ---"; +const TEMPLATE_LIST_END: &str = "--- TEMPLATE LIST END ---"; + +// Template parameter patterns for substitution +const PARAM_DOCUMENT_PATH: &str = "{{DOCUMENT_PATH}}"; +const PARAM_DOCUMENT_CONSTANT_NAME: &str = "{{DOCUMENT_CONSTANT_NAME}}"; +const PARAM_DOCUMENT_CONTENT: &str = "{{DOCUMENT_CONTENT}}"; +const PARAM_DOCUMENT_PATH_SNAKE_CASE: &str = "{{DOCUMENT_PATH_SNAKE_CASE}}"; + +fn main() -> io::Result<()> { + println!("cargo:rerun-if-changed=src/docs.rs.template"); + println!("cargo:rerun-if-changed=Documents"); + + let out_dir = env::var("OUT_DIR").unwrap(); + let dest_path = Path::new(&out_dir).join("docs.rs"); + + // Read all markdown files from docs directory recursively + let docs_dir = Path::new("./Documents"); + let mut documents = Vec::new(); + + if docs_dir.exists() { + collect_text_files(docs_dir, &mut documents)?; + } + + // Read template file + let template_path = Path::new("src/docs.rs.template"); + let template_content = fs::read_to_string(template_path)?; + + // Extract template sections preserving original indentation + let document_template = template_content + .split(TEMPLATE_DOCUMENT_BEGIN) + .nth(1) + .and_then(|s| s.split(TEMPLATE_DOCUMENT_END).next()) + .unwrap_or("") + .trim_start_matches('\n') + .trim_end_matches('\n'); + + let match_arm_template = template_content + .split(TEMPLATE_FUNC_BEGIN) + .nth(1) + .and_then(|s| s.split(TEMPLATE_FUNC_END).next()) + .unwrap_or("") + .trim_start_matches('\n') + .trim_end_matches('\n'); + + // Generate document blocks and match arms + let mut document_blocks = String::new(); + let mut match_arms = String::new(); + let mut list_items = String::new(); + + for (relative_path, content) in &documents { + // Calculate parameters for template substitution + let document_path = format!("./docs/Documents/{}", relative_path); + + // Generate constant name from relative path + let document_constant_name = relative_path + .replace(['/', '\\', '-'], "_") + .replace(".md", "") + .replace(".txt", "") + .replace(".toml", "") + .replace(".yaml", "") + .replace(".yml", "") + .replace(".json", "") + .replace(".rs", "") + .to_uppercase(); + + // Generate snake_case name for function matching + let document_path_snake_case = relative_path + .replace(['/', '\\', '-'], "_") + .replace(".md", "") + .replace(".txt", "") + .replace(".toml", "") + .replace(".yaml", "") + .replace(".yml", "") + .replace(".json", "") + .replace(".rs", "") + .to_lowercase(); + + // Escape double quotes in content + let escaped_content = content.trim().replace('\"', "\\\""); + + // Replace template parameters in document block preserving indentation + let document_block = document_template + .replace(PARAM_DOCUMENT_PATH, &document_path) + .replace(PARAM_DOCUMENT_CONSTANT_NAME, &document_constant_name) + .replace(PARAM_DOCUMENT_CONTENT, &escaped_content) + .replace("r#\"\"#", &format!("r#\"{}\"#", escaped_content)); + + document_blocks.push_str(&document_block); + document_blocks.push_str("\n\n"); + + // Replace template parameters in match arm preserving indentation + let match_arm = match_arm_template + .replace(PARAM_DOCUMENT_PATH_SNAKE_CASE, &document_path_snake_case) + .replace(PARAM_DOCUMENT_CONSTANT_NAME, &document_constant_name); + + match_arms.push_str(&match_arm); + match_arms.push('\n'); + + // Generate list item for documents() function + let list_item = format!(" \"{}\".to_string(),", document_path_snake_case); + list_items.push_str(&list_item); + list_items.push('\n'); + } + + // Remove trailing newline from the last list item + if !list_items.is_empty() { + list_items.pop(); + } + + // Build final output by replacing template sections + let mut output = String::new(); + + // Add header before document blocks + if let Some(header) = template_content.split(TEMPLATE_DOCUMENT_BEGIN).next() { + output.push_str(header.trim()); + output.push_str("\n\n"); + } + + // Add document blocks + output.push_str(&document_blocks); + + // Add function section + if let Some(func_section) = template_content.split(TEMPLATE_FUNC_BEGIN).next() + && let Some(rest) = func_section.split(TEMPLATE_DOCUMENT_END).nth(1) + { + output.push_str(rest.trim()); + output.push('\n'); + } + + // Add match arms + output.push_str(&match_arms); + + // Add list items for documents() function + if let Some(list_section) = template_content.split(TEMPLATE_LIST_BEGIN).next() + && let Some(rest) = list_section.split(TEMPLATE_FUNC_END).nth(1) + { + output.push_str(rest.trim()); + output.push('\n'); + } + output.push_str(&list_items); + + // Add footer + if let Some(footer) = template_content.split(TEMPLATE_LIST_END).nth(1) { + // Preserve original indentation in footer + output.push_str(footer); + } + + // Write generated file + let mut file = fs::File::create(&dest_path)?; + file.write_all(output.as_bytes())?; + + // Copy to src directory for development + let src_dest_path = Path::new("src/docs.rs"); + fs::write(src_dest_path, output)?; + + Ok(()) +} + +fn collect_text_files(dir: &Path, documents: &mut Vec<(String, String)>) -> io::Result<()> { + for entry in fs::read_dir(dir)? { + let entry = entry?; + let path = entry.path(); + + if path.is_dir() { + collect_text_files(&path, documents)?; + } else if path.extension().is_some_and(|ext| { + ext == "md" + || ext == "txt" + || ext == "toml" + || ext == "yaml" + || ext == "yml" + || ext == "json" + || ext == "rs" + }) && let Ok(relative_path) = path.strip_prefix("./Documents") + && let Some(relative_path_str) = relative_path.to_str() + { + let content = fs::read_to_string(&path)?; + documents.push(( + relative_path_str.trim_start_matches('/').to_string(), + content, + )); + } + } + Ok(()) +} |
