diff options
Diffstat (limited to 'vendor/gix-config/src/file/write.rs')
-rw-r--r-- | vendor/gix-config/src/file/write.rs | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/vendor/gix-config/src/file/write.rs b/vendor/gix-config/src/file/write.rs new file mode 100644 index 000000000..29024170d --- /dev/null +++ b/vendor/gix-config/src/file/write.rs @@ -0,0 +1,93 @@ +use bstr::{BStr, BString, ByteSlice}; + +use crate::{file::Section, parse::Event, File}; + +impl File<'_> { + /// Serialize this type into a `BString` for convenience. + /// + /// Note that `to_string()` can also be used, but might not be lossless. + #[must_use] + pub fn to_bstring(&self) -> BString { + let mut buf = Vec::new(); + self.write_to(&mut buf).expect("io error impossible"); + buf.into() + } + + /// Stream ourselves to the given `out` in order to reproduce this file mostly losslessly + /// as it was parsed, while writing only sections for which `filter` returns true. + pub fn write_to_filter( + &self, + mut out: impl std::io::Write, + mut filter: impl FnMut(&Section<'_>) -> bool, + ) -> std::io::Result<()> { + let nl = self.detect_newline_style(); + + { + for event in self.frontmatter_events.as_ref() { + event.write_to(&mut out)?; + } + + if !ends_with_newline(self.frontmatter_events.as_ref(), nl, true) && self.sections.values().any(&mut filter) + { + out.write_all(nl)?; + } + } + + let mut prev_section_ended_with_newline = true; + for section_id in &self.section_order { + if !prev_section_ended_with_newline { + out.write_all(nl)?; + } + let section = self.sections.get(section_id).expect("known section-id"); + if !filter(section) { + continue; + } + section.write_to(&mut out)?; + + prev_section_ended_with_newline = ends_with_newline(section.body.0.as_ref(), nl, false); + if let Some(post_matter) = self.frontmatter_post_section.get(section_id) { + if !prev_section_ended_with_newline { + out.write_all(nl)?; + } + for event in post_matter { + event.write_to(&mut out)?; + } + prev_section_ended_with_newline = ends_with_newline(post_matter, nl, prev_section_ended_with_newline); + } + } + + if !prev_section_ended_with_newline { + out.write_all(nl)?; + } + + Ok(()) + } + + /// Stream ourselves to the given `out`, in order to reproduce this file mostly losslessly + /// as it was parsed. + pub fn write_to(&self, out: impl std::io::Write) -> std::io::Result<()> { + self.write_to_filter(out, |_| true) + } +} + +pub(crate) fn ends_with_newline(e: &[crate::parse::Event<'_>], nl: impl AsRef<[u8]>, default: bool) -> bool { + if e.is_empty() { + return default; + } + e.iter() + .rev() + .take_while(|e| e.to_bstr_lossy().iter().all(|b| b.is_ascii_whitespace())) + .find_map(|e| e.to_bstr_lossy().contains_str(nl.as_ref()).then_some(true)) + .unwrap_or(false) +} + +pub(crate) fn extract_newline<'a>(e: &'a Event<'_>) -> Option<&'a BStr> { + match e { + Event::Newline(b) => b.as_ref().into(), + _ => None, + } +} + +pub(crate) fn platform_newline() -> &'static BStr { + if cfg!(windows) { "\r\n" } else { "\n" }.into() +} |