From aa69757a01c26cfad12498053c55cbc3d66a4bdb Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 23 Jun 2020 22:27:24 +0200 Subject: More principled indentation trimming in fixtures --- crates/stdx/src/lib.rs | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) (limited to 'crates/stdx') diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs index 100db9d5d..08ac6f70f 100644 --- a/crates/stdx/src/lib.rs +++ b/crates/stdx/src/lib.rs @@ -128,3 +128,85 @@ pub fn split_delim(haystack: &str, delim: char) -> Option<(&str, &str)> { let idx = haystack.find(delim)?; Some((&haystack[..idx], &haystack[idx + delim.len_utf8()..])) } + +pub fn trim_indent(mut text: &str) -> String { + if text.starts_with('\n') { + text = &text[1..]; + } + let indent = text + .lines() + .filter(|it| !it.trim().is_empty()) + .map(|it| it.len() - it.trim_start().len()) + .min() + .unwrap_or(0); + lines_with_ends(text) + .map( + |line| { + if line.len() <= indent { + line.trim_start_matches(' ') + } else { + &line[indent..] + } + }, + ) + .collect() +} + +pub fn lines_with_ends(text: &str) -> LinesWithEnds { + LinesWithEnds { text } +} + +pub struct LinesWithEnds<'a> { + text: &'a str, +} + +impl<'a> Iterator for LinesWithEnds<'a> { + type Item = &'a str; + fn next(&mut self) -> Option<&'a str> { + if self.text.is_empty() { + return None; + } + let idx = self.text.find('\n').map_or(self.text.len(), |it| it + 1); + let (res, next) = self.text.split_at(idx); + self.text = next; + Some(res) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_trim_indent() { + assert_eq!(trim_indent(""), ""); + assert_eq!( + trim_indent( + " + hello + world +" + ), + "hello\nworld\n" + ); + assert_eq!( + trim_indent( + " + hello + world" + ), + "hello\nworld" + ); + assert_eq!(trim_indent(" hello\n world\n"), "hello\nworld\n"); + assert_eq!( + trim_indent( + " + fn main() { + return 92; + } + " + ), + "fn main() {\n return 92;\n}\n" + ); + } +} -- cgit v1.2.3