From f54df9fd6d50030beee064bfd1415bad066107d2 Mon Sep 17 00:00:00 2001 From: A Farzat Date: Sat, 20 Jun 2026 16:58:01 +0300 Subject: Extract paths_from_null_separated_bytes to utils --- src/lib.rs | 8 +++++++- src/path_list_editor.rs | 16 ++++++--------- src/run.rs | 15 +++----------- src/util/mod.rs | 1 + src/util/path_list.rs | 52 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 69 insertions(+), 23 deletions(-) create mode 100644 src/util/path_list.rs diff --git a/src/lib.rs b/src/lib.rs index c35c0ea..4815653 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,8 @@ //! The crate is used by the main `repo2markdown` binary and by helper binaries such as //! `r2md-fence`, `r2md-append`, `r2md-prepend`, and `r2md-remove`. +mod util; + pub mod fence_wrapper; pub mod fenced_md_generator; pub mod logger; @@ -14,4 +16,8 @@ pub mod md_generator; pub mod normalizer; pub mod path_list_editor; pub mod renderer; -mod util; + +/// Utilities for working with null-separated path lists. +pub mod path_list { + pub use crate::util::path_list::paths_from_null_separated_bytes; +} diff --git a/src/path_list_editor.rs b/src/path_list_editor.rs index a740bf2..bdd6982 100644 --- a/src/path_list_editor.rs +++ b/src/path_list_editor.rs @@ -9,13 +9,13 @@ use std::{ collections::HashSet, - ffi::{OsStr, OsString}, + ffi::OsString, io::{Read, Write}, os::unix::ffi::OsStrExt, - path::{Path, PathBuf}, + path::PathBuf, }; -use crate::normalizer::Normalizer; +use crate::{normalizer::Normalizer, util::path_list::paths_from_null_separated_bytes}; const NUL: &[u8] = b"\0"; @@ -117,14 +117,10 @@ pub fn remove_paths( .iter() .map(|path| normalizer.normalize(path)) .collect::, _>>()?; - for segment in input_buf.split(|b| *b == 0) { - if segment.is_empty() { - continue; - } - let os_string_segment = OsStr::from_bytes(segment); - let normalized_path = normalizer.normalize(Path::new(os_string_segment))?; + for path in paths_from_null_separated_bytes(&input_buf) { + let normalized_path = normalizer.normalize(path)?; if !unwanted_paths.contains(&normalized_path) { - output.write_all(segment)?; + output.write_all(path.as_os_str().as_bytes())?; output.write_all(NUL)?; } } diff --git a/src/run.rs b/src/run.rs index 5b1a790..183ce6b 100644 --- a/src/run.rs +++ b/src/run.rs @@ -1,13 +1,8 @@ -use std::{ - ffi::OsStr, - io::{Read, Write}, - os::unix::ffi::OsStrExt, - path::Path, -}; +use std::io::{Read, Write}; use repo2markdown::{ fenced_md_generator::generate_fenced_markdown, logger::Logger, - md_generator::generate_markdown_from_paths, + md_generator::generate_markdown_from_paths, path_list::paths_from_null_separated_bytes, }; use crate::cli::Cli; @@ -21,11 +16,7 @@ pub fn run( let mut input_buf = Vec::new(); input.read_to_end(&mut input_buf)?; - let paths: Vec<&Path> = input_buf - .split(|b| *b == 0) - .filter(|bytes| !bytes.is_empty()) - .map(|bytes| Path::new(OsStr::from_bytes(bytes))) - .collect(); + let paths = paths_from_null_separated_bytes(&input_buf); if cli.fenced { generate_fenced_markdown( diff --git a/src/util/mod.rs b/src/util/mod.rs index 24ba6fc..eda8605 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -1,3 +1,4 @@ pub mod fence; pub mod language; pub mod path_display; +pub mod path_list; diff --git a/src/util/path_list.rs b/src/util/path_list.rs new file mode 100644 index 0000000..88f43b9 --- /dev/null +++ b/src/util/path_list.rs @@ -0,0 +1,52 @@ +//! Null-separated path-list parsing helpers. + +use std::{ffi::OsStr, os::unix::ffi::OsStrExt, path::Path}; + +/// Parses a NUL-separated path list into borrowed paths. +/// +/// Empty segments are ignored. Returned paths borrow from `bytes`. +pub fn paths_from_null_separated_bytes(bytes: &[u8]) -> Vec<&Path> { + bytes + .split(|byte| *byte == 0) + .filter(|segment| !segment.is_empty()) + .map(|segment| Path::new(OsStr::from_bytes(segment))) + .collect() +} + +#[cfg(test)] +mod tests { + use std::path::Path; + + use super::paths_from_null_separated_bytes; + + #[test] + fn paths_from_null_separated_bytes_returns_empty_list_for_empty_input() { + let paths = paths_from_null_separated_bytes(b""); + + assert!(paths.is_empty()); + } + + #[test] + fn paths_from_null_separated_bytes_ignores_empty_segments() { + let paths = paths_from_null_separated_bytes(b"\0a.rs\0\0b.rs\0"); + + assert_eq!(paths, vec![Path::new("a.rs"), Path::new("b.rs")]); + } + + #[test] + fn paths_from_null_separated_bytes_accepts_final_path_without_trailing_nul() { + let paths = paths_from_null_separated_bytes(b"a.rs\0b.rs"); + + assert_eq!(paths, vec![Path::new("a.rs"), Path::new("b.rs")]); + } + + #[test] + fn paths_from_null_separated_bytes_preserves_order() { + let paths = paths_from_null_separated_bytes(b"b.rs\0a.rs\0c.rs\0"); + + assert_eq!( + paths, + vec![Path::new("b.rs"), Path::new("a.rs"), Path::new("c.rs")] + ); + } +} -- cgit v1.3.1