zsh, emacs, git, peco とかの話

# 久々に開発やったら色々便利なものが出てたのでまとめ

すでにガリガリ書いてたのは遥か昔で全く開発に興味はなくなっていたのですが、最近少しだけ開発する機会があった。で、適当な開発環境でやろうかな？と思ったんだけど、不便な所とか少しずつ手を入れてったら、気がつけば結構良い感じになってたので、ここにまとめておく事にしました。

また開発からは少し離れることになるんだけど、いつか開発やる時にこれを元に環境が作れたらいいなーなんて思ってるんだけど、その頃には、また浦島太郎状態だろうけどね。

## 誰が嬉しいのか？

僕の環境を晒して、再度環境を作る時の自分用のメモって位置付けですが、今同じ職場で働いている新卒君や２年目の人などに、コードを「読む・書く」って時に、これがあると全然効率が違うよ！ってのをアピる意味も含んだりしています :sweat_smile: 

zshに乗り換える！とかscreen使う！とかemacs使う！とか言ってくれれば設定マルっと差し上げますよ。

## 1. 環境

- [iterm2](https://www.iterm2.com/)
- [screen](https://www.gnu.org/software/screen/)
- [zsh](http://www.zsh.org/)
- [emacs](https://www.gnu.org/software/emacs/)
- [Karabiner](https://pqrs.org/osx/karabiner/index.html.ja)

これは必須かな。
KarabinerはEmacsでIME使う関係で入れてまして、他にも色々細かいのはあるけど、別になくても大丈夫かな。

```xml:private.xml
<?xml version="1.0"?>
<root>
  <list>
    <item>
        <name>C-c, C-x, C-z to IME off</name>
        <identifier>Emacs + GoogleIME Issue.</identifier>
        <only>TERMINAL</only>
        <autogen>--KeyToKey-- KeyCode::C, VK_CONTROL, KeyCode::C, VK_CONTROL, KeyCode::JIS_EISUU</autogen>
        <autogen>--KeyToKey-- KeyCode::X, VK_CONTROL, KeyCode::X, VK_CONTROL, KeyCode::JIS_EISUU</autogen>
        <autogen>--KeyToKey-- KeyCode::Z, VK_CONTROL, KeyCode::Z, VK_CONTROL, KeyCode::JIS_EISUU</autogen>
    </item>
   </list>
</root>
```

``C-c``, ``C-x``, ``C-z`` でIMEをOFFです。IMEは[Google日本語入力](https://www.google.co.jp/ime/)。このキーマップも思いっきりイジっていますが、それはまた別の機会に。


##2. iterm2

``com.googlecode.iterm2.plist`` をGoogle Driveに入れて大事に使ってますが、今の見た目とか設定（抜粋）はこんな感じ。iterm2ではマウスでスクロールしないようにしています。Magic Mouse使ってると意図せずスクロールしてストレスでしかないし、screenのコピーモードを使っているので、完全にマウスいらね。

マウスでscreenのスクロールが出来るみたいですが、何やっても上手くいかないので、諦めました。

mac iTerm2 マウスでスクロールバッファ（ステータス付）
http://qiita.com/monkick@github/items/83af0614beba840979fe


![見た目](https://qiita-image-store.s3.amazonaws.com/0/101357/11c72cbe-b164-5f6c-a1d5-5228cfc50815.png "見た目")
あんまりこだわりはないです。screen使っているので、iterm2のタブは一切使わない位でしょうか。macaってのはmacBとか控えてるからで全く考えずつけたマシン名です。今いる``branch``（ここでは``master``）がわかるようにしているのは、zshの設定を見てください。ちなみに``root``になっているとプロンプトは赤字になります。

Fontはもちろん[``Ricty``](https://github.com/yascentur/Ricty)

![設定１](https://qiita-image-store.s3.amazonaws.com/0/101357/c5d9b8c3-2717-3138-f6b5-1d970a756aae.png "設定２")
僕は``alt``を親指で押すので、``command``と``option(meta)``を入れ替えてます。
あまり見ませんが画面の切り替えを``右alt（親指）+TAB（左小指）``でやってます。IMEのON/OFFも``C+o``でやってます。

![設定２](https://qiita-image-store.s3.amazonaws.com/0/101357/61174923-485b-729a-e54d-927e45c9b121.png "設定２")
問題はここですね。Ctrlと組み合わせて使うキーがEmacsに入ってこないので、``send hex code``を結構書いてます。
IMEで変換中の場合は、C+数字でFunctionキーの機能を割り当ててます（``F7``は``C+7``って形）。

絶対にホームポジションから動きたくないんです。

Emacsの特殊キーコンボについてはこちらを参照しました。

[ターミナルのEmacsでも特殊キーコンボ ](http://d.akinori.org/2012/01/02/%E3%82%BF%E3%83%BC%E3%83%9F%E3%83%8A%E3%83%AB%E3%81%AEemacs%E3%81%A7%E3%82%82%E7%89%B9%E6%AE%8A%E3%82%AD%E3%83%BC%E3%82%B3%E3%83%B3%E3%83%9C/)

##3. zsh

こんな感じ。``` .zshlocal ```ってファイルもあって、これは特殊なコマンド（職場でしか使わない）を書いたりしています。

.zshlocalに書いてあるのは、``kinit``を楽にする設定とか、踏み台を経由する``ssh``とか、プロジェクトで使っているワークフローを自動化しているツール（wってaliasつけて笑ツールって読んでます）とかです。

```zsh:.zshrc
# UTF-8
export LANG=ja_JP.UTF-8

# COREを作らない
ulimit -c 0

# Emacs ライクな操作を有効にする（文字入力中に Ctrl-F,B でカーソル移動など）
bindkey -e

# autoloadされる関数を検索するパス
fpath=(~/.zfunc $fpath)
fpath=(~/.git_completion $fpath)
fpath=(~/.zsh.d/anyframe(N-/) $fpath)

# zsh plugin
autoload -Uz anyframe-init
anyframe-init

# 履歴の保存先と保存数
HISTFILE=$HOME/.zsh_history
HISTSIZE=100000
SAVEHIST=100000

# 色の設定
local DEFAULT=$'%{^[[m%}'$
local RED=$'%{^[[1;31m%}'$
local GREEN=$'%{^[[1;32m%}'$
local YELLOW=$'%{^[[1;33m%}'$
local BLUE=$'%{^[[1;34m%}'$
local PURPLE=$'%{^[[1;35m%}'$
local LIGHT_BLUE=$'%{^[[1;36m%}'$
local WHITE=$'%{^[[1;37m%}'$

export LSCOLORS=exfxcxdxbxegedabagacad
export LS_COLORS='di=34:ln=35:so=32:pi=33:ex=31:bd=46;34:cd=43;34:su=41;30:sg=46;30:tw=42;30:ow=43;30'

# 自動補完を有効にする
# コマンドの引数やパス名を途中まで入力して <Tab> を押すといい感じに補完してくれる
autoload -U compinit; compinit -u

# 入力したコマンド名が間違っている場合には修正
setopt correct
setopt correct_all
# 入力したコマンドが存在せず、かつディレクトリ名と一致するなら、ディレクトリに cd する
setopt auto_cd
# cd した先のディレクトリをディレクトリスタックに追加する
# ディレクトリスタックとは今までに行ったディレクトリの履歴のこと
setopt auto_pushd
# pushd したとき、ディレクトリがすでにスタックに含まれていればスタックに追加しない
setopt pushd_ignore_dups
# 入力したコマンドがすでにコマンド履歴に含まれる場合、履歴から古いほうのコマンドを削除する
# コマンド履歴とは今まで入力したコマンドの一覧のことで、上下キーでたどれる
setopt hist_ignore_all_dups
# コマンドがスペースで始まる場合、コマンド履歴に追加しない
setopt hist_ignore_space
# 補完キー連打で順に補完候補を自動で補完
setopt auto_menu
# 拡張グロブで補完(~とか^とか。例えばless *.txt~memo.txt ならmemo.txt 以外の *.txt にマッチ)
setopt extended_glob
# Beepを鳴らさない
setopt no_beep
setopt no_list_beep
# 補完候補を詰めて表示
setopt list_packed
# このオプションが有効な状態で、ある変数に絶対パスのディレクトリを設定すると、即座にその変数の名前が
# ディレクトリの名前になり、すぐにプロンプトに設定している'%~'やcdコマンドの'~'での補完に反映されるようになる。
setopt auto_name_dirs
# 補完実行時にスラッシュが末尾に付いたとき、必要に応じてスラッシュを除去する
setopt auto_remove_slash
# 行の末尾がバッククォートでも無視する
setopt sun_keyboard_hack
# 補完候補一覧でファイルの種別を識別マーク表示(ls -F の記号)
setopt list_types
# 補完のときプロンプトの位置を変えない
setopt always_last_prompt
# 変数の単語分割を行う
setopt sh_word_split
# 履歴にタイムスタンプを追加する
setopt extended_history
# Ctrl-s, Ctrl-q によるフロー制御を無効にする
setopt no_flow_control
# 履歴を共有する
setopt share_history
# バックグラウンドジョブが終了したら(プロンプトの表示を待たずに)すぐに知らせる
setopt notify

# <Tab> でパス名の補完候補を表示したあと、
# 続けて <Tab> を押すと候補からパス名を選択できるようになる
# 候補を選ぶには <Tab> か Ctrl-N,B,F,P
zstyle ':completion:*:default' menu select=1
# キャッシュを利用する
zstyle ':completion:*' use-cache true
# 補完から除外するファイル
zstyle ':completion:*:*files' ignored-patterns '*?.o' '*?~' '*\#'
# ファイル補完候補に色を付ける
zstyle ':completion:*' list-colors ${(s.:.)LS_COLORS}
# cd は親ディレクトリからカレントディレクトリを選択しないので表示させないようにする
zstyle ':completion:*:cd:*' ignore-parents parent pwd
# 大文字小文字を区別しない
zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'

# 履歴
alias his=anyframe-widget-execute-history

# cd
alias cdd=anyframe-widget-cdr

# select history
function peco-select-history() {
    local tac
    if which tac > /dev/null; then
        tac="tac"
    else
        tac="tail -r"
    fi
    BUFFER=$(\history -n 1 | \
        eval $tac | \
        peco --query "$LBUFFER")
    CURSOR=$#BUFFER
    zle clear-screen
}
zle -N peco-select-history
bindkey '^r' peco-select-history

# cdr
autoload -Uz is-at-least
if is-at-least 4.3.11
then
  autoload -Uz chpwd_recent_dirs cdr add-zsh-hook
  add-zsh-hook chpwd chpwd_recent_dirs
  zstyle ':chpwd:*'      recent-dirs-max 1000
  zstyle ':chpwd:*'      recent-dirs-default yes
  zstyle ':completion:*' recent-dirs-insert both
fi

# ブランチ名を表示する
function __git_branch() {
  git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\:\1/'
}
alias gbn=__git_branch

# Emacsはbrew版をターミナルで利用する
alias emacs='/usr/local/Cellar/emacs/24.5/bin/emacs -nw'
alias gtags='/usr/local/Cellar/global/6.5.1/bin/gtags'
alias screen='/usr/local/Cellar/screenutf8/4.3.1/bin/screen -U'

# 色の設定
if [ `uname` = "FreeBSD" ]; then
  alias ls='ls -GF'
  alias ll='ls -alGF'
elif [ `uname` = "Darwin" ]; then
  alias ls='ls -GF'
  alias ll='ls -alGF'
else
  alias ls='ls -F --color=auto'
  alias ll='ls -alF --color=auto'
fi

# プロンプト
setopt prompt_subst
if [ `whoami` = "root" ]; then
  PROMPT='[%F{red}%n@%m%F{default}]# '
else
  PROMPT='[%m$(gbn)]# '
fi
RPROMPT='[%F{green}%d%f%F{default}]'

# スクリーン起動
if [ "$WINDOW" = "" ] ; then
  screen
fi

function preexec() {
  if [ $TERM_PROGRAM = 'iTerm.app' ]; then
    mycmd=(${(s: :)${1}})
    echo -ne "\ek$(hostname|awk 'BEGIN{FS="."}{print $1}'):$mycmd[1]\e\\"
  fi
}
function precmd() {
  if [ $TERM_PROGRAM = 'iTerm.app' ]; then
    echo -ne "\ek$(hostname|awk 'BEGIN{FS="."}{print $1}'):idle\e\\"
  fi
}
```


``cdd``と``C-r（peco-select-history）``はもう手放せないです。emacsでも``Helm``（``Anything``から使っていました）なので、絞り込んで実行することに慣れてしまっています。

- ``cdd``はcdした履歴を[peco](https://github.com/peco/peco)で絞り込んで移動します。``cdr``, [``anyframe``](http://qiita.com/mollifier/items/81b18c012d7841ab33c3)使ってます。
- ``C-r``はコマンドの履歴をpecoで絞り込みます。

これは騙されたと思って入れて見て欲しいです。世界が変わります。


```zsh:.zshenv
path=(
  ~/bin ~/local/bin bin ~/usr/local/bin /bin /sbin /usr/local/bin /usr/bin /usr/sbin /opt/local/bin /opt/local/sbin
)

# VISUAL
if [ -x "`which vim`" ]; then
    export VISUAL=vim
else
    export VISUAL=vi
fi

# EDITOR
if [ -x "`which emacs`" ]; then
    export EDITOR="emacs -nw"
elif [ -x "`which vim`" ]; then
    export EDITOR=vim
fi

# PAGER
if which lv >& /dev/null ; then
  export PAGER="lv"
elif which less >& /dev/null ;  then
  export PAGER="less -RM --quiet -x2"
else
  export PAGER="more -x2"
fi

export HOSTNAME=`hostname`
export LC_COLLATE="ja_JP.UTF-8"
export WORDCHARS="*?_-.[]~=&!#$%^(){}<>"

alias ll='ls -alF'
alias ls='ls -F'
alias ps='ps auxw'
alias tc='tar cvzf'
alias tx='tar xvzf'

# grep
alias -g gr='grep --color -n '
alias -g xg='|xargs grep --color -n '

# peco
alias jump='_jump'
alias look='less $(find . -type f -maxdepth 1 | peco)'

# ag & view
function _jump(){
  __path=$(ag $* | peco | awk -F: '{printf  $1 " +" $2}'| sed -e 's/\+$//')
  if [ -n "$__path" ]; then
    view $__path
  fi
}

# git & peco.
function _git-hash(){
  git log --oneline --branches | peco | awk '{print $1}'
}
function _git-changed-files(){
  git status --short | peco | awk '{print $2}'
}

alias -g gith='$(_git-hash)'
alias -g gitc='$(_git-changed-files)'

# git diff view
function __vimd() {
  vimdiff $1 <(git show remotes/origin/test:$1)
}
alias vimd=__vimd

function __git_unmerges() {
  git l  $1..$(gbn | sed -e 's/\://')
}
alias git_unmerges=__git_unmerges

# git access token
if [ -e ~/.brew_api_token ]; then
    source ~/.brew_api_token
fi

# local setting
if [ -e ~/.zshlocal ]; then
    source ~/.zshlocal
fi

```

``look``と``jump``は結構便利に使ってます。``gith``, ``gitc``はキーバインドに入れてませんが、これも便利です。

- ``xg`` はただの```| argx grep ```を書くのが面倒なだけです。
- ``jump``は[``ag``](https://github.com/ggreer/the_silver_searcher)の結果をpecoで絞り込んでviewで行指定で開くコマンドです。
- ``look``はカレントディレクトリのファイルをlessでチラ見する時に使ってます。
- ``gith``はgitのハッシュを``peco``で選択。diffとか使い道はかなりあります。
- ``gitc``はgitのstatusのファイルを``peco``で選択。``add``とかで使ってます。
- ``vimd``はtestブランチのファイルとの差分を見るだけ。
- ``git_unmerges``は未マージの変更をみます。マージ漏れ防止の為。

あとは``brew``のためのtokenと職場でしか使わない設定を読み込んでいるだけです。この２つは当たり前ですが、gitで管理してないです（言い忘れましたが、``.zshrc``とか``emacs``の``.el``とかは全部gitにおいていて、どこでも同じような環境が作れるようにしてます。本当はemacsとかscreenとかのインストールのshellも書きたいんだけど面倒くさいからやってません。あと``plist``はGoogle Driveです）。

``look``と``jump``を使っている所

![Untitled3.gif](https://qiita-image-store.s3.amazonaws.com/0/101357/fc9cc927-3571-9641-7f9e-3226a4174fa9.gif "Untitled3.gif")


##4. brew

![Cellar](https://qiita-image-store.s3.amazonaws.com/0/101357/939c9468-754d-8af7-1353-ab6fdee314d5.png "Cellar")

これ入れてます。手抜きｗ
``tig``は便利です。恥ずかしいTYPOしたくないなら``aspel``とかは入れておきましょう。

##5. git config

```text:.gitconfig
[core]
    excludesfile = ~/.gitignore_global
    precomposeunicode = true
    quotepath = false
    editor = emacs -nw
[user]
    name  = xxxxxxxxxxxxxxxxxxxx
    email = xxxxxxxxxxxxxxxxxxxx
[color]
    ui          = auto
    status      = auto
    diff        = auto
    branch      = auto
    interactive = auto
    grep        = auto
[alias]
    # base command
    br   = branch
    co   = checkout
    st   = status
    sh   = show
    ft   = fetch
    co   = checkout
    ad   = add
    ci   = commit
    # cancel
    unad = reset HEAD --
    unci = reset --soft HEAD^
    amci = commit -amend
    # diff
    ds = diff --staged
    d1 = diff HEAD~
    d2 = diff HEAD~~
    d3 = diff HEAD~~~
    d4 = diff HEAD~~~~
    d5 = diff HEAD~~~~~
    # log
    l  = log --pretty=format:'%C(green)%h %C(white)%<(20,trunc)%an %<(80,trunc)%s'
    ll = log --pretty=format:'%C(red reverse)%d%Creset%C(white reverse) %h% Creset %C(green reverse) %an %Creset %C(cyan)%ar%Creset%n%C(white bold)%w(80)%s%Creset%n%n%w(80,2,2)%b' --graph --name-status
    # merge
    unmerge = ls-files --unmerged
[diff]
    tool = vimdiff
[difftool]
    prompt = false
[merge]
    tool = vimdiff
    ff = false
[mergetool]
    prompt = false
[pull]
    rebase = preserve

```

``pull``は``rebase``にしていて、``merge``も``no-ff``です。別に普通ですかね。
``TABインデント``を``SPACEインデント``に変えたりしているので、頻繁にコンフリクトするの```ls-files --unmerged```をaliasに登録していますが、全然使っていないです。

``ll``はどこからか忘れましたが、いただきものです。こんなの自分で書けません :sweat_smile: 

##6. emacs

![emacs](https://qiita-image-store.s3.amazonaws.com/0/101357/3dc871b0-0532-5a7d-7c7a-3e6ae6ade2c1.png "emacs")

久々にやった開発は``PHP``だったので、``PHP``関連の``lisp``をメインに追加しました。画面は適当な``PHP``のファイルを開いて```helm-swoop```で``this``を検索している所です。

Emacsはターミナルで使っています。``GUI(cocoa)``で受けられる恩恵（``IMEパッチ``が動く、[``git-gutter``](https://github.com/syohex/emacs-git-gutter)が動くなど）もありますが、僕は``C-z``（``screen``のキーバインドを``C-z``にしているので、正確には``C-zz``）で直ぐにシェルでコマンド叩いて``fg``で``emacs``に戻るスタイルになれていますので、``GUI``は今後も使わないです。

ちょっと話がそれますが、仕事中にscreenは最低でも3つは常に開いています。

- emacs用
- ``vagrant ssh``しているスクリーン
- ``tig``立ち上げてるスクリーン

それとは別に割り込みの作業とかが入った場合は迷わず``C-zc``です。

### 今や必須

- helm

``anything``使ってたのですが、この機会に乗換ました。
``helm``と``peco``使っていると絞りこまないで何かをしていたのが信じられません。

### コードを読むとき

- helm-gtags
- helm-swoop
- helm-ls-git

gtagsとswoopがあれば十分なんだけど、``ls-git``も便利。``helm-mini``の``recentf``もあると便利かな。
そうなんです、プロジェクトのファイル数がめっちゃ多いのです。覚えられないのです（しつこいw）。

### コードを書くとき

- auto-complete
- smart-char
- helm-c-yasnippet

この辺はどの言語でも使ってるかな。

では、emacsの設定行きますか。

### ディレクトリ構成
```
elisp/
elpa/
inits/
init.el
recentf
snippets/
```
``elpa``, ``recntf``以外はgit管理。定番だと思いますが、init.elはこれ。

```lisp:init.el
(require 'init-loader-x "~/.emacs.d/elisp/init-loader-x")
(init-loader-load "~/.emacs.d/inits")
```

``elisp``にはこれだけしか入っていないです。ほぼ全ての``lisp``は``list-packages``で入れていまして、``use-package :ensure`` でなければインストールするようにしていてます。

```
anything/
auto-install/
dmacro.el
init-loader-x.el
smartchr.el
themes/
```

- ``anything``は``auto-complete``だったか、``php-completion``だったかが僕の設定が足りていないのか、``anythig``を使おうとしてwarningが``\*messages\*``に出てウザイのでおいてあるだけ。
- ``auto-install``は今のところ使ってないですが、ディレクトリだけ作っておいた
- ``dmacro``はめっちゃ使います。[xyzzy](http://xyzzy-022.github.io/)にも移植されていて、そっちでも使っています。
- ``smartchr``も便利ですね。

### inits

```
00-package.el
01-path.el
02-auto-install.el
03-lang.el
04-global-fun.el
05-display.el
06-whitespace.el
07-theme.el
08-recentf.el
09-linum.el
10-redo.el
11-rainbow-mode.el
12-rainbow-delimiters.el
13-auto-complete.el
14-smartchr.el
15-helm-c-yasnippet.el
15-helm-descbinds.el
15-helm-gtags.el
15-helm-ls-git.el
15-helm-swoop.el
15-helm.el
16-powerline.el
17-expand-region.el
18-dmacro.el
19-aspell.el
20-auto-highlight-symbol.el
21-org-mode.el
22-flycheck.el
23-migemo.el
24-which-key.el
25-yasnippet.el
30-other-init.el
40-default-style.el
41-lisp-mode.el
42-c-mode.el
43-php-mode.el
44-js2-mode.el
45-web-mode.el
46-markdown.el
99-bind-key.el
```

これ整理するの大変でしたが、前は``.emacs``にベタに書いていたので、ぐちゃぐちゃでしたが、綺麗サッパリしました。
いくつかピックアップして紹介します。

#### 11-rainbow-mode.el

カラーコードを実際の見た目に反映してくれます。CSSとか書くときは超便利。
![スクリーンショット 2015-12-09 14.10.16.png](https://qiita-image-store.s3.amazonaws.com/0/101357/652acdda-4006-21e6-61e3-b4c514856f63.png "スクリーンショット 2015-12-09 14.10.16.png")

#### 12-rainbow-delimiters.el

かっこを虹色で表示してくれて見やすいです。
![スクリーンショット 2015-12-09 14.07.53.png](https://qiita-image-store.s3.amazonaws.com/0/101357/54dda037-fabb-981f-2ca7-6503a59d9949.png "スクリーンショット 2015-12-09 14.07.53.png")

#### 13-auto-complete.el

定番の補完
![スクリーンショット 2015-12-09 14.12.41.png](https://qiita-image-store.s3.amazonaws.com/0/101357/0e94cbd0-73e6-6107-cc03-fdbcd694aba9.png "スクリーンショット 2015-12-09 14.12.41.png")

#### 15-helm-c-yasnippet.el

classって打って```C-y```するだけで、ここまでコードが挿入されます。クラス名を入れて``TAB``を打つとコンストラクタの実装にすぐに入れます。
![Untitled.gif](https://qiita-image-store.s3.amazonaws.com/0/101357/203b0669-4c92-4922-bb49-12f19767ad1c.gif "Untitled.gif")

#### 15-helm-gtags.el

コード読むのに必須。このGIFでは関数の実体へジャンプして、戻ってきて、関数を使っている場所の一覧を出しています（もちろん一覧からもジャンプできます）。

![Untitled2.gif](https://qiita-image-store.s3.amazonaws.com/0/101357/f9a9359b-3e47-bcd9-aa3e-7660229087c2.gif "Untitled2.gif")


## 最後に

tagjump と snippet位はあったほうが効率が良いので普段使っているエディタにそういう拡張があれば是非使ってみてください。あと不便だなと思ったら自前でshell書いちゃうのも良いです。不便なものを不便なまま使っているのはストレスになりますよ。

おしまい。