diff options
| -rw-r--r-- | src/fenced_md_generator.rs | 30 | ||||
| -rw-r--r-- | src/main.rs | 2 | ||||
| -rw-r--r-- | src/md_generator.rs | 76 | ||||
| -rw-r--r-- | src/renderer.rs | 60 |
4 files changed, 125 insertions, 43 deletions
diff --git a/src/fenced_md_generator.rs b/src/fenced_md_generator.rs index 078a8cb..41ca8cc 100644 --- a/src/fenced_md_generator.rs +++ b/src/fenced_md_generator.rs @@ -4,13 +4,14 @@ use std::{ }; use crate::{ - logger::Logger, md_generator::generate_markdown_from_paths, + logger::Logger, md_generator::generate_markdown_from_paths, renderer::RenderOptions, util::fence::generate_outer_backticks, }; pub fn generate_fenced_markdown<R: Read, W: Write>( input: R, mut output: W, + render_options: RenderOptions, root: &Path, origin_base: &Path, project_title: Option<&str>, @@ -20,6 +21,7 @@ pub fn generate_fenced_markdown<R: Read, W: Write>( generate_markdown_from_paths( input, &mut md_output, + render_options, root, origin_base, project_title, @@ -39,10 +41,11 @@ mod tests { use tempfile::tempdir; use crate::logger::Logger; + use crate::renderer::RenderOptions; use super::generate_fenced_markdown; - fn wrap_with_default_logger<R: Read, W: Write>( + fn wrap_with_defaults<R: Read, W: Write>( input: R, output: W, root: &std::path::Path, @@ -50,7 +53,16 @@ mod tests { project_title: Option<&str>, ) -> Result<(), Box<dyn std::error::Error>> { let logger = Logger::default(); - generate_fenced_markdown(input, output, root, origin_base, project_title, logger) + let render_options = RenderOptions::default(); + generate_fenced_markdown( + input, + output, + render_options, + root, + origin_base, + project_title, + logger, + ) } #[test] @@ -61,8 +73,7 @@ mod tests { let root = temp_dir.path(); let origin_base = temp_dir.path(); - wrap_with_default_logger(input, &mut output, root, origin_base, Some("Project name")) - .unwrap(); + wrap_with_defaults(input, &mut output, root, origin_base, Some("Project name")).unwrap(); assert_eq!( String::from_utf8(output).unwrap(), @@ -80,7 +91,7 @@ mod tests { fs::write(origin_base.join("test_main.rs"), "fn main() {}").unwrap(); - wrap_with_default_logger(input, &mut output, root, origin_base, None).unwrap(); + wrap_with_defaults(input, &mut output, root, origin_base, None).unwrap(); let output_str = String::from_utf8(output).unwrap(); // Must contain outer fence @@ -102,7 +113,7 @@ mod tests { fs::write(origin_base.join("a.rs"), "A").unwrap(); fs::write(origin_base.join("b.rs"), "B").unwrap(); - wrap_with_default_logger(input, &mut output, root, origin_base, None).unwrap(); + wrap_with_defaults(input, &mut output, root, origin_base, None).unwrap(); let output_str = String::from_utf8(output).unwrap(); // Each inner file must have its own languageāspecific fence @@ -124,7 +135,7 @@ mod tests { let content = "````"; // 4 backticks fs::write(origin_base.join("backticks.rs"), content).unwrap(); - wrap_with_default_logger(input, &mut output, root, origin_base, None).unwrap(); + wrap_with_defaults(input, &mut output, root, origin_base, None).unwrap(); let output_str = String::from_utf8(output).unwrap(); // Inner fence should be 5 backticks because inner content contains 4 backticks @@ -143,8 +154,7 @@ mod tests { let origin_base = temp_dir.path(); let project_title = "Project ``` name"; - wrap_with_default_logger(input, &mut output, root, origin_base, Some(project_title)) - .unwrap(); + wrap_with_defaults(input, &mut output, root, origin_base, Some(project_title)).unwrap(); let output_str = String::from_utf8(output).unwrap(); // Outer fence must be 4 backticks because the header contains 3 backticks diff --git a/src/main.rs b/src/main.rs index 5472198..34c4f88 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ use std::{ use repo2markdown::{ logger::{Logger, Verbosity}, md_generator::generate_markdown_from_paths, + renderer::RenderOptions, }; fn main() -> Result<(), Box<dyn std::error::Error>> { @@ -45,6 +46,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> { generate_markdown_from_paths( stdin.lock(), stdout.lock(), + RenderOptions::default(), root, origin, name.as_deref(), diff --git a/src/md_generator.rs b/src/md_generator.rs index 44802af..98ab22d 100644 --- a/src/md_generator.rs +++ b/src/md_generator.rs @@ -7,7 +7,10 @@ use std::{ }; use crate::{ - logger::Logger, normalizer::Normalizer, renderer::Renderer, util::path_display::display_path, + logger::Logger, + normalizer::Normalizer, + renderer::{RenderOptions, Renderer}, + util::path_display::display_path, }; const DEFAULT_PROJECT_NAME: &str = "Project Outline"; @@ -15,6 +18,7 @@ const DEFAULT_PROJECT_NAME: &str = "Project Outline"; pub fn generate_markdown_from_paths<R: Read, W: Write>( mut input: R, output: W, + render_options: RenderOptions, root: &Path, origin_base: &Path, project_title: Option<&str>, @@ -25,7 +29,7 @@ pub fn generate_markdown_from_paths<R: Read, W: Write>( let normalizer = Normalizer::new(root, origin_base)?; - let mut renderer = Renderer::new(output).with_logger(logger); + let mut renderer = Renderer::new(output, render_options).with_logger(logger); let project_title = project_title.unwrap_or_else(|| derive_project_title(root)); renderer.render_header(project_title)?; @@ -68,6 +72,7 @@ mod tests { use std::path::Path; use crate::logger::Logger; + use crate::renderer::RenderOptions; use tempfile::tempdir; use super::{DEFAULT_PROJECT_NAME, derive_project_title, generate_markdown_from_paths}; @@ -81,7 +86,7 @@ mod tests { output } - fn run_with_default_logger<R: Read, W: Write>( + fn generate_with_defaults<R: Read, W: Write>( input: R, output: W, root: &Path, @@ -89,7 +94,16 @@ mod tests { project_title: Option<&str>, ) -> Result<(), Box<dyn std::error::Error>> { let logger = Logger::default(); - generate_markdown_from_paths(input, output, root, origin_base, project_title, logger) + let render_options = RenderOptions::default(); + generate_markdown_from_paths( + input, + output, + render_options, + root, + origin_base, + project_title, + logger, + ) } #[test] @@ -100,7 +114,7 @@ mod tests { let root = temp_dir.path(); let origin_base = temp_dir.path(); - run_with_default_logger(input, &mut output, root, origin_base, Some("Project name")) + generate_with_defaults(input, &mut output, root, origin_base, Some("Project name")) .unwrap(); assert_eq!(String::from_utf8(output).unwrap(), "# Project name\n"); @@ -116,7 +130,7 @@ mod tests { fs::write(origin_base.join("test_main.rs"), "fn main() {}").unwrap(); - run_with_default_logger(input, &mut output, root, origin_base, None).unwrap(); + generate_with_defaults(input, &mut output, root, origin_base, None).unwrap(); let output_str = String::from_utf8(output).unwrap(); @@ -135,7 +149,7 @@ mod tests { fs::write(origin_base.join("a.rs"), "A").unwrap(); fs::write(origin_base.join("b.rs"), "B").unwrap(); - run_with_default_logger(input, &mut output, root, origin_base, None).unwrap(); + generate_with_defaults(input, &mut output, root, origin_base, None).unwrap(); let output = String::from_utf8(output).unwrap(); @@ -157,7 +171,7 @@ mod tests { fs::create_dir_all(&write_dir).unwrap(); fs::write(write_dir.join("main.rs"), "fn main() {}").unwrap(); - run_with_default_logger(input, &mut output, root, origin_base, None).unwrap(); + generate_with_defaults(input, &mut output, root, origin_base, None).unwrap(); let output = String::from_utf8(output).unwrap(); @@ -175,7 +189,7 @@ mod tests { fs::create_dir_all(&origin_base).unwrap(); fs::write(origin_base.join("main.rs"), "fn main() {}").unwrap(); - run_with_default_logger(input, &mut output, &root, &origin_base, None).unwrap(); + generate_with_defaults(input, &mut output, &root, &origin_base, None).unwrap(); let output = String::from_utf8(output).unwrap(); @@ -197,7 +211,7 @@ mod tests { let root = temp_dir2.path(); fs::write(&filepath, "fn main() {}").unwrap(); - run_with_default_logger(input, &mut output, root, origin_base, None).unwrap(); + generate_with_defaults(input, &mut output, root, origin_base, None).unwrap(); let output = String::from_utf8(output).unwrap(); @@ -216,7 +230,7 @@ mod tests { let input = Cursor::new(b"a.rs\0a.rs\0"); let mut output = Vec::new(); - run_with_default_logger(input, &mut output, root, origin, None).unwrap(); + generate_with_defaults(input, &mut output, root, origin, None).unwrap(); let output = String::from_utf8(output).unwrap(); @@ -235,7 +249,7 @@ mod tests { let input = Cursor::new(b"a.rs\0b.rs\0a.rs\0"); let mut output = Vec::new(); - run_with_default_logger(input, &mut output, root, origin, None).unwrap(); + generate_with_defaults(input, &mut output, root, origin, None).unwrap(); let output = String::from_utf8(output).unwrap(); assert_eq!(output.matches("## File: a.rs").count(), 1); @@ -258,7 +272,7 @@ mod tests { let input = Cursor::new(b"a.rs\0b.rs\0bla/../a.rs\0"); let mut output = Vec::new(); - run_with_default_logger(input, &mut output, root, origin, None).unwrap(); + generate_with_defaults(input, &mut output, root, origin, None).unwrap(); let output = String::from_utf8(output).unwrap(); assert_eq!(output.matches("## File: a.rs").count(), 1); @@ -272,7 +286,7 @@ mod tests { let mut output = Vec::new(); let root = temp_dir.path().join("repo2markdown"); - run_with_default_logger(input, &mut output, &root, origin_base, None).unwrap(); + generate_with_defaults(input, &mut output, &root, origin_base, None).unwrap(); let output_str = String::from_utf8(output).unwrap(); @@ -295,4 +309,38 @@ mod tests { let root = Path::new("/root/repo2markdown/"); assert_eq!(derive_project_title(root), "repo2markdown"); } + + #[test] + fn generator_uses_render_options_for_large_file_placeholders() { + let temp_dir = tempdir().unwrap(); + let origin_base = temp_dir.path(); + let root = temp_dir.path(); + + let file_path = origin_base.join("big.txt"); + fs::write(&file_path, "A".repeat(10)).unwrap(); + + let input = Cursor::new(b"big.txt\0"); + let mut output = Vec::new(); + + let config = RenderOptions { + placeholder_for_binary_files: false, + placeholder_for_large_files: true, + max_file_size: 5, + }; + + generate_markdown_from_paths( + input, + &mut output, + config, + root, + origin_base, + None, + Logger::default(), + ) + .unwrap(); + + let output = String::from_utf8(output).unwrap(); + assert!(output.contains("## File: big.txt")); + assert!(output.contains("[FILE TOO LARGE]")); + } } diff --git a/src/renderer.rs b/src/renderer.rs index d9cf7b4..4223a00 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -24,13 +24,17 @@ pub struct Renderer<W: Write> { } impl<W: Write> Renderer<W> { - pub fn new(output: W) -> Self { + pub fn new_with_defaults(output: W) -> Self { + Self::new(output, RenderOptions::default()) + } + + pub fn new(output: W, config: RenderOptions) -> Self { Self { output, - max_file_size: DEFAULT_MAX_FILE_SIZE, + max_file_size: config.max_file_size, logger: Logger::default(), - placeholder_for_binary_files: false, - placeholder_for_large_files: false, + placeholder_for_binary_files: config.placeholder_for_binary_files, + placeholder_for_large_files: config.placeholder_for_large_files, } } @@ -133,6 +137,23 @@ impl<W: Write> Renderer<W> { } } +#[derive(Debug, Clone, Copy)] +pub struct RenderOptions { + pub max_file_size: u64, + pub placeholder_for_binary_files: bool, + pub placeholder_for_large_files: bool, +} + +impl Default for RenderOptions { + fn default() -> Self { + RenderOptions { + max_file_size: DEFAULT_MAX_FILE_SIZE, + placeholder_for_binary_files: false, + placeholder_for_large_files: false, + } + } +} + fn human_readable_size(bytes: u64) -> String { const UNITS: [&str; 5] = ["B", "KiB", "MiB", "GiB", "TiB"]; @@ -169,7 +190,7 @@ mod tests { #[test] fn renderer_writes_header() { let mut output = Vec::new(); - let mut renderer = Renderer::new(&mut output); + let mut renderer = Renderer::new_with_defaults(&mut output); renderer.render_header("Project name").unwrap(); @@ -179,7 +200,7 @@ mod tests { #[test] fn renderer_renders_single_rust_file_with_language_fence() { let mut output = Vec::new(); - let mut renderer = Renderer::new(&mut output); + let mut renderer = Renderer::new_with_defaults(&mut output); let input = Cursor::new("fn main() {}"); renderer.render_file(Path::new("main.rs"), input).unwrap(); @@ -191,7 +212,7 @@ mod tests { #[test] fn binary_files_are_not_included_in_output_at_all_by_default() { let mut output = Vec::new(); - let mut renderer = Renderer::new(&mut output); + let mut renderer = Renderer::new_with_defaults(&mut output); let input = Cursor::new(&[0x00, 0x01, 0x02, 0xc3]); renderer.render_file(Path::new("image.png"), input).unwrap(); @@ -203,7 +224,8 @@ mod tests { #[test] fn renderer_can_place_a_placeholder_for_binary_files() { let mut output = Vec::new(); - let mut renderer = Renderer::new(&mut output).with_binary_file_placeholder(true); + let mut renderer = + Renderer::new_with_defaults(&mut output).with_binary_file_placeholder(true); let input = Cursor::new(&[0x00, 0x01, 0x02, 0xc3]); renderer.render_file(Path::new("image.png"), input).unwrap(); @@ -215,7 +237,7 @@ mod tests { #[test] fn filename_with_linebreaks_and_invalid_chars_handled_properly() { let mut output = Vec::new(); - let mut renderer = Renderer::new(&mut output); + let mut renderer = Renderer::new_with_defaults(&mut output); let input = Cursor::new("fn main() {}"); let filename = Path::new(OsStr::from_bytes(b"jap\xE3\x81\x82dir/some\nma\xc3in.rs")); @@ -228,7 +250,7 @@ mod tests { #[test] fn file_with_backticks_is_handled_safely() { let mut output = Vec::new(); - let mut renderer = Renderer::new(&mut output); + let mut renderer = Renderer::new_with_defaults(&mut output); let input = Cursor::new("fn main() { println!(\"``` inside\"); }"); renderer @@ -243,7 +265,7 @@ mod tests { #[test] fn unknown_filetype_has_no_language_fence() { let mut output = Vec::new(); - let mut renderer = Renderer::new(&mut output); + let mut renderer = Renderer::new_with_defaults(&mut output); let input = Cursor::new("hello world"); renderer.render_file(Path::new("readme"), input).unwrap(); @@ -255,7 +277,7 @@ mod tests { #[test] fn txt_file_has_no_language_fence() { let mut output = Vec::new(); - let mut renderer = Renderer::new(&mut output); + let mut renderer = Renderer::new_with_defaults(&mut output); let input = Cursor::new("hello world"); renderer.render_file(Path::new("hello.txt"), input).unwrap(); @@ -267,7 +289,7 @@ mod tests { #[test] fn python_file_has_python_language_fence() { let mut output = Vec::new(); - let mut renderer = Renderer::new(&mut output); + let mut renderer = Renderer::new_with_defaults(&mut output); let input = Cursor::new("print('hello')"); renderer.render_file(Path::new("main.py"), input).unwrap(); @@ -279,7 +301,7 @@ mod tests { #[test] fn json_file_has_json_language_fence() { let mut output = Vec::new(); - let mut renderer = Renderer::new(&mut output); + let mut renderer = Renderer::new_with_defaults(&mut output); let input = Cursor::new("{\"key\":\"value\"}"); renderer.render_file(Path::new("main.json"), input).unwrap(); @@ -291,7 +313,7 @@ mod tests { #[test] fn uppercase_extension_is_still_detected() { let mut output = Vec::new(); - let mut renderer = Renderer::new(&mut output); + let mut renderer = Renderer::new_with_defaults(&mut output); let input = Cursor::new("fn main() {}"); renderer.render_file(Path::new("MAIN.RS"), input).unwrap(); @@ -303,7 +325,7 @@ mod tests { #[test] fn bash_file_detected_from_shebang() { let mut output = Vec::new(); - let mut renderer = Renderer::new(&mut output); + let mut renderer = Renderer::new_with_defaults(&mut output); let input = Cursor::new("#! /bin/bash\necho hello"); renderer.render_file(Path::new("hello"), input).unwrap(); @@ -315,7 +337,7 @@ mod tests { #[test] fn python_file_detected_from_shebang() { let mut output = Vec::new(); - let mut renderer = Renderer::new(&mut output); + let mut renderer = Renderer::new_with_defaults(&mut output); let input = Cursor::new("#! /bin/python3\nprint('hello')"); renderer.render_file(Path::new("hello"), input).unwrap(); @@ -327,7 +349,7 @@ mod tests { #[test] fn large_files_are_not_included_in_output_at_all_by_default() { let mut output = Vec::new(); - let mut renderer = Renderer::new(&mut output).with_max_file_size(5); // smaller than file + let mut renderer = Renderer::new_with_defaults(&mut output).with_max_file_size(5); // smaller than file let temp_dir = tempdir().unwrap(); let file_path = temp_dir.path().join("big.txt"); @@ -348,7 +370,7 @@ mod tests { #[test] fn renderer_can_place_a_placeholder_for_large_files() { let mut output = Vec::new(); - let mut renderer = Renderer::new(&mut output) + let mut renderer = Renderer::new_with_defaults(&mut output) .with_large_file_placeholder(true) .with_max_file_size(5); // smaller than file |
