fix completions being not unique and duplicated

ptr.pet 373a827a fb6d141e

verified
Changed files
+253 -143
src
+3 -2
src/cmd/ls.rs
··· 98 98 } else { 99 99 // Non-glob path: check if it's a directory and list its contents 100 100 let normalized_path = path_str.trim_start_matches('/').trim_end_matches('/'); 101 - let target_path = base_path.join(normalized_path) 101 + let target_path = base_path 102 + .join(normalized_path) 102 103 .map_err(to_shell_err(call.arguments_span()))?; 103 - 104 + 104 105 let metadata = target_path.metadata().map_err(to_shell_err(span))?; 105 106 match metadata.file_type { 106 107 vfs::VfsFileType::Directory => {
+147 -84
src/completion/context.rs
··· 1 1 use crate::completion::helpers::*; 2 - use crate::completion::types::CompletionContext; 2 + use crate::completion::types::{CompletionContext, CompletionKind}; 3 3 use crate::console_log; 4 4 use nu_parser::FlatShape; 5 5 use nu_protocol::engine::{EngineState, StateWorkingSet}; ··· 122 122 if let Some((cmd_name, _)) = 123 123 find_command_and_arg_index(input, shapes, idx, local_span, global_offset) 124 124 { 125 - CompletionContext::Flag { 125 + CompletionContext { 126 + kind: CompletionKind::Flag { 127 + command_name: cmd_name, 128 + }, 126 129 prefix: trimmed_prefix.to_string(), 127 130 span, 128 - command_name: cmd_name, 129 131 } 130 132 } else { 131 - CompletionContext::Argument { 133 + CompletionContext { 134 + kind: CompletionKind::Argument, 132 135 prefix: prefix.to_string(), 133 136 span, 134 137 } ··· 138 141 if let Some((cmd_name, arg_index)) = 139 142 find_command_and_arg_index(input, shapes, idx, local_span, global_offset) 140 143 { 141 - CompletionContext::CommandArgument { 144 + CompletionContext { 145 + kind: CompletionKind::CommandArgument { 146 + command_name: cmd_name, 147 + arg_index, 148 + }, 142 149 prefix: trimmed_prefix.to_string(), 143 150 span, 144 - command_name: cmd_name, 145 - arg_index, 146 151 } 147 152 } else { 148 - CompletionContext::Argument { 153 + CompletionContext { 154 + kind: CompletionKind::Argument, 149 155 prefix: prefix.to_string(), 150 156 span, 151 157 } ··· 227 233 console_log!( 228 234 "[completion] {shape_name} is empty, showing subcommands of {cmd_name:?}" 229 235 ); 230 - Some(CompletionContext::Command { 236 + Some(CompletionContext { 237 + kind: CompletionKind::Command { 238 + parent_command: Some(cmd_name), 239 + }, 231 240 prefix: String::new(), 232 241 span: adjusted_span, 233 - parent_command: Some(cmd_name), 234 242 }) 235 243 } else { 236 244 // Truly empty - show all commands 237 245 console_log!("[completion] {shape_name} is empty, setting Command context"); 238 - Some(CompletionContext::Command { 246 + Some(CompletionContext { 247 + kind: CompletionKind::Command { 248 + parent_command: None, 249 + }, 239 250 prefix: String::new(), 240 251 span: adjusted_span, 241 - parent_command: None, 242 252 }) 243 253 } 244 254 } else if let Some(last_sep_pos) = last_sep_pos_in_prefix { ··· 247 257 console_log!( 248 258 "[completion] {shape_name} has separator at {last_sep_pos}, after_sep={after_sep:?}, setting Command context" 249 259 ); 250 - Some(CompletionContext::Command { 260 + Some(CompletionContext { 261 + kind: CompletionKind::Command { 262 + parent_command: None, 263 + }, 251 264 prefix: after_sep.to_string(), 252 265 span: Span::new(span.start + last_sep_pos, span.end), 253 - parent_command: None, 254 266 }) 255 267 } else { 256 268 console_log!( ··· 270 282 console_log!( 271 283 "[completion] {shape_name}: Setting CellPath context with var {var_name:?}, prefix {cell_prefix:?}" 272 284 ); 273 - Some(CompletionContext::CellPath { 285 + Some(CompletionContext { 286 + kind: CompletionKind::CellPath { 287 + var_id, 288 + path_so_far: path_so_far.iter().map(|s| s.to_string()).collect(), 289 + }, 274 290 prefix: cell_prefix.to_string(), 275 291 span: Span::new(cell_span_start, adjusted_span.end), 276 - var_id, 277 - path_so_far: path_so_far.iter().map(|s| s.to_string()).collect(), 278 292 }) 279 293 } else { 280 294 // Unknown variable, fall back to variable completion ··· 282 296 console_log!( 283 297 "[completion] {shape_name}: Unknown var, setting Variable context with prefix {var_prefix:?}" 284 298 ); 285 - Some(CompletionContext::Variable { 299 + Some(CompletionContext { 300 + kind: CompletionKind::Variable, 286 301 prefix: var_prefix, 287 302 span: adjusted_span, 288 303 }) ··· 297 312 console_log!( 298 313 "[completion] {shape_name}: Setting Variable context with prefix {var_prefix:?}" 299 314 ); 300 - Some(CompletionContext::Variable { 315 + Some(CompletionContext { 316 + kind: CompletionKind::Variable, 301 317 prefix: var_prefix, 302 318 span: adjusted_span, 303 319 }) ··· 314 330 console_log!( 315 331 "[completion] {shape_name}: Found command {cmd_name:?} for flag completion" 316 332 ); 317 - Some(CompletionContext::Flag { 333 + Some(CompletionContext { 334 + kind: CompletionKind::Flag { 335 + command_name: cmd_name, 336 + }, 318 337 prefix: trimmed.to_string(), 319 338 span: adjusted_span, 320 - command_name: cmd_name, 321 339 }) 322 340 } else { 323 - Some(CompletionContext::Argument { 341 + Some(CompletionContext { 342 + kind: CompletionKind::Argument, 324 343 prefix: trimmed_prefix.to_string(), 325 344 span: adjusted_span, 326 345 }) ··· 337 356 console_log!( 338 357 "[completion] {shape_name}: Found command {cmd_name:?} with arg_index {arg_index} for argument completion" 339 358 ); 340 - Some(CompletionContext::CommandArgument { 359 + Some(CompletionContext { 360 + kind: CompletionKind::CommandArgument { 361 + command_name: cmd_name, 362 + arg_index, 363 + }, 341 364 prefix: trimmed.to_string(), 342 365 span: adjusted_span, 343 - command_name: cmd_name, 344 - arg_index, 345 366 }) 346 367 } else { 347 368 // No command found, treat as regular argument 348 369 console_log!( 349 370 "[completion] {shape_name}: No command found, using Argument context" 350 371 ); 351 - Some(CompletionContext::Argument { 372 + Some(CompletionContext { 373 + kind: CompletionKind::Argument, 352 374 prefix: trimmed_prefix.to_string(), 353 375 span: adjusted_span, 354 376 }) ··· 392 414 console_log!( 393 415 "[completion] Detected cell path from Variable+String shapes, var_id={var_id:?}, prefix={cell_prefix:?}, path={path_so_far:?}" 394 416 ); 395 - Some(CompletionContext::CellPath { 417 + Some(CompletionContext { 418 + kind: CompletionKind::CellPath { 419 + var_id, 420 + path_so_far: path_so_far.iter().map(|s| s.to_string()).collect(), 421 + }, 396 422 prefix: cell_prefix.to_string(), 397 423 span: Span::new(cell_span_start, span.end), 398 - var_id, 399 - path_so_far: path_so_far.iter().map(|s| s.to_string()).collect(), 400 424 }) 401 425 } else { 402 426 // Gap between shapes, use helper to determine context ··· 434 458 global_offset: usize, 435 459 ) -> Option<CompletionContext> { 436 460 if idx == 0 { 437 - return Some(CompletionContext::Argument { 461 + return Some(CompletionContext { 462 + kind: CompletionKind::Argument, 438 463 prefix: prefix.to_string(), 439 464 span, 440 465 }); ··· 460 485 console_log!( 461 486 "[completion] Detected cell path from adjacent Variable shape, var_id={var_id:?}, prefix={cell_prefix:?}" 462 487 ); 463 - Some(CompletionContext::CellPath { 488 + Some(CompletionContext { 489 + kind: CompletionKind::CellPath { 490 + var_id, 491 + path_so_far: path_so_far.iter().map(|s| s.to_string()).collect(), 492 + }, 464 493 prefix: cell_prefix.to_string(), 465 494 span: Span::new(cell_span_start, span.end), 466 - var_id, 467 - path_so_far: path_so_far.iter().map(|s| s.to_string()).collect(), 468 495 }) 469 496 } else { 470 497 // Gap between shapes, fall through to default handling 471 - Some(CompletionContext::Argument { 498 + Some(CompletionContext { 499 + kind: CompletionKind::Argument, 472 500 prefix: prefix.to_string(), 473 501 span, 474 502 }) 475 503 } 476 504 } else { 477 505 // Previous shape is not a Variable, this is likely a file path starting with . 478 - Some(CompletionContext::Argument { 506 + Some(CompletionContext { 507 + kind: CompletionKind::Argument, 479 508 prefix: prefix.to_string(), 480 509 span, 481 510 }) ··· 518 547 if trimmed_prefix == "{" { 519 548 // We're right after '{' - command context 520 549 if let Some((_, adjusted_span, _)) = handle_block_prefix(&prefix, span) { 521 - return Some(CompletionContext::Command { 550 + return Some(CompletionContext { 551 + kind: CompletionKind::Command { 552 + parent_command: None, 553 + }, 522 554 prefix: String::new(), 523 555 span: adjusted_span, 524 - parent_command: None, 525 556 }); 526 557 } 527 558 } else { ··· 577 608 // Calculate span for the cell path member being completed 578 609 let prefix_byte_len = cell_prefix.len(); 579 610 let cell_span_start = span.end.saturating_sub(prefix_byte_len); 580 - return Some(CompletionContext::CellPath { 611 + return Some(CompletionContext { 612 + kind: CompletionKind::CellPath { 613 + var_id, 614 + path_so_far: path_so_far 615 + .iter() 616 + .map(|s| s.to_string()) 617 + .collect(), 618 + }, 581 619 prefix: cell_prefix.to_string(), 582 620 span: Span::new(cell_span_start, span.end), 583 - var_id, 584 - path_so_far: path_so_far 585 - .iter() 586 - .map(|s| s.to_string()) 587 - .collect(), 588 621 }); 589 622 } else { 590 623 // Unknown variable, fall back to variable completion 591 624 let var_prefix = trimmed_prefix[1..].to_string(); 592 - return Some(CompletionContext::Variable { 625 + return Some(CompletionContext { 626 + kind: CompletionKind::Variable, 593 627 prefix: var_prefix, 594 628 span, 595 629 }); ··· 601 635 } else { 602 636 String::new() 603 637 }; 604 - return Some(CompletionContext::Variable { 638 + return Some(CompletionContext { 639 + kind: CompletionKind::Variable, 605 640 prefix: var_prefix, 606 641 span, 607 642 }); ··· 610 645 _ if is_command_shape(input, shape, local_span) => { 611 646 let (full_prefix, full_span) = 612 647 build_command_prefix(input, shapes, idx, span, &prefix, global_offset); 613 - return Some(CompletionContext::Command { 648 + return Some(CompletionContext { 649 + kind: CompletionKind::Command { 650 + parent_command: None, 651 + }, 614 652 prefix: full_prefix, 615 653 span: full_span, 616 - parent_command: None, 617 654 }); 618 655 } 619 656 FlatShape::Block | FlatShape::Closure => { ··· 641 678 { 642 679 let prefix_byte_len = cell_prefix.len(); 643 680 let cell_span_start = span.end.saturating_sub(prefix_byte_len); 644 - return Some(CompletionContext::CellPath { 681 + return Some(CompletionContext { 682 + kind: CompletionKind::CellPath { 683 + var_id: *var_id, 684 + path_so_far: path_so_far 685 + .iter() 686 + .map(|s| s.to_string()) 687 + .collect(), 688 + }, 645 689 prefix: cell_prefix.to_string(), 646 690 span: Span::new(cell_span_start, span.end), 647 - var_id: *var_id, 648 - path_so_far: path_so_far 649 - .iter() 650 - .map(|s| s.to_string()) 651 - .collect(), 652 691 }); 653 692 } else { 654 693 // Simple variable completion 655 694 let var_prefix = trimmed_prefix[1..].to_string(); 656 - return Some(CompletionContext::Variable { 695 + return Some(CompletionContext { 696 + kind: CompletionKind::Variable, 657 697 prefix: var_prefix, 658 698 span, 659 699 }); 660 700 } 661 701 } else { 662 702 // Fallback to argument context if no $ found 663 - return Some(CompletionContext::Argument { 703 + return Some(CompletionContext { 704 + kind: CompletionKind::Argument, 664 705 prefix: prefix.to_string(), 665 706 span, 666 707 }); ··· 678 719 if let Some(var_id) = var_id { 679 720 let prefix_byte_len = cell_prefix.len(); 680 721 let cell_span_start = span.end.saturating_sub(prefix_byte_len); 681 - return Some(CompletionContext::CellPath { 722 + return Some(CompletionContext { 723 + kind: CompletionKind::CellPath { 724 + var_id, 725 + path_so_far: path_so_far 726 + .iter() 727 + .map(|s| s.to_string()) 728 + .collect(), 729 + }, 682 730 prefix: cell_prefix.to_string(), 683 731 span: Span::new(cell_span_start, span.end), 684 - var_id, 685 - path_so_far: path_so_far 686 - .iter() 687 - .map(|s| s.to_string()) 688 - .collect(), 689 732 }); 690 733 } else { 691 734 let var_prefix = trimmed_prefix[1..].to_string(); 692 - return Some(CompletionContext::Variable { 735 + return Some(CompletionContext { 736 + kind: CompletionKind::Variable, 693 737 prefix: var_prefix, 694 738 span, 695 739 }); ··· 701 745 } else { 702 746 String::new() 703 747 }; 704 - return Some(CompletionContext::Variable { 748 + return Some(CompletionContext { 749 + kind: CompletionKind::Variable, 705 750 prefix: var_prefix, 706 751 span, 707 752 }); ··· 810 855 "[completion] Right after command {cmd_name:?}, setting CommandArgument context with arg_index: {arg_count}" 811 856 ); 812 857 813 - context.push(CompletionContext::CommandArgument { 858 + context.push(CompletionContext { 859 + kind: CompletionKind::CommandArgument { 860 + command_name: cmd_name.clone(), 861 + arg_index: arg_count, 862 + }, 814 863 prefix: String::new(), 815 864 span: Span::new(byte_pos, byte_pos), 816 - command_name: cmd_name.clone(), 817 - arg_index: arg_count, 818 865 }); 819 866 } 820 867 } ··· 830 877 console_log!( 831 878 "[completion] Command {cmd_name:?} has no positional args, showing subcommands" 832 879 ); 833 - context.push(CompletionContext::Command { 880 + context.push(CompletionContext { 881 + kind: CompletionKind::Command { 882 + parent_command: Some(cmd_first_word), 883 + }, 834 884 prefix: String::new(), 835 885 span: Span::new(byte_pos, byte_pos), 836 - parent_command: Some(cmd_first_word), 837 886 }); 838 887 } 839 888 // reverse to put subcommands in the beginning ··· 842 891 } else { 843 892 // Not right after command, complete the command itself 844 893 console_log!("[completion] Set Command context with prefix: {cmd:?}"); 845 - return vec![CompletionContext::Command { 894 + return vec![CompletionContext { 895 + kind: CompletionKind::Command { 896 + parent_command: None, 897 + }, 846 898 prefix: cmd.to_string(), 847 899 span: local_span, 848 - parent_command: None, 849 900 }]; 850 901 } 851 902 } ··· 902 953 console_log!("[completion] last_word_start={last_word_start}, last_word={last_word:?}"); 903 954 904 955 if is_cmd_context { 905 - vec![CompletionContext::Command { 956 + vec![CompletionContext { 957 + kind: CompletionKind::Command { 958 + parent_command: None, 959 + }, 906 960 prefix: last_word.to_string(), 907 961 span: Span::new(last_word_start, byte_pos), 908 - parent_command: None, 909 962 }] 910 963 } else { 911 964 // Check if this is a variable or cell path (starts with $) ··· 918 971 if let Some(var_id) = var_id { 919 972 let prefix_byte_len = cell_prefix.len(); 920 973 let cell_span_start = byte_pos.saturating_sub(prefix_byte_len); 921 - vec![CompletionContext::CellPath { 974 + vec![CompletionContext { 975 + kind: CompletionKind::CellPath { 976 + var_id, 977 + path_so_far: path_so_far.iter().map(|s| s.to_string()).collect(), 978 + }, 922 979 prefix: cell_prefix.to_string(), 923 980 span: Span::new(cell_span_start, byte_pos), 924 - var_id, 925 - path_so_far: path_so_far.iter().map(|s| s.to_string()).collect(), 926 981 }] 927 982 } else { 928 983 let var_prefix = trimmed_word[1..].to_string(); 929 - vec![CompletionContext::Variable { 984 + vec![CompletionContext { 985 + kind: CompletionKind::Variable, 930 986 prefix: var_prefix, 931 987 span: Span::new(last_word_start, byte_pos), 932 988 }] ··· 934 990 } else { 935 991 // Simple variable completion 936 992 let var_prefix = trimmed_word[1..].to_string(); 937 - vec![CompletionContext::Variable { 993 + vec![CompletionContext { 994 + kind: CompletionKind::Variable, 938 995 prefix: var_prefix, 939 996 span: Span::new(last_word_start, byte_pos), 940 997 }] ··· 952 1009 } 953 1010 } 954 1011 if let Some(cmd_name) = found_cmd { 955 - vec![CompletionContext::Flag { 1012 + vec![CompletionContext { 1013 + kind: CompletionKind::Flag { 1014 + command_name: cmd_name, 1015 + }, 956 1016 prefix: trimmed_word.to_string(), 957 1017 span: Span::new(last_word_start, byte_pos), 958 - command_name: cmd_name, 959 1018 }] 960 1019 } else { 961 - vec![CompletionContext::Argument { 1020 + vec![CompletionContext { 1021 + kind: CompletionKind::Argument, 962 1022 prefix: last_word.to_string(), 963 1023 span: Span::new(last_word_start, byte_pos), 964 1024 }] ··· 985 1045 } 986 1046 } 987 1047 if let Some(cmd_name) = found_cmd { 988 - vec![CompletionContext::CommandArgument { 1048 + vec![CompletionContext { 1049 + kind: CompletionKind::CommandArgument { 1050 + command_name: cmd_name, 1051 + arg_index: arg_count, 1052 + }, 989 1053 prefix: trimmed_word.to_string(), 990 1054 span: Span::new(last_word_start, byte_pos), 991 - command_name: cmd_name, 992 - arg_index: arg_count, 993 1055 }] 994 1056 } else { 995 - vec![CompletionContext::Argument { 1057 + vec![CompletionContext { 1058 + kind: CompletionKind::Argument, 996 1059 prefix: last_word.to_string(), 997 1060 span: Span::new(last_word_start, byte_pos), 998 1061 }]
+5 -1
src/completion/mod.rs
··· 73 73 global_offset, 74 74 ); 75 75 76 + // Convert Vec to HashSet 77 + use std::collections::HashSet; 78 + let context_set: HashSet<CompletionContext> = context.into_iter().collect(); 79 + 76 80 // Generate suggestions based on context 77 81 let suggestions = generate_suggestions( 78 82 &input, 79 - context, 83 + context_set, 80 84 &working_set, 81 85 &engine_guard, 82 86 &stack_guard,
+54 -38
src/completion/suggestions.rs
··· 1 1 use crate::completion::context::get_command_signature; 2 2 use crate::completion::helpers::to_char_span; 3 - use crate::completion::types::{CompletionContext, Suggestion}; 3 + use crate::completion::types::{CompletionContext, CompletionKind, Suggestion}; 4 4 use crate::completion::variables::*; 5 5 use crate::console_log; 6 6 use nu_protocol::Span; 7 7 use nu_protocol::engine::{EngineState, Stack, StateWorkingSet}; 8 + use std::collections::HashSet; 8 9 9 10 pub fn generate_command_suggestions( 10 11 input: &str, ··· 205 206 ); 206 207 207 208 let mut suggestions = Vec::new(); 208 - 209 + 209 210 // If we're at argument index 0, check if the command has subcommands and add them 210 211 if arg_index == 0 { 211 212 let parent_prefix = format!("{} ", command_name); ··· 214 215 } else { 215 216 format!("{}{}", parent_prefix, prefix) 216 217 }; 217 - 218 + 218 219 let subcommands = working_set 219 220 .find_commands_by_predicate(|value| value.starts_with(search_prefix.as_bytes()), true); 220 - 221 + 221 222 if !subcommands.is_empty() { 222 223 // Command has subcommands - add them to suggestions 223 224 console_log!( ··· 229 230 if let Some(subcommand_name) = name_str.strip_prefix(&parent_prefix) { 230 231 suggestions.push(Suggestion { 231 232 rendered: { 232 - let name_colored = ansi_term::Color::Green.bold().paint(subcommand_name); 233 + let name_colored = 234 + ansi_term::Color::Green.bold().paint(subcommand_name); 233 235 let desc_str = desc.as_deref().unwrap_or("<no description>"); 234 236 format!("{name_colored} {desc_str}") 235 237 }, ··· 242 244 } 243 245 } 244 246 } 245 - 247 + 246 248 if let Some(signature) = get_command_signature(engine_guard, &command_name) { 247 249 // First, check if we're completing an argument for a flag 248 250 // Look backwards from the current position to find the previous flag ··· 558 560 559 561 pub fn generate_suggestions( 560 562 input: &str, 561 - contexts: Vec<CompletionContext>, 563 + contexts: HashSet<CompletionContext>, 562 564 working_set: &StateWorkingSet, 563 565 engine_guard: &EngineState, 564 566 stack_guard: &Stack, ··· 567 569 ) -> Vec<Suggestion> { 568 570 console_log!("contexts: {contexts:?}"); 569 571 572 + let mut context_vec: Vec<_> = contexts.into_iter().collect(); 573 + context_vec.sort_by_key(|ctx| match &ctx.kind { 574 + CompletionKind::Command { .. } => 0, 575 + CompletionKind::Flag { .. } => 1, 576 + CompletionKind::Variable => 2, 577 + CompletionKind::CellPath { .. } => 3, 578 + CompletionKind::CommandArgument { .. } => 4, 579 + CompletionKind::Argument => 5, 580 + }); 581 + 570 582 let mut suggestions = Vec::new(); 571 - for context in contexts { 572 - let mut sug = match context { 573 - CompletionContext::Command { 574 - prefix, 575 - span, 576 - parent_command, 577 - } => generate_command_suggestions(input, working_set, prefix, span, parent_command), 578 - CompletionContext::Argument { prefix, span } => { 579 - generate_argument_suggestions(input, prefix, span, root) 583 + for context in context_vec.iter() { 584 + let mut sug = match &context.kind { 585 + CompletionKind::Command { parent_command } => generate_command_suggestions( 586 + input, 587 + working_set, 588 + context.prefix.clone(), 589 + context.span, 590 + parent_command.clone(), 591 + ), 592 + CompletionKind::Argument => { 593 + generate_argument_suggestions(input, context.prefix.clone(), context.span, root) 580 594 } 581 - CompletionContext::Flag { 582 - prefix, 583 - span, 584 - command_name, 585 - } => generate_flag_suggestions(input, engine_guard, prefix, span, command_name), 586 - CompletionContext::CommandArgument { 587 - prefix, 588 - span, 595 + CompletionKind::Flag { command_name } => generate_flag_suggestions( 596 + input, 597 + engine_guard, 598 + context.prefix.clone(), 599 + context.span, 600 + command_name.clone(), 601 + ), 602 + CompletionKind::CommandArgument { 589 603 command_name, 590 604 arg_index, 591 605 } => generate_command_argument_suggestions( 592 606 input, 593 607 engine_guard, 594 608 working_set, 595 - prefix, 596 - span, 597 - command_name, 598 - arg_index, 609 + context.prefix.clone(), 610 + context.span, 611 + command_name.clone(), 612 + *arg_index, 599 613 root, 600 614 ), 601 - CompletionContext::Variable { prefix, span } => { 602 - generate_variable_suggestions(input, working_set, prefix, span, byte_pos) 603 - } 604 - CompletionContext::CellPath { 605 - prefix, 606 - span, 615 + CompletionKind::Variable => generate_variable_suggestions( 616 + input, 617 + working_set, 618 + context.prefix.clone(), 619 + context.span, 620 + byte_pos, 621 + ), 622 + CompletionKind::CellPath { 607 623 var_id, 608 624 path_so_far, 609 625 } => generate_cell_path_suggestions( ··· 611 627 working_set, 612 628 engine_guard, 613 629 stack_guard, 614 - prefix, 615 - span, 616 - var_id, 617 - path_so_far, 630 + context.prefix.clone(), 631 + context.span, 632 + *var_id, 633 + path_so_far.clone(), 618 634 ), 619 635 }; 620 636 suggestions.append(&mut sug);
+44 -18
src/completion/types.rs
··· 27 27 } 28 28 } 29 29 30 - #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] 31 - pub enum CompletionContext { 30 + #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 31 + pub enum CompletionKind { 32 32 Command { 33 - prefix: String, 34 - span: Span, 35 33 parent_command: Option<String>, // If Some, only show subcommands of this command 36 34 }, 37 - Argument { 38 - prefix: String, 39 - span: Span, 40 - }, 35 + Argument, 41 36 Flag { 42 - prefix: String, 43 - span: Span, 44 37 command_name: String, 45 38 }, 46 39 CommandArgument { 47 - prefix: String, 48 - span: Span, 49 40 command_name: String, 50 41 arg_index: usize, 51 42 }, 52 - Variable { 53 - prefix: String, // without the $ prefix 54 - span: Span, 55 - }, 43 + Variable, // prefix is without the $ prefix 56 44 CellPath { 57 - prefix: String, // the partial field name being typed (after the last dot) 58 - span: Span, // replacement span 59 45 var_id: nu_protocol::VarId, // variable ID for evaluation 60 46 path_so_far: Vec<String>, // path members accessed before current one 61 47 }, 62 48 } 49 + 50 + #[derive(Debug)] 51 + pub struct CompletionContext { 52 + pub kind: CompletionKind, 53 + pub prefix: String, // the partial text being completed 54 + pub span: Span, 55 + } 56 + 57 + impl PartialEq for CompletionContext { 58 + fn eq(&self, other: &Self) -> bool { 59 + self.kind == other.kind && self.prefix == other.prefix 60 + } 61 + } 62 + 63 + impl Eq for CompletionContext {} 64 + 65 + impl PartialOrd for CompletionContext { 66 + fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { 67 + match self.kind.partial_cmp(&other.kind) { 68 + Some(std::cmp::Ordering::Equal) => self.prefix.partial_cmp(&other.prefix), 69 + other => other, 70 + } 71 + } 72 + } 73 + 74 + impl Ord for CompletionContext { 75 + fn cmp(&self, other: &Self) -> std::cmp::Ordering { 76 + match self.kind.cmp(&other.kind) { 77 + std::cmp::Ordering::Equal => self.prefix.cmp(&other.prefix), 78 + other => other, 79 + } 80 + } 81 + } 82 + 83 + impl std::hash::Hash for CompletionContext { 84 + fn hash<H: std::hash::Hasher>(&self, state: &mut H) { 85 + self.kind.hash(state); 86 + self.prefix.hash(state); 87 + } 88 + }