Skip to content

Commit 4b2aba3

Browse files
g0t4krobelus
authored andcommitted
complete: tab-complete anywhere-position abbrs in non-command position
Make abbreviations with `--position anywhere` appear in the completion menu when tabbing in argument position (e.g. `cat foo.log pg<TAB>` shows pgr, pgrv, pjq, etc.), not just in command position. Lift "do_file" into an enum, so we don't have to check "is_redirection" twice, and can express more accurately the reason for not completing abbreviations after redirection. Co-authored-by: Johannes Altmanninger <[email protected]> Closes #12764
1 parent c10e782 commit 4b2aba3

3 files changed

Lines changed: 46 additions & 11 deletions

File tree

CHANGELOG.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Interactive improvements
1212
- ``fish_hg_prompt``, ``fish_git_prompt`` and ``fish_fossil_prompt`` now strip control characters from VCS state read off disk, matching ``prompt_pwd``.
1313
- The sample informative and minimalist prompts now use ``prompt_pwd`` instead of printing ``$PWD`` directly.
1414
- ``bind`` shows the file where bindings were defined (:issue:`12504`).
15+
- Abbreviations with ``--position=anywhere`` can now be completed in argument position, not just in command position (:issue:`12630`).
1516

1617
For distributors and developers
1718
-------------------------------

src/complete.rs

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::{
2-
abbrs::with_abbrs,
2+
abbrs::{Position, with_abbrs},
33
ast::unescape_keyword,
44
autoload::{Autoload, AutoloadResult},
55
builtins::shared::{builtin_exists, builtin_get_desc, builtin_get_names},
@@ -689,7 +689,7 @@ impl<'ctx, 'parser> Completer<'ctx, 'parser> {
689689
return;
690690
}
691691
self.complete_cmd(WString::new());
692-
self.complete_abbr(L!(""));
692+
self.complete_abbr(L!(""), true);
693693
return;
694694
};
695695

@@ -744,7 +744,7 @@ impl<'ctx, 'parser> Completer<'ctx, 'parser> {
744744
return;
745745
}
746746
// Complete command filename.
747-
self.complete_abbr(current_token);
747+
self.complete_abbr(current_token, true);
748748
self.complete_cmd(current_token.to_owned());
749749
return;
750750
}
@@ -784,10 +784,17 @@ impl<'ctx, 'parser> Completer<'ctx, 'parser> {
784784
}
785785
}
786786

787-
let mut do_file = false;
787+
#[derive(Eq, PartialEq)]
788+
enum DoFile {
789+
No,
790+
Yes,
791+
Only,
792+
}
793+
794+
let mut do_file = DoFile::No;
788795
let mut handle_as_special_cd = false;
789796
if in_redirection {
790-
do_file = true;
797+
do_file = DoFile::Only;
791798
} else {
792799
// Try completing as an argument.
793800
let mut arg_data = CustomArgData::new(&mut var_assignments);
@@ -817,11 +824,15 @@ impl<'ctx, 'parser> Completer<'ctx, 'parser> {
817824
command_range,
818825
&mut arg_data,
819826
);
820-
do_file = arg_data.do_file;
827+
do_file = if arg_data.do_file {
828+
DoFile::Yes
829+
} else {
830+
DoFile::No
831+
};
821832

822833
// If we're autosuggesting, and the token is empty, don't do file suggestions.
823834
if is_autosuggest && arg_data.current_argument.is_empty() {
824-
do_file = false;
835+
do_file = DoFile::No;
825836
}
826837
}
827838

@@ -833,10 +844,14 @@ impl<'ctx, 'parser> Completer<'ctx, 'parser> {
833844
// Maybe apply variable assignments.
834845
let block = self.apply_var_assignments(&var_assignments);
835846
if !self.ctx.check_cancel() {
847+
if do_file != DoFile::Only {
848+
self.complete_abbr(current_argument, false);
849+
}
850+
836851
// This function wants the unescaped string.
837852
self.complete_param_expand(
838853
current_argument,
839-
do_file,
854+
do_file != DoFile::No,
840855
handle_as_special_cd,
841856
cur_tok.is_unterminated_brace,
842857
);
@@ -1144,15 +1159,18 @@ impl<'ctx, 'parser> Completer<'ctx, 'parser> {
11441159
}
11451160
}
11461161

1147-
/// Attempt to complete an abbreviation for the given string.
1148-
fn complete_abbr(&mut self, cmd: &wstr) {
1162+
/// Attempt to complete a non-regex abbreviation for the given string.
1163+
fn complete_abbr(&mut self, cmd: &wstr, is_command_position: bool) {
11491164
// Copy the list of names and descriptions so as not to hold the lock across the call to
11501165
// complete_strings.
11511166
let mut possible_comp = Vec::new();
11521167
let mut descs = HashMap::new();
11531168
with_abbrs(|set| {
11541169
for abbr in set.list() {
1155-
if !abbr.is_regex() {
1170+
if abbr.is_regex() {
1171+
continue;
1172+
}
1173+
if abbr.position == Position::Anywhere || is_command_position {
11561174
possible_comp.push(Completion::from_completion(abbr.key.clone()));
11571175
descs.insert(abbr.key.clone(), abbr.replacement.clone());
11581176
}

tests/checks/complete.fish

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,22 @@ abbr cat cat
645645
complete -C ca | string match -r '^cat(?:\t.*)?$'
646646
# CHECK: cat{{\t}}Abbreviation: cat
647647

648+
# anywhere-position abbrs complete in non-command position
649+
abbr --position anywhere __test_pgr '| grep -i'
650+
complete -C'echo __test_pgr' | string match -r '^__test_pgr.*'
651+
# CHECK: __test_pgr{{\t}}Abbreviation: | grep -i
652+
653+
# anywhere-position abbrs still complete in command position (regression guard)
654+
complete -C__test_pgr | string match -r '^__test_pgr.*'
655+
# CHECK: __test_pgr{{\t}}Abbreviation: | grep -i
656+
657+
# command-position-only abbrs do NOT complete in non-command position
658+
abbr --position command __test_cmd_only 'git status'
659+
complete -C'echo __test_cmd' | string match -rq '^__test_cmd'
660+
echo $status
661+
# CHECK: 1
662+
abbr --erase __test_pgr __test_cmd_only
663+
648664
complete complete-list -xa '(__fish_complete_list , "seq 2")'
649665
complete -C "complete-list 1,"
650666
# CHECK: 1,1

0 commit comments

Comments
 (0)