summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorA Farzat <a@farzat.xyz>2026-06-19 14:24:08 +0300
committerA Farzat <a@farzat.xyz>2026-06-19 14:28:16 +0300
commitbab2e079e37d75777ebf2849db69bdcf94c0a615 (patch)
tree9f76541cffb781bcdc9921409931f3117dadb1f7 /src
parent82b2555d858cc94c4c9b5655ee820d80540ea509 (diff)
downloadrepo2markdown-bab2e079e37d75777ebf2849db69bdcf94c0a615.tar.gz
repo2markdown-bab2e079e37d75777ebf2849db69bdcf94c0a615.zip
Add functions to edit stdin path list
These would be used to create binaries that manipulate the input before piping it back into repo2markdown.
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs1
-rw-r--r--src/path_list_editor.rs210
2 files changed, 211 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 43c66a1..b6ed259 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -3,5 +3,6 @@ pub mod fenced_md_generator;
pub mod logger;
pub mod md_generator;
pub mod normalizer;
+pub mod path_list_editor;
pub mod renderer;
mod util;
diff --git a/src/path_list_editor.rs b/src/path_list_editor.rs
new file mode 100644
index 0000000..e25b0db
--- /dev/null
+++ b/src/path_list_editor.rs
@@ -0,0 +1,210 @@
+use std::{
+ collections::HashSet,
+ ffi::{OsStr, OsString},
+ io::{Read, Write},
+ os::unix::ffi::OsStrExt,
+};
+
+pub fn append_paths<R: Read, W: Write>(
+ mut input: R,
+ mut output: W,
+ new_paths: &[OsString],
+) -> std::io::Result<()> {
+ std::io::copy(&mut input, &mut output)?;
+ for path in new_paths {
+ output.write_all(path.as_bytes())?;
+ output.write_all(b"\0")?;
+ }
+ Ok(())
+}
+
+pub fn prepend_paths<R: Read, W: Write>(
+ mut input: R,
+ mut output: W,
+ new_paths: &[OsString],
+) -> std::io::Result<()> {
+ for path in new_paths {
+ output.write_all(path.as_bytes())?;
+ output.write_all(b"\0")?;
+ }
+ std::io::copy(&mut input, &mut output)?;
+ Ok(())
+}
+
+pub fn remove_paths<R: Read, W: Write>(
+ mut input: R,
+ mut output: W,
+ unwanted_paths: &[OsString],
+) -> std::io::Result<()> {
+ let mut buf = Vec::new();
+ input.read_to_end(&mut buf)?;
+ let unwanted_paths = HashSet::<&OsString>::from_iter(unwanted_paths);
+ for segment in buf.split(|b| *b == 0) {
+ if segment.is_empty() {
+ continue;
+ }
+ let os_string_segment = OsStr::from_bytes(segment).to_os_string();
+ if !unwanted_paths.contains(&os_string_segment) {
+ output.write_all(segment)?;
+ output.write_all(b"\0")?;
+ }
+ }
+ Ok(())
+}
+
+#[cfg(test)]
+mod tests {
+ use std::ffi::OsString;
+
+ use super::{append_paths, prepend_paths, remove_paths};
+
+ #[test]
+ fn append_paths_works_with_empty_stdin_and_args() {
+ let input = b"";
+ let mut output = Vec::new();
+
+ append_paths(&input[..], &mut output, &[]).unwrap();
+
+ assert_eq!(output, b"");
+ }
+
+ #[test]
+ fn append_paths_works_with_empty_args() {
+ let input = b"README.md\0";
+ let mut output = Vec::new();
+
+ append_paths(&input[..], &mut output, &[]).unwrap();
+
+ assert_eq!(output, b"README.md\0");
+ }
+
+ #[test]
+ fn append_paths_works_with_empty_stdin() {
+ let input = b"";
+ let mut output = Vec::new();
+
+ append_paths(&input[..], &mut output, &[OsString::from("README.md")]).unwrap();
+
+ assert_eq!(output, b"README.md\0");
+ }
+
+ #[test]
+ fn append_paths_works_with_unique_stdin_and_args() {
+ let input = b"a.rs\0b.rs\0";
+ let mut output = Vec::new();
+
+ append_paths(&input[..], &mut output, &[OsString::from("c.rs")]).unwrap();
+
+ assert_eq!(output, b"a.rs\0b.rs\0c.rs\0");
+ }
+
+ #[test]
+ fn append_paths_keeps_duplicate_entries() {
+ let input = b"a.rs\0b.rs\0";
+ let mut output = Vec::new();
+
+ append_paths(&input[..], &mut output, &[OsString::from("a.rs")]).unwrap();
+
+ assert_eq!(output, b"a.rs\0b.rs\0a.rs\0");
+ }
+
+ #[test]
+ fn prepend_paths_works_with_empty_stdin_and_args() {
+ let input = b"";
+ let mut output = Vec::new();
+
+ prepend_paths(&input[..], &mut output, &[]).unwrap();
+
+ assert_eq!(output, b"");
+ }
+
+ #[test]
+ fn prepend_paths_works_with_empty_args() {
+ let input = b"README.md\0";
+ let mut output = Vec::new();
+
+ prepend_paths(&input[..], &mut output, &[]).unwrap();
+
+ assert_eq!(output, b"README.md\0");
+ }
+
+ #[test]
+ fn prepend_paths_works_with_empty_stdin() {
+ let input = b"";
+ let mut output = Vec::new();
+
+ prepend_paths(&input[..], &mut output, &[OsString::from("README.md")]).unwrap();
+
+ assert_eq!(output, b"README.md\0");
+ }
+
+ #[test]
+ fn prepend_paths_works_with_unique_stdin_and_args() {
+ let input = b"a.rs\0b.rs\0";
+ let mut output = Vec::new();
+
+ prepend_paths(&input[..], &mut output, &[OsString::from("c.rs")]).unwrap();
+
+ assert_eq!(output, b"c.rs\0a.rs\0b.rs\0");
+ }
+
+ #[test]
+ fn prepend_paths_keeps_duplicate_entries() {
+ let input = b"a.rs\0b.rs\0";
+ let mut output = Vec::new();
+
+ prepend_paths(&input[..], &mut output, &[OsString::from("a.rs")]).unwrap();
+
+ assert_eq!(output, b"a.rs\0a.rs\0b.rs\0");
+ }
+
+ #[test]
+ fn remove_paths_works_with_empty_stdin_and_args() {
+ let input = b"";
+ let mut output = Vec::new();
+
+ remove_paths(&input[..], &mut output, &[]).unwrap();
+
+ assert_eq!(output, b"");
+ }
+
+ #[test]
+ fn remove_paths_works_with_empty_args() {
+ let input = b"README.md\0";
+ let mut output = Vec::new();
+
+ remove_paths(&input[..], &mut output, &[]).unwrap();
+
+ assert_eq!(output, b"README.md\0");
+ }
+
+ #[test]
+ fn remove_paths_works_with_empty_stdin() {
+ let input = b"";
+ let mut output = Vec::new();
+
+ remove_paths(&input[..], &mut output, &[OsString::from("README.md")]).unwrap();
+
+ assert_eq!(output, b"");
+ }
+
+ #[test]
+ fn remove_paths_filters_matching_entries() {
+ let input = b"a.rs\0b.rs\0c.rs\0";
+ let mut output = Vec::new();
+
+ remove_paths(&input[..], &mut output, &[OsString::from("b.rs")]).unwrap();
+
+ assert_eq!(output, b"a.rs\0c.rs\0");
+ }
+
+ #[test]
+ fn remove_paths_removes_all_matching_entries() {
+ let input = b"a.rs\0b.rs\0b.rs\0c.rs\0";
+ let mut output = Vec::new();
+
+ remove_paths(&input[..], &mut output, &[OsString::from("b.rs")]).unwrap();
+
+ assert_eq!(output, b"a.rs\0c.rs\0");
+ }
+}