diff options
| author | A Farzat <a@farzat.xyz> | 2026-06-04 06:55:08 +0300 |
|---|---|---|
| committer | A Farzat <a@farzat.xyz> | 2026-06-04 07:10:48 +0300 |
| commit | 390b990339630c84f423b9f2c3e2623ba5299d37 (patch) | |
| tree | 8cb78cd681926a2c519d1156175eef5edc2d2572 | |
| parent | 6c0a5c33d18de9fb56f4f3804c790a86707add75 (diff) | |
| download | repo2markdown-390b990339630c84f423b9f2c3e2623ba5299d37.tar.gz repo2markdown-390b990339630c84f423b9f2c3e2623ba5299d37.zip | |
Safely escape files with backticks
| -rw-r--r-- | src/renderer.rs | 61 |
1 files changed, 60 insertions, 1 deletions
diff --git a/src/renderer.rs b/src/renderer.rs index 518abd8..4965963 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -4,11 +4,32 @@ pub fn render(project_name: &str, files: &[(&str, &str)]) -> String { output.push_str("\n## Files\n"); } for (filename, content) in files { - output.push_str(&format!("\n### {}\n```\n{}\n```\n", filename, content)); + let outer_backticks = outer_backticks(content); + output.push_str(&format!( + "\n### {}\n{}\n{}\n{}\n", + filename, outer_backticks, content, outer_backticks + )); } output } +fn outer_backticks(contents: &str) -> String { + let mut max_ticks = 0; + let mut current_count = 0; + for char in contents.chars() { + if char == '`' { + current_count += 1; + if current_count > max_ticks { + max_ticks = current_count; + } + } else { + current_count = 0; + } + } + let fence_len = std::cmp::max(3, max_ticks + 1); + "`".repeat(fence_len) +} + #[cfg(test)] mod tests { use super::render; @@ -35,4 +56,42 @@ mod tests { ```\n" ); } + + #[test] + fn multiple_files_are_rendered_in_order() { + let files = vec![("main.rs", "fn main() {}"), ("lib.rs", "pub fn hello() {}")]; + + let output = render("Project name", &files); + + assert_eq!( + output, + "# Project name\n\n\ + ## Files\n\n\ + ### main.rs\n\ + ```\n\ + fn main() {}\n\ + ```\n\n\ + ### lib.rs\n\ + ```\n\ + pub fn hello() {}\n\ + ```\n" + ); + } + + #[test] + fn file_with_backticks_is_handled_safely() { + let files = vec![("example.rs", "fn main() { println!(\"``` inside\"); }")]; + + let output = render("Project name", &files); + + assert_eq!( + output, + "# Project name\n\n\ + ## Files\n\n\ + ### example.rs\n\ + ````\n\ + fn main() { println!(\"``` inside\"); }\n\ + ````\n" + ); + } } |
