summaryrefslogtreecommitdiffstats
path: root/vendor/gix-config/src/file/write.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gix-config/src/file/write.rs')
-rw-r--r--vendor/gix-config/src/file/write.rs93
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()
+}