タイトルは少し端折っていて、正確には ~/.zshrc に以下の設定が必要です。
# $FPATH 以下にある補完コレクションを使う。
autoload -Uz compinit; compinit -u
これは Heroku CLI 固有の設定ではありません。ls や git などにも適用
される補完を有効にする設定です。
macOS High Sierra 付属の zsh の $FPATH デフォルト値です。
$ echo $FPATH | tr ':' '\n'
/usr/local/share/zsh/site-functions
/usr/share/zsh/site-functions
/usr/share/zsh/5.3/functions
このように補完が効きます。App の補完はうれしい。
ここに至った経緯 1/2
Heroku CLI は $ brew install heroku でインストールしており、
/usr/local/share/zsh/site-functions/_heroku があります。
そのため、初めはこんな設定をしていました。
FPATH=/usr/local/share/zsh/site-functions:$FPATH
でも前述したように /usr/local/share/zsh/site-functions は $FPATH
のデフォルト値に含まれているので不要でした。削除。
ここに至った経緯 2/2
別件で $ brew install heroku は obsolete で、
現在は $ brew install heroku/brew/heroku だと知りました。
$ heroku releases --app aqueous-reaches-70470
Warning: Unsupported install. Install heroku with `brew install heroku/brew/heroku`
=== aqueous-reaches-70470 Releases - Current: v3
v3 Deploy masutaka@example.com 2018/10/27 12:01:49 +0900 (~ 1m ago)
v2 Enable Logplex masutaka@example.com 2018/10/27 11:49:44 +0900 (~ 13m ago)
v1 Initial release masutaka@example.com 2018/10/27 11:49:43 +0900 (~ 13m ago)
Heroku CLI をインストールし直したら、補完設定が表示されました。
$ brew uninstall heroku --force
$ brew install heroku/brew/heroku
(snip)
==> heroku
To use the Heroku CLI's autocomplete --
Via homebrew's shell completion:
1) Follow homebrew's install instructions https://docs.brew.sh/Shell-Completion
NOTE: For zsh, as the instructions mention, be sure compinit is autoloaded
and called, either explicitly or via a framework like oh-my-zsh.
2) Then run
$ heroku autocomplete --refresh-cache
OR
Use our standalone setup:
1) Run and follow the install steps:
$ heroku autocomplete
Bash completion has been installed to:
/usr/local/etc/bash_completion.d
zsh completions have been installed to:
/usr/local/share/zsh/site-functions
OR の前に書かれていることは、$FPATH を設定して
$ heroku autocomplete –refresh-cache しろとのこと。
~/.zcompdump と ~/Library/Caches/heroku 以下が更新されたようです。
~/Library/Caches/heroku 以下には App 名のキャッシュも含まれている
けど、このコマンドを実行しないと更新されないのかな。うーん。
OR の後に書かれていることもやってみました。
$ heroku autocomplete
Building the autocomplete cache... done
Setup Instructions for HEROKU CLI Autocomplete ---
1) Add the autocomplete env var to your zsh profile and source it
$ printf "$(heroku autocomplete:script zsh)" >> ~/.zshrc; source ~/.zshrc
NOTE: After sourcing, you can run `$ compaudit -D` to ensure no permissions conflicts are present
2) Test it out, e.g.:
$ heroku <TAB> # Command completion
$ heroku apps:info --<TAB> # Flag completion
$ heroku apps:info --app=<TAB> # Flag option completion
Visit the autocomplete Dev Center doc at https://devcenter.heroku.com/articles/heroku-cli-autocomplete
Enjoy!
printf “$(heroku autocomplete:script zsh)” » ~/.zshrc したら、
~/.zshrc に以下が書き込まれました。
# heroku autocomplete setup
HEROKU_AC_ZSH_SETUP_PATH=/Users/masutaka/Library/Caches/heroku/autocomplete/zsh_setup && test -f $HEROKU_AC_ZSH_SETUP_PATH && source $HEROKU_AC_ZSH_SETUP_PATH;
先ほどの補完とほぼ同じで、違いは ‘…’ が表示されることくらいです。
面倒ですが、以下について調べてみました。
(1) /Users/masutaka/Library/Caches/heroku/autocomplete/zsh_setup の仕組み
$ heroku autocomplete がこのファイルを使うように誘導する。
(2) /usr/local/share/zsh/site-functions/_heroku の仕組み
$ brew install heroku/brew/heroku によって作られる。
(1) /Users/masutaka/Library/Caches/heroku/autocomplete/zsh_setup の仕組み
TAB キーに関数を割り当てつつ、シェル変数の設定をしています。
autoload -Uz compinit; compinit -u もやってくれます。
# /Users/masutaka/Library/Caches/heroku/autocomplete/zsh_setup | |
expand-or-complete-with-dots() { | |
echo -n "..." | |
zle expand-or-complete | |
zle redisplay | |
} | |
zle -N expand-or-complete-with-dots | |
bindkey "^I" expand-or-complete-with-dots | |
HEROKU_AC_ANALYTICS_DIR=/Users/masutaka/Library/Caches/heroku/autocomplete/completion_analytics; | |
HEROKU_AC_COMMANDS_PATH=/Users/masutaka/Library/Caches/heroku/autocomplete/commands; | |
HEROKU_AC_ZSH_SETTERS_PATH=${HEROKU_AC_COMMANDS_PATH}_setters && test -f $HEROKU_AC_ZSH_SETTERS_PATH && source $HEROKU_AC_ZSH_SETTERS_PATH; | |
fpath=( | |
/usr/local/Cellar/heroku/7.18.3/libexec/node_modules/@heroku-cli/plugin-autocomplete/autocomplete/zsh | |
$fpath | |
); | |
autoload -Uz compinit; | |
compinit; |
/usr/local/Cellar/heroku/7.18.3/libexec/node_modules/@heroku-cli/plugin-autocomplete/autocomplete/zsh は
ディレクトリで、_heroku というファイルがあります。
関数 _heroku を定義して実行するだけのようです。
# /usr/local/Cellar/heroku/7.18.3/libexec/node_modules/@heroku-cli/plugin-autocomplete/autocomplete/zsh/_heroku | |
#compdef heroku | |
_heroku () { | |
# exit if vars are not set | |
: "${HEROKU_AC_ANALYTICS_DIR?}" | |
: "${HEROKU_AC_COMMANDS_PATH?}" | |
local -a _flags=() | |
local _command_id=${words[2]} | |
local _cur=${words[CURRENT]} | |
mkdir -p "$HEROKU_AC_ANALYTICS_DIR" | |
## all commands | |
_complete_commands () { | |
touch "$HEROKU_AC_ANALYTICS_DIR"/command | |
local -a _all_commands_list | |
if type _set_all_commands_list >/dev/null 2>&1; then | |
_set_all_commands_list | |
_describe -t all-commands "all commands" _all_commands_list | |
return | |
fi | |
# fallback to grep'ing cmds from cache | |
compadd $(grep -oe '^[a-zA-Z0-9:_-]\+' $HEROKU_AC_COMMANDS_PATH) | |
} | |
## end all commands | |
_compadd_args () { | |
compadd $(echo $([[ -n $REPORTTIME ]] && REPORTTIME=100; heroku autocomplete:options "${words}")) | |
} | |
_compadd_flag_options () { | |
touch "$HEROKU_AC_ANALYTICS_DIR"/value | |
_compadd_args | |
} | |
if [ $CURRENT -gt 2 ]; then | |
if [[ "$_cur" == -* ]]; then | |
touch "$HEROKU_AC_ANALYTICS_DIR"/flag | |
local _flag_completion_func="_set_${_command_id//:/_}_flags" | |
declare -f $_flag_completion_func >/dev/null && $_flag_completion_func | |
else | |
if type _compadd_args >/dev/null 2>&1; then | |
_compadd_args | |
fi | |
fi | |
fi | |
_arguments '1: :_complete_commands' \ | |
$_flags | |
} | |
_heroku |
(2) /usr/local/share/zsh/site-functions/_heroku の仕組み
シェル変数を設定し、関数 _heroku を定義して実行しています。
# /usr/local/share/zsh/site-functions/_heroku | |
#compdef heroku | |
### Keep in sync with zsh shim | |
HEROKU_AC_ANALYTICS_DIR=$HOME/Library/Caches/heroku/autocomplete/completion_analytics; | |
HEROKU_AC_COMMANDS_PATH=$HOME/Library/Caches/heroku/autocomplete/commands; | |
HEROKU_AC_ZSH_SETTERS_PATH=${HEROKU_AC_COMMANDS_PATH}_setters && test -f $HEROKU_AC_ZSH_SETTERS_PATH && source $HEROKU_AC_ZSH_SETTERS_PATH; | |
### Keep in sync with autocomplete/zsh/_heroku | |
_heroku () { | |
# exit if vars are not set | |
: "${HEROKU_AC_ANALYTICS_DIR?}" | |
: "${HEROKU_AC_COMMANDS_PATH?}" | |
local -a _flags=() | |
local _command_id=${words[2]} | |
local _cur=${words[CURRENT]} | |
mkdir -p "$HEROKU_AC_ANALYTICS_DIR" | |
## all commands | |
_complete_commands () { | |
touch "$HEROKU_AC_ANALYTICS_DIR"/command | |
local -a _all_commands_list | |
if type _set_all_commands_list >/dev/null 2>&1; then | |
_set_all_commands_list | |
_describe -t all-commands "all commands" _all_commands_list | |
return | |
fi | |
# fallback to grep'ing cmds from cache | |
compadd $(grep -oe '^[a-zA-Z0-9:_-]\+' $HEROKU_AC_COMMANDS_PATH) | |
} | |
## end all commands | |
_compadd_args () { | |
compadd $(echo $([[ -n $REPORTTIME ]] && REPORTTIME=100; heroku autocomplete:options "${words}")) | |
} | |
_compadd_flag_options () { | |
touch "$HEROKU_AC_ANALYTICS_DIR"/value | |
_compadd_args | |
} | |
if [ $CURRENT -gt 2 ]; then | |
if [[ "$_cur" == -* ]]; then | |
touch "$HEROKU_AC_ANALYTICS_DIR"/flag | |
local _flag_completion_func="_set_${_command_id//:/_}_flags" | |
declare -f $_flag_completion_func >/dev/null && $_flag_completion_func | |
else | |
if type _compadd_args >/dev/null 2>&1; then | |
_compadd_args | |
fi | |
fi | |
fi | |
_arguments '1: :_complete_commands' \ | |
$_flags | |
} | |
_heroku |
(1) と (2) の違い
ほぼ同じでした。(1) は TAB キーに関数 expand-or-complete-with-dots
を割り当てる点だけが違います。この関数は補完時に ‘…’ を表示するだけです。
測定はしていませんが、(1) は autoload -Uz compinit; compinit; も
実行するため、(2) より若干 zsh の起動が遅そうです。
zsh の起動はチリツモで遅くなるため、(1) を使う必要性は少なさそうです。
おまけ
参考までに、私の ~/.zshrc を貼っておきます。
https://github.com/masutaka/dotfiles-public/blob/master/.zshrc