This isn't perfect, but then again bash completion is quite a tricky thing...
The very simplest way is on a per-command basis, it's slightly more flexible than FIGNORE
, you can do:
complete -f -X "/myproject/data/*" vi
This instructs autocomplete that completion for vi
is for files, and to remove patterns matching the -X
filter. The downside is that the pattern isn't normalised, so ../data
and variations won't match.
The next best thing might be a custom PROMPT_COMMAND
function:
# associative arrays of non-autocomplete directories
declare -A noacdirs=([/myproject/data]=1 )
function _myprompt {
[[ -n "${noacdirs[$PWD]}" ]] && {
echo autocomplete off
bind 'set disable-completion on'
} || {
echo autocomplete on
bind 'set disable-completion off'
}
}
PROMPT_COMMAND=_myprompt
This disables completion (completely) when you are in the directory, but it disables it for every path not just files in that directory.
It would be more generally useful to selectively disable this for defined paths, but I believe the only way is to use a default completion function (bash-4.1 and later with complete -D
) and a lot of messing about.
This should work for you, but it may have unintended side effects (i.e. changes to the expected completion in some cases):
declare -A noacdirs=([/myproject/data]=1 )
_xcomplete() {
local cur=${COMP_WORDS[COMP_CWORD]} # the current token
name=$(readlink -f "${cur:-./}") # poor man's path canonify
dirname=$(dirname "$name/.")
[[ -n "${noacdirs[$dirname]}" ]] && {
COMPREPLY=( "" ) # dummy to prevent completion
return
}
# let default kick in
COMPREPLY=()
}
complete -o bashdefault -o default -F _xcomplete vi
This works for completion of vi
, other commands can be added as needed. It should stop completion for files in the named directories regardless of path or working directory.
I believe the general approach with complete -D
is to dynamically add completion functions for each command as it is encountered. One might also need to add complete -E
(completion of command name when input buffer is empty).
Update
Here's a hybrid version of the PROMPT_COMMAND
and completion function solutions, it's a little easier to understand and hack I think:
declare -A noacdirs=([/myproject/data]=1 [/project2/bigdata]=1)
_xcomplete() {
local cmd=${COMP_WORDS[0]}
local cur=${COMP_WORDS[COMP_CWORD]} # the current token
[[ -z "$cur" && -n "$nocomplete" ]] && {
printf "\n(restricted completion for $cmd in $nocomplete)\n"
printf "$PS2 $COMP_LINE"
COMPREPLY=( "" ) # dummy to prevent completion
return
}
COMPREPLY=() # let default kick in
}
function _myprompt {
nocomplete=
# uncomment next line for hard-coded list of directories
[[ -n "${noacdirs[$PWD]}" ]] && nocomplete=$PWD
# uncomment next line for per-directory ".noautocomplete"
# [[ -f ./.noautocomplete ]] && nocomplete=$PWD
# uncomment next line for size-based guessing of large directories
# [[ $(stat -c %s .) -gt 512*1024 ]] && nocomplete=$PWD
}
PROMPT_COMMAND=_myprompt
complete -o bashdefault -o default -F _xcomplete vi cp scp diff
This prompt function sets the nocomplete
variable when you enter one of the configured directories. The modified completion behaviour only kicks in when that variable is non-blank and only when you try completing from an empty string, thus allowing completion of partial names (remove the -z "$cur"
condition to prevent completion altogether). Comment out the two printf
lines for silent operation.
Other options include a per-directory .noautocomplete
flag file that you can touch
in a directory as needed; and guessing of directory size using GNU stat
. You can use any or all of those three options.
(The stat
method is only a guess, the reported directory size grows with its contents, it's a "high water mark" that won't usually shrink when files are deleted without some administrative intervention. It's cheaper than determining the real contents of a potentially large directory. Precise behaviour and increment per file depends on underlying filesystem. I find it a reliable indicator on linux ext2/3/4 systems at least.)
bash adds an extra space even when an empty completion is returned (this only occurs when completing at the end of a line). You can add -o nospace
to the complete
command to prevent this.
One remaining niggle is that if you back up the cursor to the start of a token and hit tab, the default completion will kick in again. Consider it a feature ;-)
(Or you could futz around with ${COMP_LINE:$COMP_POINT-1:1}
if you like over-engineering, but I find bash itself fails to set the completion variables reliably when you back up and attempt completion in the middle of a command.)
Best Answer
Start the command in the background and poll its elapsed CPU time every minute: