mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-01 15:51:12 +00:00
Avoid reallocation when ensuring trailing newline
This commit is contained in:
parent
da5fdf6d2f
commit
8f6f20b57d
2 changed files with 44 additions and 5 deletions
|
@ -181,8 +181,7 @@ fn fmt_all<'a>(arena: &'a Bump, buf: &mut Buf<'a>, ast: &'a Ast) {
|
||||||
fmt_def(buf, arena.alloc(def.value), 0);
|
fmt_def(buf, arena.alloc(def.value), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.trim_end();
|
buf.fmt_end_of_file();
|
||||||
buf.newline();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// RemoveSpaces normalizes the ast to something that we _expect_ to be invariant under formatting.
|
/// RemoveSpaces normalizes the ast to something that we _expect_ to be invariant under formatting.
|
||||||
|
|
|
@ -91,9 +91,49 @@ impl<'a> Buf<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trim_end(&mut self) {
|
/// Ensures the text ends in a newline with no whitespace preceding it.
|
||||||
while self.text.ends_with(char::is_whitespace) {
|
pub fn fmt_end_of_file(&mut self) {
|
||||||
self.text.truncate(self.text.len() - 1);
|
fmt_text_eof(&mut self.text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ensures the text ends in a newline with no whitespace preceding it.
|
||||||
|
fn fmt_text_eof(text: &mut bumpalo::collections::String<'_>) {
|
||||||
|
let mut chars_rev = text.chars().rev();
|
||||||
|
let mut last_whitespace = None;
|
||||||
|
let mut last_whitespace_index = text.len();
|
||||||
|
|
||||||
|
// Keep going until we either run out of characters or encounter one
|
||||||
|
// that isn't whitespace.
|
||||||
|
loop {
|
||||||
|
match chars_rev.next() {
|
||||||
|
Some(ch) if ch.is_whitespace() => {
|
||||||
|
last_whitespace = Some(ch);
|
||||||
|
last_whitespace_index -= 1;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match last_whitespace {
|
||||||
|
Some('\n') => {
|
||||||
|
// There may have been more whitespace after this newline; remove it!
|
||||||
|
text.truncate(last_whitespace_index + 1);
|
||||||
|
}
|
||||||
|
Some(_) => {
|
||||||
|
// There's some whitespace at the end of this file, but the first
|
||||||
|
// whitespace char after the last non-whitespace char isn't a newline.
|
||||||
|
// So replace that whitespace char (and everything after it) with a newline.
|
||||||
|
text.replace_range(last_whitespace_index.., "\n");
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
debug_assert!(last_whitespace_index == text.len());
|
||||||
|
debug_assert!(!text.ends_with(char::is_whitespace));
|
||||||
|
|
||||||
|
// This doesn't end in whitespace at all, so add a newline.
|
||||||
|
text.push('\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue