summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/fenced_md_generator.rs30
-rw-r--r--src/main.rs2
-rw-r--r--src/md_generator.rs76
-rw-r--r--src/renderer.rs60
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