親ディレクトリへ「cd ..」をShift + Upでキーバインド

Finder(Mac OS)なら「Cmd + Up」、Explorer(Windows OS)なら「Alt + Up」で親ディレクトリへ移動ができる。端末でも同じようなことができたらと思い「Shift + Up」を設定してみたら、意外と使えたので紹介

#環境
|             | 名前            | バージョン |
|:------------|:--------------- |:-------|
| OS          | OS X El Capitan |10.11.6 |
| 端末         | iTerm2          |3.0.5   |
| シェル        | zsh             |5.2     |

#設定
`~/.zshrc`に以下内容を追加

```bash
# hook関数precmd実行
__call_precmds() {
  type precmd > /dev/null 2>&1 && precmd
  for __pre_func in $precmd_functions; do $__pre_func; done
}

#shift+upで親ディレクトリへ
__cd_up()   { builtin cd ..; echo "\r\n"; __call_precmds; zle reset-prompt }
zle -N __cd_up;   bindkey '^[[1;2A' __cd_up
```

※上記の`^[`は`^ + [` でなく「Esc」

#試行錯誤
上記設定内容にいたるまで

## 1.最初に
まずは何も考えず、zshのキーバインド設定のお約束な書き方で記載

参考:
　・[よく実行するコマンドにキーバインドを割り当てると捗る話](http://qiita.com/yuku_t/items/e58cbecf13407446bd50#2-2)
　・[zle:bindkeys\[ZshWiki\]](http://zshwiki.org/home/zle/bindkeys#ctrl-v_-_manually_find_out_esc-sequences)

```bash
__cd_up() { cd ..; zle reset-prompt }
zle -N __cd_up;   bindkey '^[[1;2A' __cd_up
```

そしたら、cdの拡張プラグイン[enhancd](http://qiita.com/b4b4r07/items/2cf90da00a4c2c7b7e60)が動いてエラーが、、

```bash
awk: i/o error occurred while closing /dev/stdin
 source line number 16
awk: i/o error occurred while closing /dev/stdin
```

設定していたことをすっかり忘れていた。。。

## 2.余計な処理が入らないように

素のcdが動くように`builtin`を追加

```bash
__cd_up() { builtin cd ..; zle reset-prompt }
zle -N __cd_up;   bindkey '^[[1;2A' __cd_up
```

参考：
`$ man sh`から
>
**builtin shell-builtin [arguments]**
  Execute the specified shell builtin, passing it arguments, and return its  exit
  status.   This  is  useful when defining a function whose name is the same as a
  shell builtin, retaining the functionality of the builtin within the  function.
  The  cd  builtin is commonly redefined this way.  The return status is false if
  shell-builtin is not a shell builtin command.
>

しかし、改行してくれない

```bash
# Shift + Upを押下
[2016-07-29 15:28] ~/workspace　-> [2016-07-29 15:28] ~
%
```

こうなってほしい

```bash
# Shift + Upを押下
[2016-07-29 15:28] ~/workspace
%
[2016-07-29 15:28] ~
%
```

## 3.改行を入れる
何も考えずに`echo "\r\n"` 入れてみた

```bash
__cd_up() { builtin cd ..; echo "\r\n"; zle reset-prompt }
zle -N __cd_up;   bindkey '^[[1;2A' __cd_up
```

思った通り、動いた。
が、右プロンプトに表示するgit情報が変化しない

```bash
[2016-07-29 16:24] ~/workspace/study
% cd dotfile
[2016-07-29 16:24] ~/workspace/study/dotfiles
%                                                            (git)-[master]
[2016-07-29 16:24] ~/workspace/study
%                                                            (git)-[master]
```

## 4.原因の調査
右プロンプトはhook関数によって描画を変更しているらしい
※該当の設定はコピペなので、気付かなかった
参考:
・[zshでhook関数を登録する](http://qiita.com/mollifier/items/558712f1a93ee07e22e2)
・[zshのターミナルにリポジトリの情報を表示してみる](http://tkengo.github.io/blog/2013/05/12/zsh-vcs-info/)

`~/.zshrc`にて

```bash
########################################
# vcs_info
autoload -Uz vcs_info
autoload -Uz add-zsh-hook

zstyle ':vcs_info:*' formats '%F{green}(%s)-[%b]%f'
zstyle ':vcs_info:*' actionformats '%F{red}(%s)-[%b|%a]%f'

_update_vcs_info_msg() {
    RPROMPT="${vcs_info_msg_0_}"
}
add-zsh-hook precmd _update_vcs_info_msg

```

hook関数を全く考慮していなかったことに気づく

## 5.hook関数実行処理追加して完成

参考:
　[precmdを明示的に呼ぶ方法](http://qiita.com/yuyuchu3333/items/b01536fa63d9f8fadf4f)

```bash
# hook関数precmd実行
__call_precmds() {
  type precmd > /dev/null 2>&1 && precmd
  for __pre_func in $precmd_functions; do $__pre_func; done
}

#shift+upで親ディレクトリへ
__cd_up()   { builtin cd ..; echo "\r\n"; __call_precmds; zle reset-prompt }
zle -N __cd_up;   bindkey '^[[1;2A' __cd_up

```

うまく動いた

# おまけ：「戻る」を可能に(`cd`から`pushd`に変更)

Finder(Mac OS)なら「Cmd + [」、Explorer(Windows OS)なら「Alt + Left」で前のディレクトリへ移動できる。
`pushd`を使用すれば、同じようなことができるのではと思いつき変更
ついでに「Shift + Down」で`popd`実行する処理を追加

参考:
　[ディレクトリの移動は cd コマンドよりも pushd コマンドのほうが便利！](http://qiita.com/noraworld/items/81c12253d22b7575151a)
　

```bash
# hook関数precmd実行
__call_precmds() {
  type precmd > /dev/null 2>&1 && precmd
  for __pre_func in $precmd_functions; do $__pre_func; done
}

#shift+upで親ディレクトリへ
#shift+downで戻る
__cd_up()   { builtin pushd ..; echo; __call_precmds; zle reset-prompt }
__cd_undo() { builtin popd;     echo; __call_precmds; zle reset-prompt }
zle -N __cd_up;   bindkey '^[[1;2A' __cd_up
zle -N __cd_undo; bindkey '^[[1;2B' __cd_undo
```

※ `pushd`を実行するとディレクトリスタックを表示し、改行するので`echo "\r\n";` -> `echo;`に変更

# 使ってみての感想
　上記のキーバインド設定を追加してから、実はそれほど便利には感じていなかったのですがキーバインド未設定の端末を操作することで無意識に
「Shift + Up」
を押していたことに気づきました
　よく考えると「cd ..」は「c + d + Space + . + . + Enter」と6回キーを押す必要があります。
やや雑に考えれば、キーバインドしておくことで速さは単純に6倍向上することになります。さらに「cd ..」はどちらかといえば、使用頻度が高いコマンドです。

 実際は思った以上に役立っていたようです。