summaryrefslogtreecommitdiff
path: root/src/renderer.rs
diff options
context:
space:
mode:
authorA Farzat <a@farzat.xyz>2026-06-04 13:39:01 +0300
committerA Farzat <a@farzat.xyz>2026-06-04 13:39:01 +0300
commit54cc2bf0701e4b6f04a7345ca6d4d761fa76949b (patch)
treeeb024c14b6c84ccaaa5e2fd08f35d1bf7f5d438c /src/renderer.rs
parent6d7a879bdf848f8c40dd39ed8cfb0c48012d17f1 (diff)
downloadrepo2markdown-54cc2bf0701e4b6f04a7345ca6d4d761fa76949b.tar.gz
repo2markdown-54cc2bf0701e4b6f04a7345ca6d4d761fa76949b.zip
Escape non-standard paths in the markdown file
Diffstat (limited to 'src/renderer.rs')
-rw-r--r--src/renderer.rs68
1 files changed, 47 insertions, 21 deletions
diff --git a/src/renderer.rs b/src/renderer.rs
index 583730a..6aa5ac7 100644
--- a/src/renderer.rs
+++ b/src/renderer.rs
@@ -1,15 +1,18 @@
-use std::fmt;
+use std::{
+ fmt,
+ path::{Path, PathBuf},
+};
#[derive(Debug)]
pub enum RenderError {
- BinaryFile(String),
+ BinaryFile(PathBuf),
}
impl fmt::Display for RenderError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
RenderError::BinaryFile(filename) => {
- write!(f, "Binary file encountered: {}", filename)
+ write!(f, "Binary file encountered: {:?}", filename)
}
}
}
@@ -17,17 +20,17 @@ impl fmt::Display for RenderError {
impl std::error::Error for RenderError {}
-pub fn render(project_name: &str, files: &[(&str, &[u8])]) -> Result<String, RenderError> {
+pub fn render(project_name: &str, files: &[(&Path, &[u8])]) -> Result<String, RenderError> {
let mut output = format!("# {}\n", project_name);
if !files.is_empty() {
output.push_str("\n## Files\n");
}
for (filename, bytes) in files {
let content = std::str::from_utf8(bytes)
- .map_err(|_| RenderError::BinaryFile(filename.to_string()))?;
+ .map_err(|_| RenderError::BinaryFile(filename.to_path_buf()))?;
let outer_backticks = outer_backticks(content);
output.push_str(&format!(
- "\n### {}\n{}\n{}\n{}\n",
+ "\n### {:?}\n{}\n{}\n{}\n",
filename, outer_backticks, content, outer_backticks
));
}
@@ -53,6 +56,8 @@ fn outer_backticks(contents: &str) -> String {
#[cfg(test)]
mod tests {
+ use std::{ffi::OsStr, os::unix::ffi::OsStrExt, path::Path};
+
use super::{RenderError, render};
#[test]
@@ -63,7 +68,7 @@ mod tests {
#[test]
fn single_file_is_rendered() {
- let files: Vec<(&str, &[u8])> = vec![("main.rs", b"fn main() {}")];
+ let files: Vec<(&Path, &[u8])> = vec![(Path::new("main.rs"), b"fn main() {}")];
let output = render("Project name", &files);
@@ -71,7 +76,7 @@ mod tests {
output.unwrap(),
"# Project name\n\n\
## Files\n\n\
- ### main.rs\n\
+ ### \"main.rs\"\n\
```\n\
fn main() {}\n\
```\n"
@@ -80,9 +85,9 @@ mod tests {
#[test]
fn multiple_files_are_rendered_in_order() {
- let files: Vec<(&str, &[u8])> = vec![
- ("main.rs", b"fn main() {}"),
- ("lib.rs", b"pub fn hello() {}"),
+ let files: Vec<(&Path, &[u8])> = vec![
+ (Path::new("main.rs"), b"fn main() {}"),
+ (Path::new("lib.rs"), b"pub fn hello() {}"),
];
let output = render("Project name", &files);
@@ -91,11 +96,11 @@ mod tests {
output.unwrap(),
"# Project name\n\n\
## Files\n\n\
- ### main.rs\n\
+ ### \"main.rs\"\n\
```\n\
fn main() {}\n\
```\n\n\
- ### lib.rs\n\
+ ### \"lib.rs\"\n\
```\n\
pub fn hello() {}\n\
```\n"
@@ -104,8 +109,10 @@ mod tests {
#[test]
fn file_with_backticks_is_handled_safely() {
- let files: Vec<(&str, &[u8])> =
- vec![("example.rs", b"fn main() { println!(\"``` inside\"); }")];
+ let files: Vec<(&Path, &[u8])> = vec![(
+ Path::new("example.rs"),
+ b"fn main() { println!(\"``` inside\"); }",
+ )];
let output = render("Project name", &files);
@@ -113,7 +120,7 @@ mod tests {
output.unwrap(),
"# Project name\n\n\
## Files\n\n\
- ### example.rs\n\
+ ### \"example.rs\"\n\
````\n\
fn main() { println!(\"``` inside\"); }\n\
````\n"
@@ -122,13 +129,32 @@ mod tests {
#[test]
fn binary_file_is_rejected() {
- let files: Vec<(&str, &[u8])> = vec![("image.png", &[0x00, 0x01, 0x02, 0xc3])];
+ let files: Vec<(&Path, &[u8])> = vec![(Path::new("image.png"), &[0x00, 0x01, 0x02, 0xc3])];
let result = render("Project name", &files);
- assert!(matches!(
- result,
- Err(RenderError::BinaryFile(name)) if name == "image.png"
- ));
+ assert!(
+ matches!(result, Err(RenderError::BinaryFile(name)) if name == Path::new("image.png"))
+ );
+ }
+
+ #[test]
+ fn filename_with_linebreaks_and_invalid_chars_handled_properly() {
+ let files: Vec<(&Path, &[u8])> = vec![(
+ Path::new(OsStr::from_bytes(b"some\nma\xc3in.rs")),
+ b"fn main() {}",
+ )];
+
+ let output = render("Project name", &files);
+
+ assert_eq!(
+ output.unwrap(),
+ "# Project name\n\n\
+ ## Files\n\n\
+ ### \"some\\nma\\xC3in.rs\"\n\
+ ```\n\
+ fn main() {}\n\
+ ```\n"
+ );
}
}