impl Display for LitLinesCrlf<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let input = &self.0;
-
- // TODO don't collect
- // TODO more principled indentation handling
- let output = input.split_inclusive('\n')
- .map(|s| s.trim_start_matches(&[' ','\t'][..]))
- .map(|s| match s.strip_suffix("\n") {
- None => [s, ""],
- Some(l) => [l, "\r\n"],
- })
- .flatten()
- .collect::<String>();
-
- write!(f, "{output}")
+ let input = self.0.split_inclusive('\n');
+
+ // Use indentation from first nonempty line
+ let indent = input.clone()
+ .filter_map(|l| {
+ let trimmed = l.trim_start();
+ if trimmed.is_empty() {
+ None
+ } else {
+ Some(l.len() - trimmed.len())
+ }
+ })
+ .next()
+ .unwrap_or(0);
+
+ for l in input {
+ let (l, nl) = l.strip_suffix("\n")
+ .map(|l| (l, Some(())))
+ .unwrap_or((l, None));
+
+ let (spc, content) = l.split_at_checked(indent).unwrap_or((l, ""));
+ assert!(spc.trim().is_empty(), "non-blank indent {:?} in {:?}", spc, l);
+ write!(f, "{content}")?;
+ if let Some(()) = nl {
+ write!(f, "\r\n")?;
+ }
+ }
+
+ Ok(())
}
}