From 1b5bda2c2dee23fb55e88dbb7d8ff52cb5de7cb8 Mon Sep 17 00:00:00 2001 From: Erin van der Veen Date: Thu, 13 Jul 2023 13:36:04 +0200 Subject: [PATCH 1/2] Create append/prepend versions of scope captures --- README.md | 13 +- topiary/languages/nickel.scm | 40 ++-- topiary/languages/ocaml.scm | 52 ++--- topiary/languages/ocamllex.scm | 10 +- topiary/src/atom_collection.rs | 202 +++++++++--------- topiary/src/lib.rs | 24 ++- .../samples/expected/tree-sitter-query.scm | 48 ++--- .../tests/samples/input/tree-sitter-query.scm | 48 ++--- 8 files changed, 221 insertions(+), 216 deletions(-) diff --git a/README.md b/README.md index 5ebe8c74..01811200 100644 --- a/README.md +++ b/README.md @@ -833,18 +833,17 @@ top-level node `product_expression (0, 1) - (1, 1)` is multi-line. To solve this issue, we introduce user-defined scopes and softlines. -#### `@begin_scope` / `@end_scope` +#### `@prepend_begin_scope` / `@append_begin_scope` / `@prepend_end_scope` / `@append_end_scope` -`@begin_scope` and `@end_scope` tags are used to define custom scopes. -In conjunction with the `#scope_id!` predicate, they define scopes that -can span multiple CST nodes, or only part of one. For instance, this -scope matches anything between parenthesis in a +These tags are used to define custom scopes. In conjunction with the `#scope_id! +` predicate, they define scopes that can span multiple CST nodes, or only part +of one. For instance, this scope matches anything between parenthesis in a `parenthesized_expression`: ```scheme (parenthesized_expression - "(" @begin_scope - ")" @end_scope + "(" @append_begin_scope + ")" @prepend_end_scope (#scope_id! "tuple") ) ``` diff --git a/topiary/languages/nickel.scm b/topiary/languages/nickel.scm index 4b36d0a2..140514c4 100644 --- a/topiary/languages/nickel.scm +++ b/topiary/languages/nickel.scm @@ -122,8 +122,8 @@ [ (infix_expr) (annotated_infix_expr) - ] @begin_scope -) @end_scope + ] @prepend_begin_scope +) @append_end_scope (infix_expr (#scope_id! "infix_chain") @@ -169,9 +169,9 @@ (_ (#scope_id! "bound_rhs") - "=" @begin_scope + "=" @prepend_begin_scope . - (term) @end_scope + (term) @append_end_scope ) (_ @@ -237,9 +237,9 @@ (let_expr (#scope_id! "let_result") (let_in_block - "in" @begin_scope @prepend_spaced_softline + "in" @prepend_begin_scope @prepend_spaced_softline ) - (term) @end_scope + (term) @append_end_scope ) (let_expr @@ -253,9 +253,9 @@ ; coexist, so create a scope that covers them both. ( (#scope_id! "annotated_assignment") - (annot) @begin_scope + (annot) @prepend_begin_scope . - "=" @end_scope + "=" @append_end_scope ) ; Start an indentation block from the start of the annotations to the @@ -274,9 +274,9 @@ ; id | a -> a ( (#scope_id! "annotations") - (_) @begin_scope + (_) @prepend_begin_scope . - (annot) @end_scope + (annot) @append_end_scope ) ; Put each annotation -- and the equals sign, if it follows annotations @@ -303,8 +303,8 @@ ; This also defines an indentation block. (fun_expr (#scope_id! "function_definition") - "=>" @begin_scope @append_indent_start -) @append_indent_end @end_scope + "=>" @prepend_begin_scope @append_indent_start +) @append_indent_end @append_end_scope (fun_expr (#scope_id! "function_definition") @@ -319,8 +319,8 @@ ; like the operands to start on their own line, each indented. (infix_expr (#scope_id! "applicative_chain") - (applicative) @begin_scope -) @end_scope + (applicative) @prepend_begin_scope +) @append_end_scope ( (#scope_id! "applicative_chain") @@ -387,9 +387,9 @@ (_ (#scope_id! "container") . - "{" @append_spaced_softline @append_indent_start @begin_scope + "{" @append_spaced_softline @append_indent_start @prepend_begin_scope (_) - "}" @prepend_indent_end @prepend_spaced_softline @end_scope + "}" @prepend_indent_end @prepend_spaced_softline @append_end_scope . ) @@ -399,9 +399,9 @@ (_ (#scope_id! "container") . - "[" @append_empty_softline @append_indent_start @begin_scope + "[" @append_empty_softline @append_indent_start @prepend_begin_scope (_) - "]" @prepend_indent_end @prepend_empty_softline @end_scope + "]" @prepend_indent_end @prepend_empty_softline @append_end_scope . ) @@ -410,8 +410,8 @@ (_ (#scope_id! "container") . - "[|" @append_spaced_softline @append_indent_start @begin_scope - "|]" @prepend_indent_end @prepend_spaced_softline @end_scope + "[|" @append_spaced_softline @append_indent_start @prepend_begin_scope + "|]" @prepend_indent_end @prepend_spaced_softline @append_end_scope . ) diff --git a/topiary/languages/ocaml.scm b/topiary/languages/ocaml.scm index 3aa145bc..6a5f6548 100644 --- a/topiary/languages/ocaml.scm +++ b/topiary/languages/ocaml.scm @@ -754,11 +754,11 @@ ; in ; bar (let_binding - "=" @begin_scope + "=" @prepend_begin_scope . (fun_expression "->" @append_spaced_scoped_softline - ) @end_scope + ) @append_end_scope (#scope_id! "fun_definition") ) @@ -778,11 +778,11 @@ ; in ; bar (let_binding - "=" @begin_scope + "=" @prepend_begin_scope . (function_expression "function" @append_spaced_scoped_softline - ) @end_scope + ) @append_end_scope (#scope_id! "function_definition") ) ; The following is the general case, which should happen anywhere except in let bindings @@ -791,7 +791,7 @@ . (function_expression "function" @append_spaced_scoped_softline - ) @begin_scope @end_scope + ) @prepend_begin_scope @append_end_scope (#scope_id! "function_definition") ) (function_expression @@ -935,9 +935,9 @@ (field_declaration) (attribute) (comment) - ]? @end_scope + ]? @append_end_scope . - (field_declaration) @begin_scope + (field_declaration) @prepend_begin_scope ) (record_declaration (#scope_id! "field_declaration") @@ -945,7 +945,7 @@ (field_declaration) (attribute) (comment) - ] @end_scope + ] @append_end_scope . "}" ) @@ -977,9 +977,9 @@ (field_expression) (attribute) (comment) - ]? @end_scope + ]? @append_end_scope . - (field_expression) @begin_scope + (field_expression) @prepend_begin_scope ) (record_expression (#scope_id! "field_expression") @@ -987,7 +987,7 @@ (field_expression) (attribute) (comment) - ] @end_scope + ] @append_end_scope . "}" ) @@ -1151,7 +1151,7 @@ [ "=" "+=" - ] @begin_scope @append_spaced_scoped_softline + ] @prepend_begin_scope @append_spaced_scoped_softline . [ (constructed_type) @@ -1164,7 +1164,7 @@ (type_constructor_path) (type_variable) (variant_declaration) - ] @end_scope + ] @append_end_scope (#scope_id! "type_binding_before_constraint") ) @@ -1269,8 +1269,8 @@ ) (let_binding . - (_) @begin_scope - "=" @end_scope + (_) @prepend_begin_scope + "=" @append_end_scope (#scope_id! "let_binding_before_equal") ) (let_binding @@ -1299,8 +1299,8 @@ ) (fun_expression . - "fun" @begin_scope - "->" @end_scope + "fun" @prepend_begin_scope + "->" @append_end_scope (#scope_id! "fun_expr_before_arrow") ) (fun_expression @@ -1341,7 +1341,7 @@ ; We only want to define a scope around the outermost `product_expression`, ; which is the one that *isn't* followed by a comma. ( - (product_expression) @begin_scope @end_scope + (product_expression) @prepend_begin_scope @append_end_scope . ","? @do_nothing (#scope_id! "tuple") @@ -1375,7 +1375,7 @@ ( "->"? @do_nothing . - (function_type) @begin_scope @end_scope + (function_type) @prepend_begin_scope @append_end_scope (#scope_id! "function_type") ) (function_type @@ -1398,7 +1398,7 @@ (or_operator) ]? @do_nothing . - (infix_expression) @begin_scope @end_scope + (infix_expression) @prepend_begin_scope @append_end_scope (#scope_id! "infix_expression") ) (infix_expression @@ -1440,7 +1440,7 @@ ";" . "%"? @do_nothing - ) @begin_scope @end_scope + ) @prepend_begin_scope @append_end_scope (#scope_id! "sequence_expression") ) (sequence_expression @@ -1462,7 +1462,7 @@ ";" . "%" - ) @begin_scope @end_scope + ) @prepend_begin_scope @append_end_scope (#scope_id! "ppx_sequence_expression") ) (sequence_expression @@ -1519,17 +1519,17 @@ ; let foo = x ; end (module_binding - (module_name) @append_indent_start @begin_scope - "=" @prepend_empty_scoped_softline @prepend_indent_end @end_scope + (module_name) @append_indent_start @prepend_begin_scope + "=" @prepend_empty_scoped_softline @prepend_indent_end @append_end_scope (#scope_id! "module_binding_before_equal") ) ; if a module binding has no equal sign and isn't just a signature, everything enters the scope (module_binding (#scope_id! "module_binding_before_equal") - (module_name) @append_indent_start @begin_scope + (module_name) @append_indent_start @prepend_begin_scope "="? @do_nothing (signature)? @do_nothing -) @append_indent_end @end_scope +) @append_indent_end @append_end_scope (module_binding (module_name) @append_empty_scoped_softline (module_parameter) @prepend_spaced_scoped_softline diff --git a/topiary/languages/ocamllex.scm b/topiary/languages/ocamllex.scm index 39ede0e3..27cb7ab9 100644 --- a/topiary/languages/ocamllex.scm +++ b/topiary/languages/ocamllex.scm @@ -5,7 +5,7 @@ ( (#scope_id! "action") - (action) @begin_scope @end_scope + (action) @prepend_begin_scope @append_end_scope ) ; If the action spanned multiple lines, add newlines @@ -43,7 +43,7 @@ (_) @append_empty_scoped_softline . "]" @prepend_indent_end @prepend_antispace -) @begin_scope @end_scope +) @prepend_begin_scope @append_end_scope (aliased_regexp "as" @prepend_space @append_space @@ -53,11 +53,11 @@ (#scope_id! "parenthesized_regexp") "(" @append_empty_scoped_softline @append_indent_start ")" @prepend_empty_scoped_softline @prepend_indent_end -) @begin_scope @end_scope @prepend_spaced_softline @append_spaced_softline +) @prepend_begin_scope @append_end_scope @prepend_spaced_softline @append_spaced_softline ( (#scope_id! "regexp_alternative") - (regexp_alternative) @begin_scope @end_scope + (regexp_alternative) @prepend_begin_scope @append_end_scope ) (regexp_alternative @@ -81,7 +81,7 @@ (#scope_id! "lexer_entry") "=" @prepend_space @append_space ["parse" "shortest"] @append_spaced_scoped_softline @append_indent_start -) @begin_scope @end_scope +) @prepend_begin_scope @append_end_scope (lexer_entry (lexer_argument) @prepend_space @append_space diff --git a/topiary/src/atom_collection.rs b/topiary/src/atom_collection.rs index fcd48ab3..db96a26e 100644 --- a/topiary/src/atom_collection.rs +++ b/topiary/src/atom_collection.rs @@ -7,7 +7,7 @@ use std::{ use tree_sitter_facade::Node; -use crate::{Atom, FormatterError, FormatterResult, ScopeCondition}; +use crate::{Atom, FormatterError, FormatterResult, ScopeCondition, ScopeInformation}; /// A struct that holds sets of node IDs that have line breaks before or after them. /// @@ -56,12 +56,6 @@ pub struct AtomCollection { /// During initial Atom collection, any node that has a linebreak directly /// after it is added to this HashSet. line_break_after: HashSet, - /// The semantics of the types of scope_begin and scope_end is - /// HashMap)> - /// The line number is passed here because otherwise the information - /// is lost at post-processing time. - scope_begin: HashMap)>, - scope_end: HashMap)>, /// Used to generate unique IDs counter: usize, } @@ -82,8 +76,6 @@ impl AtomCollection { blank_lines_before: HashSet::new(), line_break_before: HashSet::new(), line_break_after: HashSet::new(), - scope_begin: HashMap::new(), - scope_end: HashMap::new(), counter: 0, } } @@ -112,8 +104,6 @@ impl AtomCollection { blank_lines_before: blank_line_nodes.before, line_break_before: line_break_nodes.before, line_break_after: line_break_nodes.after, - scope_begin: HashMap::new(), - scope_end: HashMap::new(), counter: 0, }; @@ -183,6 +173,21 @@ impl AtomCollection { }) }; + // For the {prepend/append}_scope_{begin/end} captures we need this information, + // instead of creating it for both branches, create them once here. + let scope_information_prepend = || -> FormatterResult { + Ok(ScopeInformation { + line_number: node.start_position().row(), + scope_id: requires_scope_id()?.to_owned(), + }) + }; + let scope_information_append = || -> FormatterResult { + Ok(ScopeInformation { + line_number: node.end_position().row(), + scope_id: requires_scope_id()?.to_owned(), + }) + }; + let mut is_multi_line = false; if let Some(parent) = node.parent() { let parent_id = parent.id(); @@ -269,8 +274,34 @@ impl AtomCollection { self.append(Atom::DeleteEnd, node, predicates); } // Scope manipulation - "begin_scope" => self.begin_scope_before(node, requires_scope_id()?), - "end_scope" => self.end_scope_after(node, requires_scope_id()?), + "prepend_begin_scope" => { + self.prepend( + Atom::ScopeBegin(scope_information_prepend()?), + node, + predicates, + ); + } + "append_begin_scope" => { + self.append( + Atom::ScopeBegin(scope_information_append()?), + node, + predicates, + ); + } + "prepend_end_scope" => { + self.prepend( + Atom::ScopeEnd(scope_information_prepend()?), + node, + predicates, + ); + } + "append_end_scope" => { + self.append( + Atom::ScopeEnd(scope_information_append()?), + node, + predicates, + ); + } // Scoped softlines "append_empty_scoped_softline" => { let id = self.next_id(); @@ -502,50 +533,6 @@ impl AtomCollection { self.append.entry(target_node.id()).or_default().push(atom); } - /// Begins a scope with the given `scope_id` before the first leaf node of the given `Node`'s subtree. - /// - /// # Arguments - /// - /// * `node` - A reference to a `Node` object that represents a subtree in the syntax tree. - /// * `scope_id` - A reference to a string that identifies the scope to begin. - fn begin_scope_before(&mut self, node: &Node, scope_id: &str) { - let target_node = self.first_leaf(node); - - log::debug!("Begin scope {scope_id:?} before node {:?}", target_node,); - - self.scope_begin - .entry(target_node.id()) - .and_modify(|(_, scope_ids)| scope_ids.push(String::from(scope_id))) - .or_insert_with(|| { - ( - target_node.start_position().row(), - vec![String::from(scope_id)], - ) - }); - } - - /// Ends a scope with the given `scope_id` after the last leaf node of the given `Node`'s subtree. - /// - /// # Arguments - /// - /// * `node` - A reference to a `Node` object that represents a subtree in the syntax tree. - /// * `scope_id` - A reference to a string that identifies the scope to end. - fn end_scope_after(&mut self, node: &Node, scope_id: &str) { - let target_node = self.last_leaf(node); - - log::debug!("End scope {scope_id:?} after node {:?}", target_node,); - - self.scope_end - .entry(target_node.id()) - .and_modify(|(_, scope_ids)| scope_ids.push(String::from(scope_id))) - .or_insert_with(|| { - ( - target_node.end_position().row(), - vec![String::from(scope_id)], - ) - }); - } - /// Expands a softline atom to a hardline, space or empty atom depending on /// if we are in a multiline context or not. /// @@ -625,56 +612,53 @@ impl AtomCollection { let mut force_apply_modifications = false; for atom in &self.atoms { - if let Atom::Leaf { id, .. } = atom { - // Begin a new scope - if let Some((line_start, scope_ids)) = self.scope_begin.get(id) { - for scope_id in scope_ids { - opened_scopes - .entry(scope_id) - .or_insert_with(Vec::new) - .push((*line_start, Vec::new())); - } - } - // End a scope, and register the ScopedSoftline transformations - // in `modifications` - if let Some((line_end, scope_ids)) = self.scope_end.get(id) { - for scope_id in scope_ids { - if let Some((line_start, atoms)) = - opened_scopes.get_mut(scope_id).and_then(Vec::pop) + if let Atom::ScopeBegin(ScopeInformation { + line_number: line_start, + scope_id, + }) = atom + { + opened_scopes + .entry(scope_id) + .or_insert_with(Vec::new) + .push((*line_start, Vec::new())); + } else if let Atom::ScopeEnd(ScopeInformation { + line_number: line_end, + scope_id, + }) = atom + { + if let Some((line_start, atoms)) = + opened_scopes.get_mut(scope_id).and_then(Vec::pop) + { + let multiline = line_start != *line_end; + for atom in atoms { + if let Atom::ScopedSoftline { id, spaced, .. } = atom { + let new_atom = if multiline { + Atom::Hardline + } else if *spaced { + Atom::Space + } else { + Atom::Empty + }; + modifications.insert(*id, new_atom); + } else if let Atom::ScopedConditional { + id, + atom, + condition, + .. + } = atom { - let multiline = line_start != *line_end; - for atom in atoms { - if let Atom::ScopedSoftline { id, spaced, .. } = atom { - let new_atom = if multiline { - Atom::Hardline - } else if *spaced { - Atom::Space - } else { - Atom::Empty - }; - modifications.insert(*id, new_atom); - } else if let Atom::ScopedConditional { - id, - atom, - condition, - .. - } = atom - { - let multiline_only = - *condition == ScopeCondition::MultiLineOnly; - let new_atom = if multiline == multiline_only { - atom.deref().clone() - } else { - Atom::Empty - }; - modifications.insert(*id, new_atom); - } - } - } else { - log::warn!("Closing unopened scope {scope_id:?}"); - force_apply_modifications = true; + let multiline_only = *condition == ScopeCondition::MultiLineOnly; + let new_atom = if multiline == multiline_only { + atom.deref().clone() + } else { + Atom::Empty + }; + modifications.insert(*id, new_atom); } } + } else { + log::warn!("Closing unopened scope {scope_id:?}"); + force_apply_modifications = true; } // Register the ScopedSoftline in the correct scope } else if let Atom::ScopedSoftline { scope_id, .. } = atom { @@ -705,6 +689,16 @@ impl AtomCollection { force_apply_modifications = true; } + // Remove scopes from the atom list + for atom in &mut self.atoms { + match atom { + Atom::ScopeBegin(_) | Atom::ScopeEnd(_) => { + *atom = Atom::Empty; + } + _ => {} + } + } + // Apply modifications. // For performance reasons, skip this step if there are no modifications to make if !modifications.is_empty() || force_apply_modifications { diff --git a/topiary/src/lib.rs b/topiary/src/lib.rs index c651c9ef..815c8226 100644 --- a/topiary/src/lib.rs +++ b/topiary/src/lib.rs @@ -34,6 +34,12 @@ mod tree_sitter; #[doc(hidden)] pub mod test_utils; +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ScopeInformation { + line_number: u32, + scope_id: String, +} + /// An atom represents a small piece of the output. We turn Tree-sitter nodes /// into atoms, and we add white-space atoms where appropriate. The final list /// of atoms is rendered to the output. @@ -82,13 +88,19 @@ pub enum Atom { // it might happen that it contains several leaves. DeleteBegin, DeleteEnd, + /// Indicates the beginning of a scope, use in combination with the + /// ScopedSoftlines and ScopedConditionals below. + ScopeBegin(ScopeInformation), + /// Indicates the end of a scope, use in combination with the + /// ScopedSoftlines and ScopedConditionals below. + ScopeEnd(ScopeInformation), /// Scoped commands - // ScopedSoftline works together with the @begin_scope and @end_scope query tags. - // To decide if a scoped softline must be expanded into a hardline, we look at - // the innermost scope having the corresponding `scope_id`, that encompasses it. - // We expand the softline if that scope is multi-line. - // The `id` value is here for technical reasons, it allows tracking of the atom - // during post-processing. + // ScopedSoftline works together with the @{prepend,append}_begin_scope and + // @{prepend,append}_end_scope query tags. To decide if a scoped softline + // must be expanded into a hardline, we look at the innermost scope having + // the corresponding `scope_id`, that encompasses it. We expand the softline + // if that scope is multi-line. The `id` value is here for technical + // reasons, it allows tracking of the atom during post-processing. ScopedSoftline { id: usize, scope_id: String, diff --git a/topiary/tests/samples/expected/tree-sitter-query.scm b/topiary/tests/samples/expected/tree-sitter-query.scm index 5c90b71b..e31588ab 100644 --- a/topiary/tests/samples/expected/tree-sitter-query.scm +++ b/topiary/tests/samples/expected/tree-sitter-query.scm @@ -741,11 +741,11 @@ ; in ; bar (let_binding - "=" @begin_scope + "=" @prepend_begin_scope . (fun_expression "->" @append_spaced_scoped_softline - ) @end_scope + ) @append_end_scope (#scope_id! "fun_definition") ) @@ -765,15 +765,15 @@ ; in ; bar (let_binding - "=" @begin_scope + "=" @prepend_begin_scope . (function_expression "function" @append_spaced_scoped_softline - ) @end_scope + ) @append_end_scope (#scope_id! "function_definition") ) (parenthesized_expression - (function_expression) @begin_scope @end_scope + (function_expression) @prepend_begin_scope @append_end_scope (#scope_id! "function_definition") ) (function_expression @@ -908,9 +908,9 @@ (field_declaration) (attribute) (comment) - ]? @end_scope + ]? @append_end_scope . - (field_declaration) @begin_scope + (field_declaration) @prepend_begin_scope ) (record_declaration (#scope_id! "field_declaration") @@ -918,7 +918,7 @@ (field_declaration) (attribute) (comment) - ] @end_scope + ] @append_end_scope . "}" ) @@ -950,9 +950,9 @@ (field_expression) (attribute) (comment) - ]? @end_scope + ]? @append_end_scope . - (field_expression) @begin_scope + (field_expression) @prepend_begin_scope ) (record_expression (#scope_id! "field_expression") @@ -960,7 +960,7 @@ (field_expression) (attribute) (comment) - ] @end_scope + ] @append_end_scope . "}" ) @@ -1215,8 +1215,8 @@ ) (let_binding . - (_) @begin_scope - "=" @end_scope + (_) @prepend_begin_scope + "=" @append_end_scope (#scope_id! "let_binding_before_equal") ) (let_binding @@ -1245,8 +1245,8 @@ ) (fun_expression . - "fun" @begin_scope - "->" @end_scope + "fun" @prepend_begin_scope + "->" @append_end_scope (#scope_id! "fun_expr_before_arrow") ) (fun_expression @@ -1287,7 +1287,7 @@ ; We only want to define a scope around the outermost `product_expression`, ; which is the one that *isn't* followed by a comma. ( - (product_expression) @begin_scope @end_scope + (product_expression) @prepend_begin_scope @append_end_scope . ","? @do_nothing (#scope_id! "tuple") @@ -1321,7 +1321,7 @@ ( "->"? @do_nothing . - (function_type) @begin_scope @end_scope + (function_type) @prepend_begin_scope @append_end_scope (#scope_id! "function_type") ) (function_type @@ -1346,7 +1346,7 @@ ] )? @do_nothing . - (infix_expression) @begin_scope @end_scope + (infix_expression) @prepend_begin_scope @append_end_scope (#scope_id! "infix_expression") ) (infix_expression @@ -1376,7 +1376,7 @@ ";" . "%"? @do_nothing - ) @begin_scope @end_scope + ) @prepend_begin_scope @append_end_scope (#scope_id! "sequence_expression") ) (sequence_expression @@ -1398,7 +1398,7 @@ ";" . "%" - ) @begin_scope @end_scope + ) @prepend_begin_scope @append_end_scope (#scope_id! "ppx_sequence_expression") ) (sequence_expression @@ -1455,17 +1455,17 @@ ; let foo = x ; end (module_binding - (module_name) @append_indent_start @begin_scope - "=" @prepend_empty_scoped_softline @prepend_indent_end @end_scope + (module_name) @append_indent_start @prepend_begin_scope + "=" @prepend_empty_scoped_softline @prepend_indent_end @append_end_scope (#scope_id! "module_binding_before_equal") ) ; if a module binding has no equal sign and isn't just a signature, everything enters the scope (module_binding (#scope_id! "module_binding_before_equal") - (module_name) @append_indent_start @begin_scope + (module_name) @append_indent_start @prepend_begin_scope "="? @do_nothing (signature)? @do_nothing -) @append_indent_end @end_scope +) @append_indent_end @append_end_scope (module_binding (module_name) @append_empty_scoped_softline (module_parameter) @prepend_spaced_scoped_softline diff --git a/topiary/tests/samples/input/tree-sitter-query.scm b/topiary/tests/samples/input/tree-sitter-query.scm index bff4627d..53da9663 100644 --- a/topiary/tests/samples/input/tree-sitter-query.scm +++ b/topiary/tests/samples/input/tree-sitter-query.scm @@ -742,11 +742,11 @@ ; in ; bar (let_binding - "=" @begin_scope + "=" @prepend_begin_scope . (fun_expression "->" @append_spaced_scoped_softline - ) @end_scope + ) @append_end_scope (#scope_id! "fun_definition") ) @@ -766,15 +766,15 @@ ; in ; bar (let_binding - "=" @begin_scope + "=" @prepend_begin_scope . (function_expression "function" @append_spaced_scoped_softline - ) @end_scope + ) @append_end_scope (#scope_id! "function_definition") ) (parenthesized_expression - (function_expression) @begin_scope @end_scope + (function_expression) @prepend_begin_scope @append_end_scope (#scope_id! "function_definition") ) (function_expression @@ -909,9 +909,9 @@ (field_declaration) (attribute) (comment) - ]? @end_scope + ]? @append_end_scope . - (field_declaration) @begin_scope + (field_declaration) @prepend_begin_scope ) (record_declaration (#scope_id! "field_declaration") @@ -919,7 +919,7 @@ (field_declaration) (attribute) (comment) - ] @end_scope + ] @append_end_scope . "}" ) @@ -951,9 +951,9 @@ (field_expression) (attribute) (comment) - ]? @end_scope + ]? @append_end_scope . - (field_expression) @begin_scope + (field_expression) @prepend_begin_scope ) (record_expression (#scope_id! "field_expression") @@ -961,7 +961,7 @@ (field_expression) (attribute) (comment) - ] @end_scope + ] @append_end_scope . "}" ) @@ -1216,8 +1216,8 @@ ) (let_binding . - (_) @begin_scope - "=" @end_scope + (_) @prepend_begin_scope + "=" @append_end_scope (#scope_id! "let_binding_before_equal") ) (let_binding @@ -1246,8 +1246,8 @@ ) (fun_expression . - "fun" @begin_scope - "->" @end_scope + "fun" @prepend_begin_scope + "->" @append_end_scope (#scope_id! "fun_expr_before_arrow") ) (fun_expression @@ -1288,7 +1288,7 @@ ; We only want to define a scope around the outermost `product_expression`, ; which is the one that *isn't* followed by a comma. ( - (product_expression) @begin_scope @end_scope + (product_expression) @prepend_begin_scope @append_end_scope . ","? @do_nothing (#scope_id! "tuple") @@ -1322,7 +1322,7 @@ ( "->"? @do_nothing . - (function_type) @begin_scope @end_scope + (function_type) @prepend_begin_scope @append_end_scope (#scope_id! "function_type") ) (function_type @@ -1347,7 +1347,7 @@ ] )? @do_nothing . - (infix_expression) @begin_scope @end_scope + (infix_expression) @prepend_begin_scope @append_end_scope (#scope_id! "infix_expression") ) (infix_expression @@ -1377,7 +1377,7 @@ ";" . "%"? @do_nothing - ) @begin_scope @end_scope + ) @prepend_begin_scope @append_end_scope (#scope_id! "sequence_expression") ) (sequence_expression @@ -1399,7 +1399,7 @@ ";" . "%" - ) @begin_scope @end_scope + ) @prepend_begin_scope @append_end_scope (#scope_id! "ppx_sequence_expression") ) (sequence_expression @@ -1456,17 +1456,17 @@ ; let foo = x ; end (module_binding - (module_name) @append_indent_start @begin_scope - "=" @prepend_empty_scoped_softline @prepend_indent_end @end_scope + (module_name) @append_indent_start @prepend_begin_scope + "=" @prepend_empty_scoped_softline @prepend_indent_end @append_end_scope (#scope_id! "module_binding_before_equal") ) ; if a module binding has no equal sign and isn't just a signature, everything enters the scope (module_binding (#scope_id! "module_binding_before_equal") - (module_name) @append_indent_start @begin_scope + (module_name) @append_indent_start @prepend_begin_scope "="? @do_nothing (signature)? @do_nothing -) @append_indent_end @end_scope +) @append_indent_end @append_end_scope (module_binding (module_name) @append_empty_scoped_softline (module_parameter) @prepend_spaced_scoped_softline From f63b6fbc6791884316d55f19cf124417c12b2b90 Mon Sep 17 00:00:00 2001 From: Erin van der Veen Date: Thu, 13 Jul 2023 13:55:51 +0200 Subject: [PATCH 2/2] Update changelog with #576 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52d58df5..9a78f14c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,7 @@ This name should be decided amongst the team before the release. ### Changed * [#535](https://github.com/tweag/topiary/pull/535) Improved error message when idempotency fails due to invalid output in the first pass. * [#533](https://github.com/tweag/topiary/pull/533) Update tree-sitter-ocaml to 0.20.3 +* [#576](https://github.com/tweag/topiary/pull/576) Allows prepending/appending `@begin_scope` and `@end_scope` ## v0.2.3 - Cyclic Cypress - 2023-06-20