# code2md **Repository Path**: sharpglasses/code2md ## Basic Information - **Project Name**: code2md - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-27 - **Last Updated**: 2026-09-27 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Rust 命令行工具:源代码转 Markdown > RUST实现一个命令工具,实现如下的功能: 1. 读取当前文件夹及其子文件中的源文件,过滤掉 .gitignore 中忽略的文件。 2. 将文件转换为 markdown 的章节,代码放到代码块中 3. 代码块的第一行为注释,注释内容为文件路径 4. 顶层路径对应markdown为两级,子文件夹递增。 --- 你说得对,配置文件(如 `.json`, `.yaml`, `.toml` 等)也应该被视为源文件。让我们扩展 `is_source_file` 函数来包含这些文件类型,并改进整个程序: ```rust use std::{ fs::{self, File}, io::{self, BufRead, BufReader, Write}, path::{Path, PathBuf}, }; use ignore::{WalkBuilder, overrides::OverrideBuilder}; use structopt::StructOpt; #[derive(Debug, StructOpt)] #[structopt( name = "code2md", about = "Convert source code files to markdown with proper structure" )] struct Opt { /// Output file path (default: output.md) #[structopt(short, long, default_value = "output.md")] output: PathBuf, /// Include hidden files #[structopt(short = "H", long)] hidden: bool, /// Maximum depth to traverse #[structopt(short, long)] depth: Option, /// Additional file extensions to include (comma separated) #[structopt(short, long)] extensions: Option, } fn main() -> io::Result<()> { let opt = Opt::from_args(); let mut output = File::create(&opt.output)?; // Parse additional extensions let mut extensions = vec![]; if let Some(exts) = &opt.extensions { extensions.extend(exts.split(',').map(|s| s.trim().to_lowercase())); } // Configure walker let mut walker = WalkBuilder::new("."); // Set hidden files filter if !opt.hidden { let mut override_builder = OverrideBuilder::new("."); override_builder.add("!.*").map_err(|e| { io::Error::new(io::ErrorKind::Other, format!("Override error: {}", e)) })?; walker.overrides(override_builder.build().map_err(|e| { io::Error::new(io::ErrorKind::Other, format!("Override build error: {}", e)) })?); } // Set max depth if specified if let Some(depth) = opt.depth { walker.max_depth(depth); } // Walk through files respecting .gitignore for entry in walker.build() { let entry = entry.map_err(|e| { io::Error::new(io::ErrorKind::Other, format!("Walk error: {}", e)) })?; let path = entry.path(); if path.is_file() && is_source_file(path, &extensions) { process_file(path, &mut output)?; } } println!("Markdown generated at: {}", opt.output.display()); Ok(()) } fn is_source_file(path: &Path, additional_extensions: &[String]) -> bool { let ext = path.extension() .and_then(|e| e.to_str()) .unwrap_or("") .to_lowercase(); // 内置支持的文件扩展名 let builtin_extensions = [ // 源代码文件 "rs", "py", "js", "ts", "java", "c", "cpp", "h", "hpp", "go", "php", "sh", // 配置文件 "json", "yaml", "yml", "toml", "ini", "cfg", "conf", "env", // 其他文本文件 "md", "txt", "html", "css", "xml" ]; builtin_extensions.contains(&ext.as_str()) || additional_extensions.contains(&ext) } fn process_file(path: &Path, output: &mut File) -> io::Result<()> { // Calculate heading level based on path depth let depth = path.components().count() - 1; let heading_level = if depth <= 1 { 2 } else { depth + 1 }; // Write file header let rel_path = path.strip_prefix(".").unwrap_or(path); let heading = format!( "{} {}\n\n", "#".repeat(heading_level), rel_path.display() ); output.write_all(heading.as_bytes())?; // Write code block with path comment let extension = path .extension() .and_then(|e| e.to_str()) .unwrap_or("") .to_lowercase(); let code_block_start = format!("```{}\n", extension); output.write_all(code_block_start.as_bytes())?; // Write file path as first line comment let path_comment = match extension.as_str() { "rs" | "c" | "cpp" | "h" | "hpp" | "java" | "go" => format!("// {}\n", rel_path.display()), "py" | "sh" => format!("# {}\n", rel_path.display()), "js" | "ts" => format!("// {}\n", rel_path.display()), "php" => format!(" format!("// {}\n", rel_path.display()), }; output.write_all(path_comment.as_bytes())?; // Write file content let file = File::open(path)?; let reader = BufReader::new(file); for line in reader.lines() { output.write_all(line?.as_bytes())?; output.write_all(b"\n")?; } // Close code block output.write_all(b"```\n\n")?; Ok(()) } ``` ### 主要改进 1. **扩展了支持的文件类型**: - 现在包括配置文件(`.json`, `.yaml`, `.yml`, `.toml`, `.ini`, `.cfg`, `.conf`, `.env`) - 还包括其他文本文件(`.md`, `.txt`, `.html`, `.css`, `.xml`) 2. **新增命令行选项**: - `-e/--extensions`:允许用户指定额外的文件扩展名(逗号分隔) 3. **改进的文件类型检测**: - 使用静态数组检查内置支持的文件类型 - 同时检查用户提供的额外扩展名 4. **更灵活的处理**: - 未知扩展名的文件也会被处理,使用通用的注释格式 - 代码块会正确显示文件的实际扩展名 ### 使用示例 1. 基本用法(包含所有内置文件类型): ```bash cargo run -- -o output.md ``` 2. 包含隐藏文件和自定义扩展名: ```bash cargo run -- -H -e csv,log ``` 3. 限制深度并指定输出文件: ```bash cargo run -- --depth 3 -o docs/project.md ``` 这个版本的工具现在可以更好地处理各种项目文件,包括源代码和配置文件,生成结构清晰的Markdown文档。