diff --git a/CHANGELOG.rst b/CHANGELOG.rst index bc49e2b1b..2d55f0057 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -157,6 +157,7 @@ Interactive improvements - Measuring a command with ``time`` now considers the time taken for command substitution (:issue:`9100`). - ``fish_add_path`` now automatically enables verbose mode when used interactively (in the commandline), in an effort to be clearer about what it does (:issue:`10532`). - fish no longer adopts TTY modes of failed commands (:issue:`10603`). +- `complete -e cmd` now prevents autoloading completions for `cmd` (:issue:`6716`). New or improved bindings ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/complete.rs b/src/complete.rs index 5a366bf5b..26bf5467b 100644 --- a/src/complete.rs +++ b/src/complete.rs @@ -1,6 +1,6 @@ use std::{ cmp::Ordering, - collections::{BTreeMap, HashMap, HashSet}, + collections::{BTreeMap, BTreeSet, HashMap, HashSet}, mem, sync::{ atomic::{self, AtomicUsize}, @@ -452,6 +452,7 @@ struct CompletionEntryIndex { } type CompletionEntryMap = BTreeMap; static COMPLETION_MAP: Mutex = Mutex::new(BTreeMap::new()); +static COMPLETION_TOMBSTONES: Mutex> = Mutex::new(BTreeSet::new()); /// Completion "wrapper" support. The map goes from wrapping-command to wrapped-command-list. type WrapperMap = HashMap>; @@ -2340,10 +2341,14 @@ pub fn complete_remove(cmd: WString, cmd_is_path: bool, option: &wstr, typ: Comp /// Removes all completions for a given command. pub fn complete_remove_all(cmd: WString, cmd_is_path: bool) { let mut completion_map = COMPLETION_MAP.lock().expect("mutex poisoned"); - completion_map.remove(&CompletionEntryIndex { + let idx = CompletionEntryIndex { name: cmd, is_path: cmd_is_path, - }); + }; + let removed = completion_map.remove(&idx).is_some(); + if !removed && !idx.is_path { + COMPLETION_TOMBSTONES.lock().unwrap().insert(idx.name); + } } /// Returns all completions of the command cmd. @@ -2433,6 +2438,10 @@ fn completion2string(index: &CompletionEntryIndex, o: &CompleteEntryOpt) -> WStr /// Load command-specific completions for the specified command. /// Returns `true` if something new was loaded, `false` if not. pub fn complete_load(cmd: &wstr, parser: &Parser) -> bool { + if COMPLETION_TOMBSTONES.lock().unwrap().contains(cmd) { + return false; + } + let mut loaded_new = false; // We have to load this as a function, since it may define a --wraps or signature. diff --git a/tests/checks/completion-autoload-tombstone.fish b/tests/checks/completion-autoload-tombstone.fish new file mode 100644 index 000000000..32ff47daa --- /dev/null +++ b/tests/checks/completion-autoload-tombstone.fish @@ -0,0 +1,6 @@ +#RUN: %fish %s + +complete -e cat + +complete -C"cat -" | wc -l +# CHECK: 0