@@ -59,7 +59,10 @@ impl<'a> Writer<'a> {
5959 if let Some ( span) = body. span {
6060 self . out . indent_level += 1 ;
6161 let comments = self . accumulate_full_line_comments ( span. span ( ) . end ( ) ) ;
62- if !comments. is_empty ( ) {
62+ let has_real_comment = comments
63+ . iter ( )
64+ . any ( |& id| self . src . get ( id) . is_some_and ( |l| l. trim ( ) . starts_with ( "//" ) ) ) ;
65+ if has_real_comment {
6366 self . out . new_line ( ) ?;
6467 self . apply_line_comments ( comments) ?;
6568 self . out . buf . pop ( ) ; // remove the trailing newline, forcing us to end at the end of the comment
@@ -252,11 +255,19 @@ impl<'a> Writer<'a> {
252255
253256 pub fn write_body_nodes ( & mut self , children : & [ BodyNode ] ) -> Result {
254257 let mut iter = children. iter ( ) . peekable ( ) ;
258+ let mut is_first = true ;
255259
256260 while let Some ( child) = iter. next ( ) {
257261 if self . current_span_is_primary ( child. span ( ) . start ( ) ) {
258- self . write_comments ( child. span ( ) . start ( ) ) ?;
262+ let comments = self . accumulate_full_line_comments ( child. span ( ) . start ( ) ) ;
263+ let has_real_comment = comments
264+ . iter ( )
265+ . any ( |& id| self . src . get ( id) . is_some_and ( |l| l. trim ( ) . starts_with ( "//" ) ) ) ;
266+ if has_real_comment || !is_first {
267+ self . apply_line_comments ( comments) ?;
268+ }
259269 } ;
270+ is_first = false ;
260271 self . out . tab ( ) ?;
261272 self . write_ident ( child) ?;
262273 if iter. peek ( ) . is_some ( ) {
@@ -360,8 +371,10 @@ impl<'a> Writer<'a> {
360371 self . write_todo_body ( brace) ?;
361372 }
362373
363- // multiline handlers bump everything down
364- if attr_len > 1000 || self . out . indent . split_line_attributes ( ) {
374+ // multiline handlers bump everything down, but not empty blocks
375+ if !matches ! ( opt_level, ShortOptimization :: Empty )
376+ && ( attr_len > 1000 || self . out . indent . split_line_attributes ( ) )
377+ {
365378 opt_level = ShortOptimization :: NoOpt ;
366379 }
367380
@@ -410,7 +423,9 @@ impl<'a> Writer<'a> {
410423 self . write_attributes ( attributes, spreads, false , brace, has_children) ?;
411424
412425 if !children. is_empty ( ) {
413- self . out . new_line ( ) ?;
426+ if !attributes. is_empty ( ) || !spreads. is_empty ( ) {
427+ self . out . new_line ( ) ?;
428+ }
414429 self . write_body_indented ( children) ?;
415430 }
416431
@@ -425,7 +440,10 @@ impl<'a> Writer<'a> {
425440 ) && self . leading_row_is_empty ( brace. span . span ( ) . end ( ) )
426441 {
427442 let comments = self . accumulate_full_line_comments ( brace. span . span ( ) . end ( ) ) ;
428- if !comments. is_empty ( ) {
443+ let has_real_comment = comments
444+ . iter ( )
445+ . any ( |& id| self . src . get ( id) . is_some_and ( |l| l. trim ( ) . starts_with ( "//" ) ) ) ;
446+ if has_real_comment {
429447 // Undo the tab from tabbed_line(). It positioned for the closing
430448 // brace, but trailing comments need child-level indentation
431449 let tab_width = self . out . indent . indent_str ( ) . len ( ) * self . out . indent_level ;
@@ -526,8 +544,20 @@ impl<'a> Writer<'a> {
526544 fn write_attribute ( & mut self , attr : & Attribute ) -> Result {
527545 self . write_attribute_name ( & attr. name ) ?;
528546
529- // if the attribute is a shorthand, we don't need to write the colon, just the name
530547 if !attr. can_be_shorthand ( ) {
548+ if let AttributeValue :: IfExpr ( if_chain) = & attr. value {
549+ let inline_len = self . attr_value_len ( & attr. value ) ;
550+ let line_budget = 80usize . saturating_sub ( self . out . indent_level * 4 ) ;
551+ if inline_len > line_budget {
552+ write ! ( self . out, ":" ) ?;
553+ self . out . indent_level += 1 ;
554+ self . out . new_line ( ) ?;
555+ self . out . tab ( ) ?;
556+ self . write_attribute_if_chain_multiline ( if_chain) ?;
557+ self . out . indent_level -= 1 ;
558+ return Ok ( ( ) ) ;
559+ }
560+ }
531561 write ! ( self . out, ": " ) ?;
532562 self . write_attribute_value ( & attr. value ) ?;
533563 }
@@ -570,14 +600,25 @@ impl<'a> Writer<'a> {
570600 }
571601
572602 fn write_attribute_if_chain ( & mut self , if_chain : & IfAttributeValue ) -> Result {
603+ let inline_len = self . attr_value_len ( & AttributeValue :: IfExpr ( if_chain. clone ( ) ) ) ;
604+ let line_budget = 80usize . saturating_sub ( self . out . indent_level * 4 ) ;
605+
606+ if inline_len <= line_budget {
607+ self . write_attribute_if_chain_inline ( if_chain)
608+ } else {
609+ self . write_attribute_if_chain_multiline ( if_chain)
610+ }
611+ }
612+
613+ fn write_attribute_if_chain_inline ( & mut self , if_chain : & IfAttributeValue ) -> Result {
573614 let cond = self . unparse_expr ( & if_chain. if_expr . cond ) ;
574615 write ! ( self . out, "if {cond} {{ " ) ?;
575616 self . write_attribute_value ( & if_chain. then_value ) ?;
576617 write ! ( self . out, " }}" ) ?;
577618 match if_chain. else_value . as_deref ( ) {
578619 Some ( AttributeValue :: IfExpr ( else_if_chain) ) => {
579620 write ! ( self . out, " else " ) ?;
580- self . write_attribute_if_chain ( else_if_chain) ?;
621+ self . write_attribute_if_chain_inline ( else_if_chain) ?;
581622 }
582623 Some ( other) => {
583624 write ! ( self . out, " else {{ " ) ?;
@@ -586,7 +627,40 @@ impl<'a> Writer<'a> {
586627 }
587628 None => { }
588629 }
630+ Ok ( ( ) )
631+ }
589632
633+ fn write_attribute_if_chain_multiline ( & mut self , if_chain : & IfAttributeValue ) -> Result {
634+ let base = self . out . indent_level ;
635+ let cond = self . unparse_expr ( & if_chain. if_expr . cond ) ;
636+ write ! ( self . out, "if {cond} {{" ) ?;
637+ self . out . indent_level = base + 1 ;
638+ self . out . new_line ( ) ?;
639+ self . out . tab ( ) ?;
640+ self . write_attribute_value ( & if_chain. then_value ) ?;
641+ self . out . indent_level = base;
642+ self . out . new_line ( ) ?;
643+ self . out . tab ( ) ?;
644+ write ! ( self . out, "}}" ) ?;
645+ match if_chain. else_value . as_deref ( ) {
646+ Some ( AttributeValue :: IfExpr ( else_if_chain) ) => {
647+ write ! ( self . out, " else " ) ?;
648+ self . write_attribute_if_chain_multiline ( else_if_chain) ?;
649+ }
650+ Some ( other) => {
651+ write ! ( self . out, " else {{" ) ?;
652+ self . out . indent_level = base + 1 ;
653+ self . out . new_line ( ) ?;
654+ self . out . tab ( ) ?;
655+ self . write_attribute_value ( other) ?;
656+ self . out . indent_level = base;
657+ self . out . new_line ( ) ?;
658+ self . out . tab ( ) ?;
659+ write ! ( self . out, "}}" ) ?;
660+ }
661+ None => { }
662+ }
663+ self . out . indent_level = base;
590664 Ok ( ( ) )
591665 }
592666
@@ -838,18 +912,24 @@ impl<'a> Writer<'a> {
838912 return Ok ( ( ) ) ;
839913 }
840914
915+ let comments: Vec < & str > = ( start. line ..end. line )
916+ . filter_map ( |idx| {
917+ let line = self . src . get ( idx) ?;
918+ line. trim ( ) . starts_with ( "//" ) . then_some ( line. trim ( ) )
919+ } )
920+ . collect ( ) ;
921+
922+ if comments. is_empty ( ) {
923+ return Ok ( ( ) ) ;
924+ }
925+
841926 writeln ! ( self . out) ?;
842927
843- for idx in start. line ..end. line {
844- let Some ( line) = self . src . get ( idx) else {
845- continue ;
846- } ;
847- if line. trim ( ) . starts_with ( "//" ) {
848- for _ in 0 ..self . out . indent_level + 1 {
849- write ! ( self . out, " " ) ?
850- }
851- writeln ! ( self . out, "{}" , line. trim( ) ) ?;
928+ for comment in & comments {
929+ for _ in 0 ..self . out . indent_level + 1 {
930+ write ! ( self . out, " " ) ?
852931 }
932+ writeln ! ( self . out, "{comment}" ) ?;
853933 }
854934
855935 for _ in 0 ..self . out . indent_level {
0 commit comments