@@ -1260,7 +1260,7 @@ use std::sync::atomic::{AtomicUsize, Ordering};
12601260use std:: { iter, mem, ops, str, usize} ;
12611261use tree_sitter:: {
12621262 Language as Grammar , Node , Parser , Point , Query , QueryCaptures , QueryCursor , QueryError ,
1263- QueryMatch , Range , TextProvider , Tree ,
1263+ QueryMatch , Range , TextProvider , Tree , TreeCursor ,
12641264} ;
12651265
12661266const CANCELLATION_CHECK_INTERVAL : usize = 100 ;
@@ -2130,57 +2130,68 @@ impl<I: Iterator<Item = HighlightEvent>> Iterator for Merge<I> {
21302130 }
21312131}
21322132
2133+ fn node_is_visible ( node : & Node ) -> bool {
2134+ node. is_missing ( ) || ( node. is_named ( ) && node. language ( ) . node_kind_is_visible ( node. kind_id ( ) ) )
2135+ }
2136+
21332137pub fn pretty_print_tree < W : fmt:: Write > ( fmt : & mut W , node : Node ) -> fmt:: Result {
2134- pretty_print_tree_impl ( fmt, node, true , None , 0 )
2138+ if node. child_count ( ) == 0 {
2139+ if node_is_visible ( & node) {
2140+ write ! ( fmt, "({})" , node. kind( ) )
2141+ } else {
2142+ write ! ( fmt, "\" {}\" " , node. kind( ) )
2143+ }
2144+ } else {
2145+ pretty_print_tree_impl ( fmt, & mut node. walk ( ) , 0 )
2146+ }
21352147}
21362148
21372149fn pretty_print_tree_impl < W : fmt:: Write > (
21382150 fmt : & mut W ,
2139- node : Node ,
2140- is_root : bool ,
2141- field_name : Option < & str > ,
2151+ cursor : & mut TreeCursor ,
21422152 depth : usize ,
21432153) -> fmt:: Result {
2144- fn is_visible ( node : Node ) -> bool {
2145- node. is_missing ( )
2146- || ( node. is_named ( ) && node. language ( ) . node_kind_is_visible ( node. kind_id ( ) ) )
2147- }
2154+ let node = cursor. node ( ) ;
2155+ let visible = node_is_visible ( & node) ;
21482156
2149- if is_visible ( node ) {
2157+ if visible {
21502158 let indentation_columns = depth * 2 ;
21512159 write ! ( fmt, "{:indentation_columns$}" , "" ) ?;
21522160
2153- if let Some ( field_name) = field_name {
2161+ if let Some ( field_name) = cursor . field_name ( ) {
21542162 write ! ( fmt, "{}: " , field_name) ?;
21552163 }
21562164
21572165 write ! ( fmt, "({}" , node. kind( ) ) ?;
2158- } else if is_root {
2159- write ! ( fmt, "(\" {}\" )" , node. kind( ) ) ?;
21602166 }
21612167
2162- for child_idx in 0 ..node. child_count ( ) {
2163- if let Some ( child) = node. child ( child_idx) {
2164- if is_visible ( child) {
2168+ // Handle children.
2169+ if cursor. goto_first_child ( ) {
2170+ loop {
2171+ if node_is_visible ( & cursor. node ( ) ) {
21652172 fmt. write_char ( '\n' ) ?;
21662173 }
21672174
2168- pretty_print_tree_impl (
2169- fmt,
2170- child,
2171- false ,
2172- node. field_name_for_child ( child_idx as u32 ) ,
2173- depth + 1 ,
2174- ) ?;
2175+ pretty_print_tree_impl ( fmt, cursor, depth + 1 ) ?;
2176+
2177+ if !cursor. goto_next_sibling ( ) {
2178+ break ;
2179+ }
21752180 }
2181+
2182+ let moved = cursor. goto_parent ( ) ;
2183+ // The parent of the first child must exist, and must be `node`.
2184+ debug_assert ! ( moved) ;
2185+ debug_assert ! ( cursor. node( ) == node) ;
21762186 }
21772187
2178- if is_visible ( node ) {
2179- write ! ( fmt, ")" ) ?;
2188+ if visible {
2189+ fmt. write_char ( ')' ) ?;
21802190 }
21812191
21822192 Ok ( ( ) )
21832193}
2194+
21842195#[ cfg( test) ]
21852196mod test {
21862197 use super :: * ;
@@ -2353,11 +2364,17 @@ mod test {
23532364 }
23542365
23552366 #[ track_caller]
2356- fn assert_pretty_print ( source : & str , expected : & str , start : usize , end : usize ) {
2367+ fn assert_pretty_print (
2368+ language_name : & str ,
2369+ source : & str ,
2370+ expected : & str ,
2371+ start : usize ,
2372+ end : usize ,
2373+ ) {
23572374 let source = Rope :: from_str ( source) ;
23582375
23592376 let loader = Loader :: new ( Configuration { language : vec ! [ ] } ) ;
2360- let language = get_language ( "rust" ) . unwrap ( ) ;
2377+ let language = get_language ( language_name ) . unwrap ( ) ;
23612378
23622379 let config = HighlightConfiguration :: new ( language, "" , "" , "" ) . unwrap ( ) ;
23632380 let syntax = Syntax :: new ( & source, Arc :: new ( config) , Arc :: new ( loader) ) ;
@@ -2377,13 +2394,14 @@ mod test {
23772394 #[ test]
23782395 fn test_pretty_print ( ) {
23792396 let source = r#"/// Hello"# ;
2380- assert_pretty_print ( source, "(line_comment)" , 0 , source. len ( ) ) ;
2397+ assert_pretty_print ( "rust" , source, "(line_comment)" , 0 , source. len ( ) ) ;
23812398
23822399 // A large tree should be indented with fields:
23832400 let source = r#"fn main() {
23842401 println!("Hello, World!");
23852402 }"# ;
23862403 assert_pretty_print (
2404+ "rust" ,
23872405 source,
23882406 concat ! (
23892407 "(function_item\n " ,
@@ -2402,11 +2420,34 @@ mod test {
24022420
24032421 // Selecting a token should print just that token:
24042422 let source = r#"fn main() {}"# ;
2405- assert_pretty_print ( source, r#"( "fn") "# , 0 , 1 ) ;
2423+ assert_pretty_print ( "rust" , source, r#""fn""# , 0 , 1 ) ;
24062424
24072425 // Error nodes are printed as errors:
24082426 let source = r#"}{"# ;
2409- assert_pretty_print ( source, "(ERROR)" , 0 , source. len ( ) ) ;
2427+ assert_pretty_print ( "rust" , source, "(ERROR)" , 0 , source. len ( ) ) ;
2428+
2429+ // Fields broken under unnamed nodes are determined correctly.
2430+ // In the following source, `object` belongs to the `singleton_method`
2431+ // rule but `name` and `body` belong to an unnamed helper `_method_rest`.
2432+ // This can cause a bug with a pretty-printing implementation that
2433+ // uses `Node::field_name_for_child` to determine field names but is
2434+ // fixed when using `TreeCursor::field_name`.
2435+ let source = "def self.method_name
2436+ true
2437+ end" ;
2438+ assert_pretty_print (
2439+ "ruby" ,
2440+ source,
2441+ concat ! (
2442+ "(singleton_method\n " ,
2443+ " object: (self)\n " ,
2444+ " name: (identifier)\n " ,
2445+ " body: (body_statement\n " ,
2446+ " (true)))"
2447+ ) ,
2448+ 0 ,
2449+ source. len ( ) ,
2450+ ) ;
24102451 }
24112452
24122453 #[ test]
0 commit comments