はじめに

ZshのOh My Zshのプラグインのひとつにglobaliasというものがあります。

https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/globalias

これはZshで設定したエイリアスを半自動で元のコマンドに展開してくれるものです。

画像元:
画像元: Pat's Blog

主な用途としては、他人にコマンドを共有する場合に自前でエイリアス展開をしなくてよくなるので便利です。 便利なのですが、展開してくれるエイリアスは当然Zshのものだけで、Gitのエイリアスは展開してくれません。個人的にGitのエイリアスも同じように展開してほしかったのでオリジナルのglobaliasを元に書きました。

コード

function globalias() {
    local args=(${(Az)LBUFFER})
    local cmd=$args[1]
    case "$cmd" in
        git)
            cmd="$(git config --get "alias.$args[2]" 2>/dev/null)"
            if [[ "$cmd[1]" = "!" ]]; then
                cmd=(${(Aps: :)"${cmd:1}"})
                args[1]=${cmd[1]}
                args[2]=${cmd:1}
                LBUFFER="$args"
            elif [[ -n "$cmd" ]]; then
                args[2]="$cmd"
                LBUFFER="$args"
            fi
            ;;
        *)
            ;;
    esac
    local word=$args[-1]
    zstyle -a ':globalias:var' filters filters
    [[ -n "$filters" ]] || filters=()
    if [[ $filters[(Ie)$word] -ne 0 ]]; then
        zle _expand_alias
        zle expand-word
    fi
    if [[ "$KEYS" = ' ' ]]; then
        zle self-insert
    else
        zle accept-line
    fi
}
zle -N globalias

bindkey -M emacs " " globalias
bindkey -M viins " " globalias

bindkey -M emacs "^M" globalias
bindkey -M viins "^M" globalias

オリジナルのgloabaliasとの主な変更点は下記です。

  • Gitのエイリアスを展開できるようにした
  • 環境変数ではなく :globalias:var で対象を設定するようにした
  • :globalias:var で設定した対象は展開するものを設定するようにした
  • エイリアスの展開をコマンド実行時(正確には^Mを押下した時)にも行うようにした

ちょっと解説

Gitのエイリアスを展開できるようにした

下記の部分で行っています。

local args=(${(Az)LBUFFER})
local cmd=$args[1]
case "$cmd" in
    git)
        cmd="$(git config --get "alias.$args[2]" 2>/dev/null)"
        if [[ "$cmd[1]" = "!" ]]; then
            cmd=(${(Aps: :)"${cmd:1}"})
            args[1]=${cmd[1]}
            args[2]=${cmd:1}
            LBUFFER="$args"
        elif [[ -n "$cmd" ]]; then
            args[2]="$cmd"
            LBUFFER="$args"
        fi
        ;;
    *)
        ;;
esac

正確には展開ではなく置換しています。Gitのエイリアスには ! で始まるシェルスクリプトが書けるものと、Gitコマンドのみが書ける2種類がありますが、両方対応しています。

まず git で始まる場合に下記でエイリアスを取得します。

cmd="$(git config --get "alias.$args[2]" 2>/dev/null)"

取得したエイリアスが ! から始まる場合はシェルスクリプトなので、エイリアスとそれより前に入力されたコマンドをまるごと置き換えます。

cmd=(${(Aps: :)"${cmd:1}"}) # スペース区切りで分割して配列にする
args[1]=${cmd[1]} # コマンドを置き換える
args[2]=${cmd:1} # 後続の引数を置き換える
LBUFFER="$args"

例えば

g = !zsh -c 'git grep -P \"$@\" | fzf' -

というエイリアスがある場合は git g

% !zsh -c 'git grep -P \"$@\" | fzf' -

に展開されます。

取得したエイリアスが ! で始まるもの以外の場合はGitコマンドなので、そのエイリアスだけを置き換えます。

args[2]="$cmd"
LBUFFER="$args"

例えば

g = grep -P

というエイリアスがある場合は git g

% git grep -P

に展開されます。

該当するエイリアスがない場合は展開しません。

環境変数ではなく :globalias:var で対象を設定するようにした

下記の部分です。

zstyle -a ':globalias:var' filters filters
[[ -n "$filters" ]] || filters=()

オリジナルは GLOBALIAS_FILTER_VALUES という環境変数で行うようになってますが、オシャレにzstyleを使うようにしました。オシャレ以外の理由は特にありません。

設定は

zstyle ':globalias:var' filters (ls df du)

のように、展開するエイリアスを設定します。自分は

function ealias() {
    alias $@
    local args="$@"
    args=${args%%\=*}
    zstyle -a ':globalias:var' filters filters
    filters+=(${args##* })
    zstyle ':globalias:var' filters $filters
}

という関数を用意して、展開したいエイリアスを

ealias gp="git pull"

と定義しています。

:globalias:var で設定した対象は展開するものを設定するようにした

下記の部分です。

if [[ $filters[(Ie)$word] -ne 0 ]]; then

-eq-ne に変えただけです。オリジナルのglobaliasは指定したものを展開 しない 設定でしたが、逆に、設定したものを展開するように変えています。

エイリアスの展開をコマンド実行時(正確には^Mを押下した時)にも行うようにした

下記と

if [[ "$KEYS" = ' ' ]]; then
    zle self-insert
else
    zle accept-line
fi

さらに下記の部分です。

bindkey -M emacs "^M" globalias
bindkey -M viins "^M" globalias

これは、

git st

のような、追加で引数やオプションを指定しないエイリアスコマンドの場合に、スペースを押下しなくても展開できるようにしています。

以上、ちょっと解説でした。