nushell on your web browser
nushell wasm terminal

fix subcommands not showing up if command also has argument

ptr.pet 6f317b2d 373a827a

verified
+189 -155
+188 -116
src/completion/context.rs
··· 107 107 .map(|id| engine_guard.get_decl(id).signature()) 108 108 } 109 109 110 + /// Creates CommandArgument context(s), and optionally adds a Command context for subcommands 111 + /// if we're at argument index 0 and the command has subcommands. 112 + pub fn create_command_argument_contexts( 113 + command_name: String, 114 + arg_index: usize, 115 + prefix: String, 116 + span: Span, 117 + working_set: &StateWorkingSet, 118 + _engine_guard: &EngineState, 119 + ) -> Vec<CompletionContext> { 120 + let mut contexts = Vec::new(); 121 + 122 + // Always add the CommandArgument context 123 + contexts.push(CompletionContext { 124 + kind: CompletionKind::CommandArgument { 125 + command_name: command_name.clone(), 126 + arg_index, 127 + }, 128 + prefix: prefix.clone(), 129 + span, 130 + }); 131 + 132 + // If we're at argument index 0, check if the command has subcommands 133 + if arg_index == 0 { 134 + // Check if command has subcommands 135 + // Subcommands are commands that start with "command_name " (with space) 136 + let parent_prefix = format!("{} ", command_name); 137 + let subcommands = working_set 138 + .find_commands_by_predicate(|value| value.starts_with(parent_prefix.as_bytes()), true); 139 + 140 + if !subcommands.is_empty() { 141 + // Command has subcommands - add a Command context for subcommands 142 + console_log!( 143 + "[completion] Command {command_name:?} has subcommands, adding Command context for subcommands" 144 + ); 145 + contexts.push(CompletionContext { 146 + kind: CompletionKind::Command { 147 + parent_command: Some(command_name), 148 + }, 149 + prefix, 150 + span, 151 + }); 152 + } 153 + } 154 + 155 + contexts 156 + } 157 + 110 158 pub fn determine_flag_or_argument_context( 111 159 input: &str, 112 160 shapes: &[(Span, FlatShape)], ··· 115 163 local_span: Span, 116 164 span: Span, 117 165 global_offset: usize, 118 - ) -> CompletionContext { 166 + working_set: &StateWorkingSet, 167 + _engine_guard: &EngineState, 168 + ) -> Vec<CompletionContext> { 119 169 let trimmed_prefix = prefix.trim(); 120 170 if trimmed_prefix.starts_with('-') { 121 171 // This looks like a flag - find the command 122 172 if let Some((cmd_name, _)) = 123 173 find_command_and_arg_index(input, shapes, idx, local_span, global_offset) 124 174 { 125 - CompletionContext { 175 + vec![CompletionContext { 126 176 kind: CompletionKind::Flag { 127 177 command_name: cmd_name, 128 178 }, 129 179 prefix: trimmed_prefix.to_string(), 130 180 span, 131 - } 181 + }] 132 182 } else { 133 - CompletionContext { 183 + vec![CompletionContext { 134 184 kind: CompletionKind::Argument, 135 185 prefix: prefix.to_string(), 136 186 span, 137 - } 187 + }] 138 188 } 139 189 } else { 140 190 // This is a positional argument - find the command and argument index 141 191 if let Some((cmd_name, arg_index)) = 142 192 find_command_and_arg_index(input, shapes, idx, local_span, global_offset) 143 193 { 144 - CompletionContext { 145 - kind: CompletionKind::CommandArgument { 146 - command_name: cmd_name, 147 - arg_index, 148 - }, 149 - prefix: trimmed_prefix.to_string(), 194 + create_command_argument_contexts( 195 + cmd_name, 196 + arg_index, 197 + trimmed_prefix.to_string(), 150 198 span, 151 - } 199 + working_set, 200 + _engine_guard, 201 + ) 152 202 } else { 153 - CompletionContext { 203 + vec![CompletionContext { 154 204 kind: CompletionKind::Argument, 155 205 prefix: prefix.to_string(), 156 206 span, 157 - } 207 + }] 158 208 } 159 209 } 160 210 } ··· 163 213 input: &str, 164 214 shapes: &[(Span, FlatShape)], 165 215 working_set: &StateWorkingSet, 216 + engine_guard: &EngineState, 166 217 prefix: &str, 167 218 span: Span, 168 219 shape_name: &str, 169 220 current_idx: usize, 170 221 local_span: Span, 171 222 global_offset: usize, 172 - ) -> Option<CompletionContext> { 223 + ) -> Vec<CompletionContext> { 173 224 console_log!("[completion] Processing {shape_name} shape with prefix: {prefix:?}"); 174 225 175 226 // Check if the content ends with a pipe or semicolon ··· 214 265 console_log!( 215 266 "[completion] {shape_name} is empty but found full command {cmd_full:?} before it, not showing completions" 216 267 ); 217 - return None; 268 + return Vec::new(); 218 269 } 219 270 220 271 // Use the first word to show subcommands ··· 233 284 console_log!( 234 285 "[completion] {shape_name} is empty, showing subcommands of {cmd_name:?}" 235 286 ); 236 - Some(CompletionContext { 287 + vec![CompletionContext { 237 288 kind: CompletionKind::Command { 238 289 parent_command: Some(cmd_name), 239 290 }, 240 291 prefix: String::new(), 241 292 span: adjusted_span, 242 - }) 293 + }] 243 294 } else { 244 295 // Truly empty - show all commands 245 296 console_log!("[completion] {shape_name} is empty, setting Command context"); 246 - Some(CompletionContext { 297 + vec![CompletionContext { 247 298 kind: CompletionKind::Command { 248 299 parent_command: None, 249 300 }, 250 301 prefix: String::new(), 251 302 span: adjusted_span, 252 - }) 303 + }] 253 304 } 254 305 } else if let Some(last_sep_pos) = last_sep_pos_in_prefix { 255 306 // After a separator - command context ··· 257 308 console_log!( 258 309 "[completion] {shape_name} has separator at {last_sep_pos}, after_sep={after_sep:?}, setting Command context" 259 310 ); 260 - Some(CompletionContext { 311 + vec![CompletionContext { 261 312 kind: CompletionKind::Command { 262 313 parent_command: None, 263 314 }, 264 315 prefix: after_sep.to_string(), 265 316 span: Span::new(span.start + last_sep_pos, span.end), 266 - }) 317 + }] 267 318 } else { 268 319 console_log!( 269 320 "[completion] {shape_name} has no separator, checking for variable/flag/argument context" ··· 282 333 console_log!( 283 334 "[completion] {shape_name}: Setting CellPath context with var {var_name:?}, prefix {cell_prefix:?}" 284 335 ); 285 - Some(CompletionContext { 336 + vec![CompletionContext { 286 337 kind: CompletionKind::CellPath { 287 338 var_id, 288 339 path_so_far: path_so_far.iter().map(|s| s.to_string()).collect(), 289 340 }, 290 341 prefix: cell_prefix.to_string(), 291 342 span: Span::new(cell_span_start, adjusted_span.end), 292 - }) 343 + }] 293 344 } else { 294 345 // Unknown variable, fall back to variable completion 295 346 let var_prefix = trimmed[1..].to_string(); 296 347 console_log!( 297 348 "[completion] {shape_name}: Unknown var, setting Variable context with prefix {var_prefix:?}" 298 349 ); 299 - Some(CompletionContext { 350 + vec![CompletionContext { 300 351 kind: CompletionKind::Variable, 301 352 prefix: var_prefix, 302 353 span: adjusted_span, 303 - }) 354 + }] 304 355 } 305 356 } else { 306 357 // Simple variable completion (no dot) ··· 312 363 console_log!( 313 364 "[completion] {shape_name}: Setting Variable context with prefix {var_prefix:?}" 314 365 ); 315 - Some(CompletionContext { 366 + vec![CompletionContext { 316 367 kind: CompletionKind::Variable, 317 368 prefix: var_prefix, 318 369 span: adjusted_span, 319 - }) 370 + }] 320 371 } 321 372 } else if trimmed.starts_with('-') { 322 373 // Flag completion ··· 330 381 console_log!( 331 382 "[completion] {shape_name}: Found command {cmd_name:?} for flag completion" 332 383 ); 333 - Some(CompletionContext { 384 + vec![CompletionContext { 334 385 kind: CompletionKind::Flag { 335 386 command_name: cmd_name, 336 387 }, 337 388 prefix: trimmed.to_string(), 338 389 span: adjusted_span, 339 - }) 390 + }] 340 391 } else { 341 - Some(CompletionContext { 392 + vec![CompletionContext { 342 393 kind: CompletionKind::Argument, 343 394 prefix: trimmed_prefix.to_string(), 344 395 span: adjusted_span, 345 - }) 396 + }] 346 397 } 347 398 } else { 348 399 // Try to find the command and argument index ··· 356 407 console_log!( 357 408 "[completion] {shape_name}: Found command {cmd_name:?} with arg_index {arg_index} for argument completion" 358 409 ); 359 - Some(CompletionContext { 360 - kind: CompletionKind::CommandArgument { 361 - command_name: cmd_name, 362 - arg_index, 363 - }, 364 - prefix: trimmed.to_string(), 365 - span: adjusted_span, 366 - }) 410 + create_command_argument_contexts( 411 + cmd_name, 412 + arg_index, 413 + trimmed.to_string(), 414 + adjusted_span, 415 + working_set, 416 + engine_guard, 417 + ) 367 418 } else { 368 419 // No command found, treat as regular argument 369 420 console_log!( 370 421 "[completion] {shape_name}: No command found, using Argument context" 371 422 ); 372 - Some(CompletionContext { 423 + vec![CompletionContext { 373 424 kind: CompletionKind::Argument, 374 425 prefix: trimmed_prefix.to_string(), 375 426 span: adjusted_span, 376 - }) 427 + }] 377 428 } 378 429 } 379 430 } 380 431 } else { 381 - None 432 + Vec::new() 382 433 } 383 434 } 384 435 385 436 pub fn handle_variable_string_shape( 386 437 input: &str, 387 438 shapes: &[(Span, FlatShape)], 388 - _working_set: &StateWorkingSet, 439 + working_set: &StateWorkingSet, 440 + engine_guard: &EngineState, 389 441 idx: usize, 390 442 prefix: &str, 391 443 span: Span, 392 444 local_span: Span, 393 445 global_offset: usize, 394 - ) -> Option<CompletionContext> { 446 + ) -> Vec<CompletionContext> { 395 447 if idx == 0 { 396 - return None; 448 + return Vec::new(); 397 449 } 398 450 399 451 let prev_shape = &shapes[idx - 1]; ··· 414 466 console_log!( 415 467 "[completion] Detected cell path from Variable+String shapes, var_id={var_id:?}, prefix={cell_prefix:?}, path={path_so_far:?}" 416 468 ); 417 - Some(CompletionContext { 469 + vec![CompletionContext { 418 470 kind: CompletionKind::CellPath { 419 471 var_id, 420 472 path_so_far: path_so_far.iter().map(|s| s.to_string()).collect(), 421 473 }, 422 474 prefix: cell_prefix.to_string(), 423 475 span: Span::new(cell_span_start, span.end), 424 - }) 476 + }] 425 477 } else { 426 478 // Gap between shapes, use helper to determine context 427 - Some(determine_flag_or_argument_context( 479 + determine_flag_or_argument_context( 428 480 input, 429 481 shapes, 430 482 &prefix.trim(), ··· 432 484 local_span, 433 485 span, 434 486 global_offset, 435 - )) 487 + working_set, 488 + engine_guard, 489 + ) 436 490 } 437 491 } else { 438 492 // Previous shape is not a Variable, use helper to determine context 439 - Some(determine_flag_or_argument_context( 493 + determine_flag_or_argument_context( 440 494 input, 441 495 shapes, 442 496 &prefix.trim(), ··· 444 498 local_span, 445 499 span, 446 500 global_offset, 447 - )) 501 + working_set, 502 + engine_guard, 503 + ) 448 504 } 449 505 } 450 506 ··· 456 512 span: Span, 457 513 local_span: Span, 458 514 global_offset: usize, 459 - ) -> Option<CompletionContext> { 515 + ) -> Vec<CompletionContext> { 460 516 if idx == 0 { 461 - return Some(CompletionContext { 517 + return vec![CompletionContext { 462 518 kind: CompletionKind::Argument, 463 519 prefix: prefix.to_string(), 464 520 span, 465 - }); 521 + }]; 466 522 } 467 523 468 524 let prev_shape = &shapes[idx - 1]; ··· 485 541 console_log!( 486 542 "[completion] Detected cell path from adjacent Variable shape, var_id={var_id:?}, prefix={cell_prefix:?}" 487 543 ); 488 - Some(CompletionContext { 544 + vec![CompletionContext { 489 545 kind: CompletionKind::CellPath { 490 546 var_id, 491 547 path_so_far: path_so_far.iter().map(|s| s.to_string()).collect(), 492 548 }, 493 549 prefix: cell_prefix.to_string(), 494 550 span: Span::new(cell_span_start, span.end), 495 - }) 551 + }] 496 552 } else { 497 553 // Gap between shapes, fall through to default handling 498 - Some(CompletionContext { 554 + vec![CompletionContext { 499 555 kind: CompletionKind::Argument, 500 556 prefix: prefix.to_string(), 501 557 span, 502 - }) 558 + }] 503 559 } 504 560 } else { 505 561 // Previous shape is not a Variable, this is likely a file path starting with . 506 - Some(CompletionContext { 562 + vec![CompletionContext { 507 563 kind: CompletionKind::Argument, 508 564 prefix: prefix.to_string(), 509 565 span, 510 - }) 566 + }] 511 567 } 512 568 } 513 569 ··· 515 571 input: &str, 516 572 shapes: &[(Span, FlatShape)], 517 573 working_set: &StateWorkingSet, 574 + engine_guard: &EngineState, 518 575 byte_pos: usize, 519 576 global_offset: usize, 520 - ) -> Option<CompletionContext> { 577 + ) -> Vec<CompletionContext> { 521 578 // First, check if cursor is within a shape 522 579 for (idx, (span, shape)) in shapes.iter().enumerate() { 523 580 let local_span = to_local_span(*span, global_offset); ··· 547 604 if trimmed_prefix == "{" { 548 605 // We're right after '{' - command context 549 606 if let Some((_, adjusted_span, _)) = handle_block_prefix(&prefix, span) { 550 - return Some(CompletionContext { 607 + return vec![CompletionContext { 551 608 kind: CompletionKind::Command { 552 609 parent_command: None, 553 610 }, 554 611 prefix: String::new(), 555 612 span: adjusted_span, 556 - }); 613 + }]; 557 614 } 558 615 } else { 559 616 match shape { 560 617 // Special case: Check if we're completing a cell path where the Variable and field are in separate shapes 561 618 _ if { idx > 0 && matches!(shape, FlatShape::String) } => { 562 - if let Some(ctx) = handle_variable_string_shape( 619 + let contexts = handle_variable_string_shape( 563 620 input, 564 621 shapes, 565 622 working_set, 623 + engine_guard, 566 624 idx, 567 625 &prefix, 568 626 span, 569 627 local_span, 570 628 global_offset, 571 - ) { 572 - return Some(ctx); 629 + ); 630 + if !contexts.is_empty() { 631 + return contexts; 573 632 } 574 633 } 575 634 // Special case: Check if we're completing a cell path where the Variable and dot are in separate shapes ··· 578 637 trimmed_prefix.starts_with('.') && idx > 0 579 638 } => 580 639 { 581 - if let Some(ctx) = handle_dot_shape( 640 + let contexts = handle_dot_shape( 582 641 input, 583 642 shapes, 584 643 idx, ··· 586 645 span, 587 646 local_span, 588 647 global_offset, 589 - ) { 590 - return Some(ctx); 648 + ); 649 + if !contexts.is_empty() { 650 + return contexts; 591 651 } 592 652 } 593 653 _ if { ··· 608 668 // Calculate span for the cell path member being completed 609 669 let prefix_byte_len = cell_prefix.len(); 610 670 let cell_span_start = span.end.saturating_sub(prefix_byte_len); 611 - return Some(CompletionContext { 671 + return vec![CompletionContext { 612 672 kind: CompletionKind::CellPath { 613 673 var_id, 614 674 path_so_far: path_so_far ··· 618 678 }, 619 679 prefix: cell_prefix.to_string(), 620 680 span: Span::new(cell_span_start, span.end), 621 - }); 681 + }]; 622 682 } else { 623 683 // Unknown variable, fall back to variable completion 624 684 let var_prefix = trimmed_prefix[1..].to_string(); 625 - return Some(CompletionContext { 685 + return vec![CompletionContext { 626 686 kind: CompletionKind::Variable, 627 687 prefix: var_prefix, 628 688 span, 629 - }); 689 + }]; 630 690 } 631 691 } else { 632 692 // Variable completion context (no dot) ··· 635 695 } else { 636 696 String::new() 637 697 }; 638 - return Some(CompletionContext { 698 + return vec![CompletionContext { 639 699 kind: CompletionKind::Variable, 640 700 prefix: var_prefix, 641 701 span, 642 - }); 702 + }]; 643 703 } 644 704 } 645 705 _ if is_command_shape(input, shape, local_span) => { 646 706 let (full_prefix, full_span) = 647 707 build_command_prefix(input, shapes, idx, span, &prefix, global_offset); 648 - return Some(CompletionContext { 708 + return vec![CompletionContext { 649 709 kind: CompletionKind::Command { 650 710 parent_command: None, 651 711 }, 652 712 prefix: full_prefix, 653 713 span: full_span, 654 - }); 714 + }]; 655 715 } 656 716 FlatShape::Block | FlatShape::Closure => { 657 - if let Some(ctx) = handle_block_or_closure( 717 + let contexts = handle_block_or_closure( 658 718 input, 659 719 shapes, 660 720 working_set, 721 + engine_guard, 661 722 &prefix, 662 723 span, 663 724 shape.as_str().trim_start_matches("shape_"), 664 725 idx, 665 726 local_span, 666 727 global_offset, 667 - ) { 668 - return Some(ctx); 728 + ); 729 + if !contexts.is_empty() { 730 + return contexts; 669 731 } 670 732 } 671 733 FlatShape::Variable(var_id) => { ··· 678 740 { 679 741 let prefix_byte_len = cell_prefix.len(); 680 742 let cell_span_start = span.end.saturating_sub(prefix_byte_len); 681 - return Some(CompletionContext { 743 + return vec![CompletionContext { 682 744 kind: CompletionKind::CellPath { 683 745 var_id: *var_id, 684 746 path_so_far: path_so_far ··· 688 750 }, 689 751 prefix: cell_prefix.to_string(), 690 752 span: Span::new(cell_span_start, span.end), 691 - }); 753 + }]; 692 754 } else { 693 755 // Simple variable completion 694 756 let var_prefix = trimmed_prefix[1..].to_string(); 695 - return Some(CompletionContext { 757 + return vec![CompletionContext { 696 758 kind: CompletionKind::Variable, 697 759 prefix: var_prefix, 698 760 span, 699 - }); 761 + }]; 700 762 } 701 763 } else { 702 764 // Fallback to argument context if no $ found 703 - return Some(CompletionContext { 765 + return vec![CompletionContext { 704 766 kind: CompletionKind::Argument, 705 767 prefix: prefix.to_string(), 706 768 span, 707 - }); 769 + }]; 708 770 } 709 771 } 710 772 _ => { ··· 719 781 if let Some(var_id) = var_id { 720 782 let prefix_byte_len = cell_prefix.len(); 721 783 let cell_span_start = span.end.saturating_sub(prefix_byte_len); 722 - return Some(CompletionContext { 784 + return vec![CompletionContext { 723 785 kind: CompletionKind::CellPath { 724 786 var_id, 725 787 path_so_far: path_so_far ··· 729 791 }, 730 792 prefix: cell_prefix.to_string(), 731 793 span: Span::new(cell_span_start, span.end), 732 - }); 794 + }]; 733 795 } else { 734 796 let var_prefix = trimmed_prefix[1..].to_string(); 735 - return Some(CompletionContext { 797 + return vec![CompletionContext { 736 798 kind: CompletionKind::Variable, 737 799 prefix: var_prefix, 738 800 span, 739 - }); 801 + }]; 740 802 } 741 803 } else { 742 804 // Simple variable completion ··· 745 807 } else { 746 808 String::new() 747 809 }; 748 - return Some(CompletionContext { 810 + return vec![CompletionContext { 749 811 kind: CompletionKind::Variable, 750 812 prefix: var_prefix, 751 813 span, 752 - }); 814 + }]; 753 815 } 754 816 } else { 755 817 // Use helper to determine flag or argument context 756 - return Some(determine_flag_or_argument_context( 818 + return determine_flag_or_argument_context( 757 819 input, 758 820 shapes, 759 821 &trimmed_prefix, ··· 761 823 local_span, 762 824 span, 763 825 global_offset, 764 - )); 826 + working_set, 827 + engine_guard, 828 + ); 765 829 } 766 830 } 767 831 } ··· 769 833 break; 770 834 } 771 835 } 772 - None 836 + Vec::new() 773 837 } 774 838 775 839 pub fn determine_context_fallback( ··· 855 919 "[completion] Right after command {cmd_name:?}, setting CommandArgument context with arg_index: {arg_count}" 856 920 ); 857 921 858 - context.push(CompletionContext { 859 - kind: CompletionKind::CommandArgument { 860 - command_name: cmd_name.clone(), 861 - arg_index: arg_count, 862 - }, 863 - prefix: String::new(), 864 - span: Span::new(byte_pos, byte_pos), 865 - }); 922 + // Use helper to create CommandArgument context(s) - may include subcommand context 923 + let arg_contexts = create_command_argument_contexts( 924 + cmd_name.clone(), 925 + arg_count, 926 + String::new(), 927 + Span::new(byte_pos, byte_pos), 928 + working_set, 929 + engine_guard, 930 + ); 931 + context.extend(arg_contexts); 866 932 } 867 933 } 868 934 // No positional arguments ··· 1045 1111 } 1046 1112 } 1047 1113 if let Some(cmd_name) = found_cmd { 1048 - vec![CompletionContext { 1049 - kind: CompletionKind::CommandArgument { 1050 - command_name: cmd_name, 1051 - arg_index: arg_count, 1052 - }, 1053 - prefix: trimmed_word.to_string(), 1054 - span: Span::new(last_word_start, byte_pos), 1055 - }] 1114 + create_command_argument_contexts( 1115 + cmd_name, 1116 + arg_count, 1117 + trimmed_word.to_string(), 1118 + Span::new(last_word_start, byte_pos), 1119 + working_set, 1120 + engine_guard, 1121 + ) 1056 1122 } else { 1057 1123 vec![CompletionContext { 1058 1124 kind: CompletionKind::Argument, ··· 1073 1139 global_offset: usize, 1074 1140 ) -> Vec<CompletionContext> { 1075 1141 // First try to determine context from shapes 1076 - if let Some(ctx) = 1077 - determine_context_from_shape(input, shapes, working_set, byte_pos, global_offset) 1078 - { 1079 - return vec![ctx]; 1142 + let contexts = determine_context_from_shape( 1143 + input, 1144 + shapes, 1145 + working_set, 1146 + engine_guard, 1147 + byte_pos, 1148 + global_offset, 1149 + ); 1150 + if !contexts.is_empty() { 1151 + return contexts; 1080 1152 } 1081 1153 1082 1154 // Fallback to token-based context determination
+1 -39
src/completion/suggestions.rs
··· 194 194 pub fn generate_command_argument_suggestions( 195 195 input: &str, 196 196 engine_guard: &EngineState, 197 - working_set: &StateWorkingSet, 197 + _working_set: &StateWorkingSet, 198 198 prefix: String, 199 199 span: Span, 200 200 command_name: String, ··· 206 206 ); 207 207 208 208 let mut suggestions = Vec::new(); 209 - 210 - // If we're at argument index 0, check if the command has subcommands and add them 211 - if arg_index == 0 { 212 - let parent_prefix = format!("{} ", command_name); 213 - let search_prefix = if prefix.is_empty() { 214 - parent_prefix.clone() 215 - } else { 216 - format!("{}{}", parent_prefix, prefix) 217 - }; 218 - 219 - let subcommands = working_set 220 - .find_commands_by_predicate(|value| value.starts_with(search_prefix.as_bytes()), true); 221 - 222 - if !subcommands.is_empty() { 223 - // Command has subcommands - add them to suggestions 224 - console_log!( 225 - "[completion] Command {command_name:?} has subcommands, adding subcommand suggestions for prefix: {prefix:?}" 226 - ); 227 - let span = to_char_span(input, span); 228 - for (_, name, desc, _) in subcommands { 229 - let name_str = String::from_utf8_lossy(&name).to_string(); 230 - if let Some(subcommand_name) = name_str.strip_prefix(&parent_prefix) { 231 - suggestions.push(Suggestion { 232 - rendered: { 233 - let name_colored = 234 - ansi_term::Color::Green.bold().paint(subcommand_name); 235 - let desc_str = desc.as_deref().unwrap_or("<no description>"); 236 - format!("{name_colored} {desc_str}") 237 - }, 238 - name: subcommand_name.to_string(), 239 - description: desc.map(|d| d.to_string()), 240 - span_start: span.start, 241 - span_end: span.end, 242 - }); 243 - } 244 - } 245 - } 246 - } 247 209 248 210 if let Some(signature) = get_command_signature(engine_guard, &command_name) { 249 211 // First, check if we're completing an argument for a flag