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);
|
||||
}
|
||||
|
||||
buf.trim_end();
|
||||
buf.newline();
|
||||
buf.fmt_end_of_file();
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
while self.text.ends_with(char::is_whitespace) {
|
||||
self.text.truncate(self.text.len() - 1);
|
||||
/// Ensures the text ends in a newline with no whitespace preceding it.
|
||||
pub fn fmt_end_of_file(&mut self) {
|
||||
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