diff --git a/src/format.rs b/src/format.rs index e344d469e..e5ae1d662 100644 --- a/src/format.rs +++ b/src/format.rs @@ -487,7 +487,7 @@ type GlyphMap = Vec<(CodeSpan, (Loc, Loc))>; impl<'a> Formatter<'a> { fn format_top_items(mut self, items: &[Item]) -> (String, GlyphMap) { - self.format_items(items); + self.format_items(items, 0); let mut output = self.output; while output.ends_with('\n') { output.pop(); @@ -497,10 +497,12 @@ impl<'a> Formatter<'a> { } (output, self.glyph_map) } - fn format_items(&mut self, items: &[Item]) { - for item in items { - self.format_item(item); - self.output.push('\n'); + fn format_items(&mut self, items: &[Item], depth: usize) { + for (i, item) in items.iter().enumerate() { + if i > 0 || depth > 0 { + self.newline(depth); + } + self.format_item(item, depth); } // Align end-of-line comments if self.config.align_comments && !self.end_of_line_comments.is_empty() { @@ -573,7 +575,16 @@ impl<'a> Formatter<'a> { self.output = new_output; } } - fn format_item(&mut self, item: &Item) { + fn newline(&mut self, depth: usize) { + self.output.push('\n'); + self.indent(depth); + } + fn indent(&mut self, depth: usize) { + for _ in 0..self.config.multiline_indent * depth { + self.output.push(' '); + } + } + fn format_item(&mut self, item: &Item, depth: usize) { match item { Item::Module(m) => { self.prev_import_function = None; @@ -581,14 +592,17 @@ impl<'a> Formatter<'a> { if let Some(name) = &m.value.name { self.push(&name.span, &name.value); } - self.output.push('\n'); - self.format_items(&m.value.items); + self.format_items(&m.value.items, depth + 1); + if self.output.ends_with('\n') { + self.output.pop(); + } + self.newline(depth); self.output.push_str("---"); } Item::Words(lines) => { self.prev_import_function = None; let lines = unsplit_words(lines.iter().cloned().flat_map(split_words).collect()); - self.format_multiline_words(&lines, false, false, 0); + self.format_multiline_words(&lines, false, false, false, depth); } Item::Binding(binding) => { match binding.words.first().map(|w| &w.value) { @@ -627,7 +641,7 @@ impl<'a> Formatter<'a> { .unwrap_or_else(|| binding.arrow_span.clone()); let mut lines = unsplit_words(split_words(binding.words.clone())); if lines.len() == 1 { - self.format_words(&lines[0], true, 0); + self.format_words(&lines[0], true, depth); } else { lines.push(Vec::new()); self.format_words( @@ -638,7 +652,7 @@ impl<'a> Formatter<'a> { closed: true, }))], true, - 0, + depth, ); } } @@ -876,7 +890,13 @@ impl<'a> Formatter<'a> { self.output.pop(); } } - self.format_multiline_words(&arr.lines, arr.signature.is_none(), true, depth + 1); + self.format_multiline_words( + &arr.lines, + arr.signature.is_none(), + true, + true, + depth + 1, + ); if arr.boxes { self.output.push('}'); } else { @@ -918,7 +938,7 @@ impl<'a> Formatter<'a> { self.output.pop(); } } - self.format_multiline_words(&func.lines, false, true, depth + 1); + self.format_multiline_words(&func.lines, false, true, true, depth + 1); self.output.push(')'); } Word::Pack(pack) => { @@ -957,7 +977,7 @@ impl<'a> Formatter<'a> { self.output.pop(); } } - self.format_multiline_words(&br.value.lines, false, false, depth + 1); + self.format_multiline_words(&br.value.lines, false, false, true, depth + 1); if any_multiline && br.value.lines.last().is_some_and(|line| !line.is_empty()) && !self.output.trim_end_matches(' ').ends_with('\n') @@ -1118,6 +1138,7 @@ impl<'a> Formatter<'a> { lines: &[Vec>], allow_compact: bool, allow_leading_space: bool, + allow_trailing_newline: bool, depth: usize, ) { if lines.is_empty() { @@ -1177,7 +1198,7 @@ impl<'a> Formatter<'a> { self.format_words(line, true, depth); } - if !compact { + if allow_trailing_newline && !compact { if depth > 0 && !lines.iter().last().is_some_and(|line| line.is_empty()) { self.output.push('\n'); } diff --git a/src/lex.rs b/src/lex.rs index db865bec4..28f06f421 100644 --- a/src/lex.rs +++ b/src/lex.rs @@ -775,11 +775,6 @@ impl<'a> Lexer<'a> { } fn run(mut self) -> (Vec>, Vec>) { use {self::AsciiToken::*, Token::*}; - // Initial scope delimiters - let start = self.loc; - if self.next_chars_exact(["-", "-", "-"]) { - self.end(TripleMinus, start); - } // Main loop 'main: loop { let start = self.loc; @@ -801,6 +796,7 @@ impl<'a> Lexer<'a> { "_" => self.end(Underscore, start), "|" => self.end(Bar, start), ";" => self.end(Semicolon, start), + "-" if self.next_chars_exact(["-", "-"]) => self.end(TripleMinus, start), "'" if self.next_char_exact("'") => { if let Some(swiz) = self.array_swizzle() { self.end(ArraySwizzle(swiz), start) @@ -1070,14 +1066,7 @@ impl<'a> Lexer<'a> { self.end(Number, start) } // Newlines - "\n" | "\r\n" => { - self.end(Newline, start); - // Scope delimiters - let start = self.loc; - if self.next_chars_exact(["-", "-", "-"]) { - self.end(TripleMinus, start); - } - } + "\n" | "\r\n" => self.end(Newline, start), " " | "\t" => { while self.next_char_exact(" ") || self.next_char_exact("\t") {} self.end(Spaces, start) diff --git a/src/parse.rs b/src/parse.rs index 413e3f1d5..a0fc81ebf 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -201,7 +201,7 @@ pub fn parse( next_output_comment: 0, depth: 0, }; - let items = parser.items(true); + let items = parser.items(false); if parser.errors.is_empty() && parser.index < parser.tokens.len() { parser.errors.push( parser @@ -282,13 +282,13 @@ impl<'i> Parser<'i> { )); self.errors.push(err); } - fn items(&mut self, parse_scopes: bool) -> Vec { + fn items(&mut self, in_scope: bool) -> Vec { let mut items = Vec::new(); while self.try_exact(Newline).is_some() { self.try_spaces(); } loop { - match self.try_item(parse_scopes) { + match self.try_item(in_scope) { Some(item) => items.push(item), None => { if self.try_exact(Newline).is_none() { @@ -308,7 +308,7 @@ impl<'i> Parser<'i> { } items } - fn try_item(&mut self, parse_scopes: bool) -> Option { + fn try_item(&mut self, in_scope: bool) -> Option { self.try_spaces(); Some(if let Some(binding) = self.try_binding() { Item::Binding(binding) @@ -319,11 +319,16 @@ impl<'i> Parser<'i> { // Convert multiline words into multiple items if !lines.is_empty() { Item::Words(lines) - } else if parse_scopes { + } else { + let backup = self.index; let start = self.try_exact(TripleMinus.into())?; self.try_spaces(); let name = self.try_ident(); - let items = self.items(false); + if in_scope && name.is_none() { + self.index = backup; + return None; + } + let items = self.items(true); let span = if let Some(end) = self.try_exact(TripleMinus.into()) { start.merge(end) } else { @@ -332,8 +337,6 @@ impl<'i> Parser<'i> { }; let module = ScopedModule { name, items }; Item::Module(span.sp(module)) - } else { - return None; } }) }