← All docs

How do I set up tab completion for VM names?

Two options

  • dynamic completion that queries your VM list on each tab press
  • static SSH config approach

Dynamic completion never goes out of date, but has a lag. Works best with zsh.

Static completion is more general purpose, but requires updating when your VM list changes.

Dynamic completion

The trick is to query ssh exe.dev ls --json on each tab press. Requires jq.

Zsh

Add to ~/.zshrc:

_exe_hosts() {
    reply=(${(f)"$(ssh exe.dev ls --json 2>/dev/null | jq -r '.vms[].ssh_dest')"})
}
zstyle -e ':completion:*:(ssh|scp|rsync):*' hosts '_exe_hosts'

The zstyle approach only overrides the hosts list. Flag and path completion still work normally.

Bash

See the caveat below before using!

Add to ~/.bashrc:

_exe_hosts() {
    local cur="${COMP_WORDS[COMP_CWORD]}"
    local hosts
    hosts=$(ssh exe.dev ls --json 2>/dev/null | jq -r '.vms[].ssh_dest')
    COMPREPLY=($(compgen -W "$hosts" -- "$cur"))
}
complete -F _exe_hosts -o default ssh scp rsync

Caveat: complete -F replaces the default completion function for these commands, so you lose flag completion (ssh -<TAB>). If that hurts, consider using the static SSH config approach instead.

Fish

Add to ~/.config/fish/config.fish:

complete -c ssh -fa '(ssh exe.dev ls --json 2>/dev/null | jq -r ".vms[].ssh_dest")'
complete -c scp -fa '(ssh exe.dev ls --json 2>/dev/null | jq -r ".vms[].ssh_dest")'
complete -c rsync -fa '(ssh exe.dev ls --json 2>/dev/null | jq -r ".vms[].ssh_dest")'

SSH config approach (any shell)

Add your VM names to ~/.ssh/config, so shells pick them up automatically.

One time, add to ~/.ssh/config:

Include ~/.ssh/exe-hosts

Every time you create, delete, or rename a VM, regenerate the config:

ssh exe.dev ls --json | jq -r '.vms[].ssh_dest' | sed 's/^/Host /' > ~/.ssh/exe-hosts