diff --git a/plugins/ssh/README.md b/plugins/ssh/README.md index 3dd32ec76..bbe3e6c65 100644 --- a/plugins/ssh/README.md +++ b/plugins/ssh/README.md @@ -1,7 +1,8 @@ # ssh plugin -This plugin provides host completion based off of your `~/.ssh/config` file, and adds -some utility functions to work with SSH keys. +This plugin provides host completion based off of your `~/.ssh/config` file, +and adds some utility functions to work with SSH keys. If the `~/.ssh/config` +contains `Include` directives, the plugin also parse hosts in related files. To use it, add `ssh` to the plugins array in your zshrc file: diff --git a/plugins/ssh/ssh.plugin.zsh b/plugins/ssh/ssh.plugin.zsh index b5b050536..3b1b28421 100644 --- a/plugins/ssh/ssh.plugin.zsh +++ b/plugins/ssh/ssh.plugin.zsh @@ -2,20 +2,49 @@ # Take all host sections in .ssh/config and offer them for # completion as hosts (e.g. for ssh, rsync, scp and the like) # Filter out wildcard host sections. -_ssh_configfile="$HOME/.ssh/config" -if [[ -f "$_ssh_configfile" ]]; then - _ssh_hosts=($( - egrep '^Host.*' "$_ssh_configfile" |\ - awk '{for (i=2; i<=NF; i++) print $i}' |\ - sort |\ - uniq |\ - grep -v '^*' |\ - sed -e 's/\.*\*$//' - )) - zstyle ':completion:*:hosts' hosts $_ssh_hosts - unset _ssh_hosts -fi -unset _ssh_configfile +# If the .ssh/config has Include directives, load them too. +function _load_ssh_hosts { + local conf="$1" + if [[ -f "$conf" ]]; then + local _ssh_hosts=($( + egrep '^Host\ .*' "$conf" |\ + awk '{for (i=2; i<=NF; i++) print $i}' |\ + sort |\ + uniq |\ + grep -v '^*' |\ + sed -e 's/\.*\*$//' + )) + echo "${_ssh_hosts[@]}" + fi +} + +# XXX: We could make it recursive but won't implement for now +function _find_include_files { + local conf="$1" + if [[ -f "$conf" ]]; then + egrep '^Include\ .*' "$conf" |\ + awk '{for (i=2; i<=NF; i++) print $i}' + fi +} + +all_hosts=($(_load_ssh_hosts "$HOME/.ssh/config")) + +_find_include_files "$HOME/.ssh/config" | while read include_file; do + # omz doesn't know "~" directory + if [[ "$include_file" == ~* ]]; then + include_file="${HOME}${include_file:1}" + fi + if [[ -f "$include_file" ]]; then + hosts=($(_load_ssh_hosts "$include_file")) + all_hosts+=("${hosts[@]}") + fi +done + +zstyle ':completion:*:hosts' hosts "${all_hosts[@]}" + +unset -f _load_ssh_hosts +unset -f _find_include_files +unset all_hosts ############################################################ # Remove host key from known hosts based on a host section