@@ -297,9 +297,12 @@ fn format_index_expr(
297297 . map ( |prefix| format_expr ( ctx, plan, & prefix) )
298298 . unwrap_or_default ( ) ;
299299 let access_docs = format_index_access_ir ( ctx, plan, expr) ;
300- let indent_tail = expr
301- . get_index_token ( )
302- . is_some_and ( |token| token. is_dot ( ) || token. is_colon ( ) ) ;
300+ let indent_tail = matches ! (
301+ access_docs. first( ) ,
302+ Some ( DocIR :: SyntaxToken (
303+ LuaTokenKind :: TkDot | LuaTokenKind :: TkColon
304+ ) )
305+ ) ;
303306
304307 let bridge = analyze_expr_bridge ( expr. syntax ( ) ) ;
305308 if bridge. has_line_break || !bridge. comment_fragments . is_empty ( ) {
@@ -349,6 +352,12 @@ pub fn format_param_list_ir(
349352 )
350353}
351354
355+ enum CompactCallArgListAttempt {
356+ Formatted ( Vec < DocIR > ) ,
357+ ReuseDocs ( Vec < Vec < DocIR > > ) ,
358+ CommentsPresent ,
359+ }
360+
352361#[ derive( Default ) ]
353362struct CollectedParamEntries {
354363 entries : Vec < ParamEntry > ,
@@ -665,10 +674,6 @@ fn format_call_arg_list(
665674 }
666675
667676 let preserve_multiline_args = args_list. syntax ( ) . text ( ) . contains_char ( '\n' ) ;
668- let first_arg_is_multiline_table = matches ! (
669- args. first( ) ,
670- Some ( LuaExpr :: TableExpr ( table) ) if table. syntax( ) . text( ) . contains_char( '\n' )
671- ) ;
672677 let attach_first_arg = preserve_multiline_args && should_attach_first_call_arg ( & args) ;
673678 let arg_docs: Vec < Vec < DocIR > > = args
674679 . iter ( )
@@ -684,6 +689,22 @@ fn format_call_arg_list(
684689 )
685690 } )
686691 . collect ( ) ;
692+
693+ format_call_arg_list_from_docs ( ctx, plan, args_list, & args, attach_first_arg, arg_docs)
694+ }
695+
696+ fn format_call_arg_list_from_docs (
697+ ctx : & FormatContext ,
698+ plan : & RootFormatPlan ,
699+ args_list : & LuaCallArgList ,
700+ args : & [ LuaExpr ] ,
701+ attach_first_arg : bool ,
702+ arg_docs : Vec < Vec < DocIR > > ,
703+ ) -> Vec < DocIR > {
704+ let first_arg_is_multiline_table = matches ! (
705+ args. first( ) ,
706+ Some ( LuaExpr :: TableExpr ( table) ) if table. syntax( ) . text( ) . contains_char( '\n' )
707+ ) ;
687708 let ( open, close) = paren_tokens ( args_list. syntax ( ) ) ;
688709 let comma = first_direct_token ( args_list. syntax ( ) , LuaTokenKind :: TkComma ) ;
689710 let layout_plan = expr_sequence_layout_plan ( plan, args_list. syntax ( ) ) ;
@@ -770,22 +791,23 @@ fn format_call_args_with_inline_block_item(
770791 close : DocIR ,
771792 comma : Option < & LuaSyntaxToken > ,
772793) -> Vec < DocIR > {
773- let prefix_items = arg_docs[ ..block_index] . to_vec ( ) ;
774- let block_item = arg_docs[ block_index] . clone ( ) ;
775- let tail_items = arg_docs[ block_index + 1 ..] . to_vec ( ) ;
794+ let prefix_items = & arg_docs[ ..block_index] ;
795+ let block_item = & arg_docs[ block_index] ;
796+ let tail_items = & arg_docs[ block_index + 1 ..] ;
776797
777798 let mut anchored_docs = vec ! [ open. clone( ) ] ;
778799 if !prefix_items. is_empty ( ) {
779- anchored_docs. extend ( ir:: intersperse (
800+ append_docs_with_separator (
801+ & mut anchored_docs,
780802 prefix_items,
781- comma_flat_separator ( plan, comma) ,
782- ) ) ;
803+ & comma_flat_separator ( plan, comma) ,
804+ ) ;
783805 anchored_docs. extend ( comma_flat_separator ( plan, comma) ) ;
784806 }
785- anchored_docs. extend ( block_item) ;
807+ anchored_docs. extend ( block_item. clone ( ) ) ;
786808 if !tail_items. is_empty ( ) {
787809 anchored_docs. push ( ir:: indent ( vec ! [ ir:: fill(
788- build_fill_parts_with_leading_separator( & tail_items, & comma_fill_separator( comma) ) ,
810+ build_fill_parts_with_leading_separator( tail_items, & comma_fill_separator( comma) ) ,
789811 ) ] ) ) ;
790812 anchored_docs. push ( ir:: hard_line ( ) ) ;
791813 anchored_docs. push ( close. clone ( ) ) ;
@@ -794,22 +816,7 @@ fn format_call_args_with_inline_block_item(
794816 }
795817
796818 let anchored = vec ! [ ir:: group_break( anchored_docs) ] ;
797-
798- let mut one_per_line_inner = Vec :: new ( ) ;
799- for ( index, item_docs) in arg_docs. iter ( ) . enumerate ( ) {
800- one_per_line_inner. push ( ir:: hard_line ( ) ) ;
801- one_per_line_inner. extend ( item_docs. clone ( ) ) ;
802- if index + 1 < arg_docs. len ( ) {
803- one_per_line_inner. extend ( comma_token_docs ( comma) ) ;
804- }
805- }
806-
807- let one_per_line = vec ! [ ir:: group_break( vec![
808- open,
809- ir:: indent( one_per_line_inner) ,
810- ir:: hard_line( ) ,
811- close,
812- ] ) ] ;
819+ let one_per_line = build_one_per_line_call_args ( & arg_docs, open, close, comma) ;
813820
814821 choose_sequence_layout (
815822 ctx,
@@ -875,22 +882,7 @@ fn format_call_args_with_block_items(
875882 ir:: hard_line( ) ,
876883 close. clone( ) ,
877884 ] ) ] ;
878-
879- let mut one_per_line_inner = Vec :: new ( ) ;
880- for ( index, item_docs) in arg_docs. iter ( ) . enumerate ( ) {
881- one_per_line_inner. push ( ir:: hard_line ( ) ) ;
882- one_per_line_inner. extend ( item_docs. clone ( ) ) ;
883- if index + 1 < arg_docs. len ( ) {
884- one_per_line_inner. extend ( comma_token_docs ( comma) ) ;
885- }
886- }
887-
888- let one_per_line = vec ! [ ir:: group_break( vec![
889- open,
890- ir:: indent( one_per_line_inner) ,
891- ir:: hard_line( ) ,
892- close,
893- ] ) ] ;
885+ let one_per_line = build_one_per_line_call_args ( & arg_docs, open, close, comma) ;
894886
895887 choose_sequence_layout (
896888 ctx,
@@ -924,6 +916,30 @@ fn render_blocked_call_arg_chunk(items_with_trailing: Vec<Vec<DocIR>>) -> Vec<Do
924916 vec ! [ ir:: fill( parts) ]
925917}
926918
919+ fn build_one_per_line_call_args (
920+ arg_docs : & [ Vec < DocIR > ] ,
921+ open : DocIR ,
922+ close : DocIR ,
923+ comma : Option < & LuaSyntaxToken > ,
924+ ) -> Vec < DocIR > {
925+ let item_count = arg_docs. len ( ) ;
926+ let mut one_per_line_inner = Vec :: new ( ) ;
927+ for ( index, item_docs) in arg_docs. iter ( ) . enumerate ( ) {
928+ one_per_line_inner. push ( ir:: hard_line ( ) ) ;
929+ one_per_line_inner. extend ( item_docs. clone ( ) ) ;
930+ if index + 1 < item_count {
931+ one_per_line_inner. extend ( comma_token_docs ( comma) ) ;
932+ }
933+ }
934+
935+ vec ! [ ir:: group_break( vec![
936+ open,
937+ ir:: indent( one_per_line_inner) ,
938+ ir:: hard_line( ) ,
939+ close,
940+ ] ) ]
941+ }
942+
927943fn should_attach_first_call_arg ( args : & [ LuaExpr ] ) -> bool {
928944 matches ! (
929945 args. first( ) ,
@@ -976,8 +992,9 @@ fn format_call_args_with_attached_first_arg(
976992 return docs;
977993 }
978994
979- let first_arg = arg_docs[ 0 ] . clone ( ) ;
980- let tail_items = arg_docs[ 1 ..] . to_vec ( ) ;
995+ let Some ( ( first_arg, tail_items) ) = arg_docs. split_first ( ) else {
996+ return vec ! [ open, close] ;
997+ } ;
981998 let tail_is_single_line = allow_inline_tail_after_first_arg
982999 && tail_items
9831000 . iter ( )
@@ -987,10 +1004,7 @@ fn format_call_args_with_attached_first_arg(
9871004 let mut docs = vec ! [ open. clone( ) ] ;
9881005 docs. extend ( first_arg. clone ( ) ) ;
9891006 docs. extend ( comma_flat_separator ( plan, comma) ) ;
990- docs. extend ( ir:: intersperse (
991- tail_items. clone ( ) ,
992- comma_flat_separator ( plan, comma) ,
993- ) ) ;
1007+ append_docs_with_separator ( & mut docs, tail_items, & comma_flat_separator ( plan, comma) ) ;
9941008 docs. push ( close. clone ( ) ) ;
9951009 docs
9961010 } ) ;
@@ -1000,31 +1014,18 @@ fn format_call_args_with_attached_first_arg(
10001014 fill_docs. extend ( comma_token_docs ( comma) ) ;
10011015 fill_docs. push ( ir:: indent ( vec ! [
10021016 ir:: soft_line( ) ,
1003- ir:: fill( build_fill_parts( & tail_items, & comma_fill_separator( comma) ) ) ,
1017+ ir:: fill( build_fill_parts( tail_items, & comma_fill_separator( comma) ) ) ,
10041018 ] ) ) ;
10051019 fill_docs. push ( close. clone ( ) ) ;
10061020
1007- let mut one_per_line_docs = vec ! [ open] ;
1008- one_per_line_docs. extend ( first_arg) ;
1009- one_per_line_docs. extend ( comma_token_docs ( comma) ) ;
1010- let mut rest = Vec :: new ( ) ;
1011- for ( index, item_docs) in tail_items. iter ( ) . enumerate ( ) {
1012- rest. push ( ir:: hard_line ( ) ) ;
1013- rest. extend ( item_docs. clone ( ) ) ;
1014- if index + 1 < tail_items. len ( ) {
1015- rest. extend ( comma_token_docs ( comma) ) ;
1016- }
1017- }
1018- one_per_line_docs. push ( ir:: indent ( rest) ) ;
1019- one_per_line_docs. push ( ir:: hard_line ( ) ) ;
1020- one_per_line_docs. push ( close) ;
1021-
10221021 choose_sequence_layout (
10231022 ctx,
10241023 SequenceLayoutCandidates {
10251024 flat,
10261025 fill : Some ( vec ! [ ir:: group( fill_docs) ] ) ,
1027- one_per_line : Some ( vec ! [ ir:: group_break( one_per_line_docs) ] ) ,
1026+ one_per_line : Some ( build_attached_first_arg_one_per_line (
1027+ & arg_docs, open, close, comma,
1028+ ) ) ,
10281029 ..Default :: default ( )
10291030 } ,
10301031 SequenceLayoutPolicy {
@@ -1036,6 +1037,45 @@ fn format_call_args_with_attached_first_arg(
10361037 )
10371038}
10381039
1040+ fn build_attached_first_arg_one_per_line (
1041+ arg_docs : & [ Vec < DocIR > ] ,
1042+ open : DocIR ,
1043+ close : DocIR ,
1044+ comma : Option < & LuaSyntaxToken > ,
1045+ ) -> Vec < DocIR > {
1046+ let mut one_per_line_docs = vec ! [ open] ;
1047+ let Some ( ( first_arg, rest_args) ) = arg_docs. split_first ( ) else {
1048+ one_per_line_docs. push ( close) ;
1049+ return vec ! [ ir:: group_break( one_per_line_docs) ] ;
1050+ } ;
1051+ one_per_line_docs. extend ( first_arg. clone ( ) ) ;
1052+ one_per_line_docs. extend ( comma_token_docs ( comma) ) ;
1053+
1054+ let rest_count = rest_args. len ( ) ;
1055+ let mut rest = Vec :: new ( ) ;
1056+ for ( index, item_docs) in rest_args. iter ( ) . enumerate ( ) {
1057+ rest. push ( ir:: hard_line ( ) ) ;
1058+ rest. extend ( item_docs. clone ( ) ) ;
1059+ if index + 1 < rest_count {
1060+ rest. extend ( comma_token_docs ( comma) ) ;
1061+ }
1062+ }
1063+
1064+ one_per_line_docs. push ( ir:: indent ( rest) ) ;
1065+ one_per_line_docs. push ( ir:: hard_line ( ) ) ;
1066+ one_per_line_docs. push ( close) ;
1067+ vec ! [ ir:: group_break( one_per_line_docs) ]
1068+ }
1069+
1070+ fn append_docs_with_separator ( docs : & mut Vec < DocIR > , items : & [ Vec < DocIR > ] , separator : & [ DocIR ] ) {
1071+ for ( index, item_docs) in items. iter ( ) . enumerate ( ) {
1072+ if index > 0 {
1073+ docs. extend ( separator. to_vec ( ) ) ;
1074+ }
1075+ docs. extend ( item_docs. clone ( ) ) ;
1076+ }
1077+ }
1078+
10391079#[ derive( Default ) ]
10401080struct CollectedCallArgEntries {
10411081 entries : Vec < CallArgEntry > ,
@@ -2438,8 +2478,23 @@ fn format_call_suffix_ir(
24382478 }
24392479
24402480 let docs = if !args_list. syntax ( ) . text ( ) . contains_char ( '\n' ) {
2441- format_compact_call_arg_list ( ctx, plan, & args_list)
2442- . unwrap_or_else ( || format_call_arg_list ( ctx, plan, & args_list) )
2481+ match format_compact_call_arg_list ( ctx, plan, & args_list, & args) {
2482+ CompactCallArgListAttempt :: Formatted ( docs) => docs,
2483+ CompactCallArgListAttempt :: ReuseDocs ( arg_docs) => {
2484+ let attach_first_arg = false ;
2485+ format_call_arg_list_from_docs (
2486+ ctx,
2487+ plan,
2488+ & args_list,
2489+ & args,
2490+ attach_first_arg,
2491+ arg_docs,
2492+ )
2493+ }
2494+ CompactCallArgListAttempt :: CommentsPresent => {
2495+ format_call_arg_list ( ctx, plan, & args_list)
2496+ }
2497+ }
24432498 } else {
24442499 format_call_arg_list ( ctx, plan, & args_list)
24452500 } ;
@@ -2466,24 +2521,24 @@ fn format_compact_call_arg_list(
24662521 ctx : & FormatContext ,
24672522 plan : & RootFormatPlan ,
24682523 args_list : & LuaCallArgList ,
2469- ) -> Option < Vec < DocIR > > {
2470- let args : Vec < _ > = args_list . get_args ( ) . collect ( ) ;
2524+ args : & [ LuaExpr ] ,
2525+ ) -> CompactCallArgListAttempt {
24712526 let collected = collect_call_arg_entries ( ctx, plan, args_list) ;
24722527 if collected. has_comments {
2473- return None ;
2528+ return CompactCallArgListAttempt :: CommentsPresent ;
24742529 }
24752530
24762531 let arg_docs: Vec < Vec < DocIR > > = args. iter ( ) . map ( |arg| format_expr ( ctx, plan, arg) ) . collect ( ) ;
24772532 if arg_docs
24782533 . iter ( )
24792534 . any ( |docs| ir:: ir_has_forced_line_break ( docs) )
24802535 {
2481- return None ;
2536+ return CompactCallArgListAttempt :: ReuseDocs ( arg_docs ) ;
24822537 }
24832538
24842539 let ( open, close) = paren_tokens ( args_list. syntax ( ) ) ;
24852540 let comma = first_direct_token ( args_list. syntax ( ) , LuaTokenKind :: TkComma ) ;
2486- Some ( format_delimited_sequence (
2541+ CompactCallArgListAttempt :: Formatted ( format_delimited_sequence (
24872542 ctx,
24882543 DelimitedSequenceLayout {
24892544 open : token_or_kind_doc ( open. as_ref ( ) , LuaTokenKind :: TkLeftParen ) ,
0 commit comments