aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bash/bash_completion.d/_ssh_config_hosts.bash62
1 files changed, 44 insertions, 18 deletions
diff --git a/bash/bash_completion.d/_ssh_config_hosts.bash b/bash/bash_completion.d/_ssh_config_hosts.bash
index 8f45c412..c26457cf 100644
--- a/bash/bash_completion.d/_ssh_config_hosts.bash
+++ b/bash/bash_completion.d/_ssh_config_hosts.bash
@@ -1,22 +1,48 @@
# Complete ssh_config(5) hostnames
_ssh_config_hosts() {
- # Read hostnames from existent config files, no asterisks
- local -a hosts
- local config option value
- for config in "$HOME"/.ssh/config /etc/ssh/ssh_config ; do
- [[ -e $config ]] || continue
- while read -r option value _ ; do
- [[ $option == Host ]] || continue
- [[ $value != *'*'* ]] || continue
- hosts[${#hosts[@]}]=$value
- done < "$config"
- done
-
- # Generate completion reply
- local host
- for host in "${hosts[@]}" ; do
- [[ $host == "${COMP_WORDS[COMP_CWORD]}"* ]] || continue
- COMPREPLY[${#COMPREPLY[@]}]=$host
- done
+ # Don't complete anything that wouldn't be in a valid hostname
+ case ${COMP_WORDS[COMP_CWORD]} in
+ *[!a-zA-Z0-9.-]*) return 1 ;;
+ esac
+
+ # Iterate through words from a subshell
+ while read -r word ; do
+ [[ -n $word ]] || continue
+ COMPREPLY[${#COMPREPLY[@]}]=$word
+ done < <(
+
+ # Check bind settings to see if we should match case insensitively
+ while read -r _ setting ; do
+ case $setting in
+ ('completion-ignore-case on')
+ shopt -qs nocasematch 2>/dev/null
+ break
+ ;;
+ esac
+ done < <(bind -v)
+
+ # Iterate through SSH client config paths
+ for config in "$HOME"/.ssh/config /etc/ssh/ssh_config ; do
+ [[ -e $config ]] || continue
+
+ # Read Host options and their first value from file
+ while read -r option value _ ; do
+ [[ $option == Host ]] || continue
+
+ # Check host value
+ case $value in
+
+ # Don't complete with wildcard characters
+ (*'*'*) ;;
+
+ # Found a match; print it
+ ("${COMP_WORDS[COMP_CWORD]}"*)
+ printf '%s\n' "$value"
+ ;;
+ esac
+
+ done < "$config"
+ done
+ )
}