さいつよのターミナル環境を構築しよう

  • 1530
    いいね
  • 6
    コメント
この記事は最終更新日から1年以上が経過しています。

僕はターミナルに引きこもっています。たまに外出しても最寄りのブラウザ程度です。そんな僕は Mac を使っています。綺麗な UNIX だからです。ターミナルアプリとしてターミナル.app を使っています。iTerm2 含めいろいろ試しましたがコレがさいつよでした。そして、僕は 2 年半かけてさいつよ環境を築き上げました。

tl;dr

最強のターミナル開発環境の構築する

最強の開発環境を目指して

タイトルで豪語しすぎた感はありますが、本気で構築中です。僕がターミナル環境の整備に目覚めたのは学生の時でした。特に何かのプロジェクトに携わるといったこともなく、たまに講義の課題を解いたり趣味のアプリを作成したりといった程度での開発だったので、環境構築や整備に割く時間がありました。

まずは現状

普段のターミナル環境は次のとおりです。

  • ターミナル.app(全画面)
  • tmux 1.9a
  • zsh 5.0.5
  • vim 7.4

ベースは以上になります。コレらさえあれば、とりあえず何らかのものづくりは可能です。あとは使い勝手の向上をはかっていくのみです。

基本的に 2 ペインで作業しています。左で作業して右で確認やその他雑務といった具合です。ペイン分けしているとメインペインでエディタを立ち上げたとしても、片側でコマンドラインが見えるので安心します。

カスタマイズ

ソフトウェア個々の設定についてみていきます。

立ち回りとしては、ターミナル立ち上げてログインシェルが tmux を自動起動して、その tmux 上で zsh を動かす感じです。つまり tmux 周りを固めることが先決でした。

ターミナル.app

その前に土台となるアプリケーションのカスタマイズです。

まずは、見た目のカスタマイズです。Solarized という目に優しいカラースキームがあります。記事トップにある画像の色味がそれです。以下からダウンロードできます。

Solarized Dark を読み込みデフォルト設定としました。

tmux

tmux はターミナルマルチプレクサと呼ばれるもので、ターミナル上でウィンドウを分割(ペイン)したり、複数のウィンドウを立ち上げたりすることができます。tmux のほかには GNU screen などが有名です。

  • ステータスバーのカスタマイズ

    まずはこれです。僕はターミナル.app を全画面表示しています。故に、OS X が持つステータスバー(日時・時刻や IME、常駐アプリなどの表示バー)を確認することができなくなります。そこで、tmux でそれをエミュレートしています。

    画像にもある通り、これがあれば何ら困ることもありません。OS X らしく tmux のステータスバーも上部に設定しました(ただし tmux 1.8 以上であること)。

    バッテリー表示などエミュレーションに使ったスクリプトは以下にあります。

  • キーバインドのカスタマイズ

    ペイン移動やウィンドウ移動、ペインリサイズなどの操作キーバインドはすべて Vim ライクのものにしました。これら後述しますが僕が Vim 派だからです。好みの問題なのでここは各種それぞれで。
    ペインの分割に関しては、直感的に割れる Prefix + |(縦割り)と Prefix + -(横割り)を採用しました。

  • カラースキームのカスタマイズ

    ターミナル.app 同様、Solarized です。やはり見た目の統一は大事です。
    tmux-colors-solarized からダウンロードして、tmux 内で source するだけです。

詳しくは、ターミナルマルチプレクサ tmux をカスタマイズする - Qiitaで言及しているので併せてどうぞ。

zsh

カスタマイズの大本命です。普段過ごすシェルは自分色に染められずにはいませんが、幸いに zsh はその全てに応えてくれるほどに高機能なポテンシャルを秘めています。

まずはその zsh をカスタマイズするのに相応しい「さいつよ」なプラグインを選りすぐりましょう。

そして、さいつよな zsh プラグインマネージャを導入します(Vim の NeoBundle みたいなやつです)。

僕は zsh の設定ファイルを分割しています(今までは嫌でしたが)。zsh に限っては分割したほうがベストプラクティスに感じ始めたからです。

現在の zsh に関する構造は以下のとおりです。

$ tree -a
...
├── .zsh
│   ├── 10_utils.zsh
│   ├── 20_keybinds.zsh
│   ├── 30_aliases.zsh
│   ├── 40_prompt.zsh
│   ├── 50_setopt.zsh
│   ...
├── .zshenv
├── .zshrc
...

dotfiles の構造については後述します。ひとまず .zsh というディレクトリを用意して、その中に分割用の設定ファイルを配置しています。数字による番号を振っているのはグロッビングによる自動ソートを無効化するためです。.zshrc 内で、

for f in ~/.zsh/[0-9]*.(sh|zsh)
do
    source "$f"
    ...

として、呼び出したい番号順にファイルにプレフィックスとして追加することで、source の順番を操作しています。

現在、.zshrc でやっていることは以下のとおりです。

  • 各種 zsh モジュールを autoload
  • シェルスクリプトの共通ライブラリを source する
  • tmux を立ち上げる(アタッチ or 新規作成)
  • zplug でプラグインをクローン・ロード

これだけです。こうすることで、.zshrc 内の見通しが良くなり、保守がしやすくなりました。

ちなみに、tmux は zsh 側で自動アタッチ or 新規セッションを選択できるようになっています。zsh が設定ファイル内で以下のスクリプトを呼び出しているためです。

ターミナル.app を立ち上げただけで以下のアスクがあり、セッションへのアタッチも簡単にできます。

vim

メインで使用するエディタです。開発には欠かせない武器です。IDE やその他の統合開発環境は嫌いよりもエディタ派ですね。Vim バインドが身に染みついているというのもあります。

  • プラグイン

    ゴリゴリにカスタマイズ…派が多いようですが、個人的にはそんなに利用していません。試してみてほんとうに気に入ったものだけなどに限っています。プラグイン依存が進むと、インストールできない環境での操作がつらいので(Vim は zsh などに比べて素の環境での操作を強いられる局面が多い気がするためです)。

    また、以下に使っているプラグインを何個か列挙、紹介します。

  • カラースキーム

    やっぱり Solarized ですね。GitHub は vim-colors-solarized にありますので、手動クローンでもよし、プラグイン管理マネージャ(neobundle.vim や pathogen)でインストールしてもいいでしょう。

  • 自動インストール

    プラグインその他、Vim の初回立ち上げ時に丸っとインストールするようにしています。

dotfiles という文化

dotfiles という設定ファイルを集めたリポジトリで管理するのが今や主流になっています(GitHub に五万とホスティングされています)。自分好みの設定に仕上げたあとは GitHub 上で公開しましょう。アップするまでが dotfiles です(家に帰るまでが遠足、的な)。こうすることでバージョン管理もでき、バックアップも兼ねることができます。今まで築き上げた設定を失うのはとてつもなく悲しいですからね。

以下では、その dotfiles 周りと取り巻く開発スタイルについて紹介します。

ghq/Go スタイル

これらの管理手法について便宜上、ghq/Go スタイルとしておきます。ghq/Go スタイルによる開発を行うことで、作業場所(作業ディレクトリ)に囚われない、かつ同じお作法で管理することができます。

$ tree -L 2 ~/src
/Users/b4b4r07/src
├── github.com
│   ├── BurntSushi
│   ├── b4b4r07
│   │   ├── brionac
│   │   ├── dotfiles
│   │   ├── enhancd
│   │   ├── emoji-cli
│   │   ├── gomi
│   │   ├── gotcha
│   │   └── xtime
│   ├── cheggaaa
│   ├── codegangsta
│   ├── daviddengcn
│   ├── google
│   ├── jessevdk
│   ├── junegunn
...
│   ├── mitchellh
│   ├── motemen
│   ├── nlopes
│   ├── nsf
│   ├── peco
│   └── x
└── golang.org
    └── x

~/src 以下にすべてのリポジトリを保持し、開発・保守にあたります。こうすることで、「あのプロジェクトどこにおいたっけ?」とかの心配はなくなります。また、よく ghqpecofzf といったインタラクティブなフィルタリング機能を持つコマンドと併用されています。これは ghq に限らずとても便利なので別記事にて紹介したいと思います。

以下は peco + ghq の例です。ghq/Go スタイルで管理するリポジトリに対し、簡単にディレクトリ移動を行うことができます。次が Bash 版で、

# Require Bash 4.0+
peco-src() {
    local selected
    selected="$(ghq list --full-path | peco --query="$READLINE_LINE")"
    if [ -n "$selected" ]; then
        READLINE_LINE="builtin cd $selected"
        READLINE_POINT=${#READLINE_LINE}
    fi
}
bind -x '"\C-]": peco-src'

次が Zsh 版です。

peco-src() {
    local selected
    selected="$(ghq list --full-path | peco --query="$LBUFFER")"
    if [ -n "$selected" ]; then
        BUFFER="builtin cd $selected"
        # zle accept-line
    fi
    zle reset-prompt
}
zle -N peco-src
bindkey '^]' peco-src

特にこの開発スタイルで重要なのは、単に「ツール "ghq" を用いること」ではありません。重要なのは Go 言語の開発スタイルをお作法とし、それに倣って他の言語についても同様に管理・開発していくことです。そしてそのフロントエンドのインターフェイスとして、ツール "ghq" を用いることです。

そのため、ghq コマンドだけに縛られずに、よりフレックスに自分スタイルを交えてカスタマイズしていくことができます。僕はリモートリポジトリをクローンすること(git clone および ghq get 相当)だけに特化した git コマンドを作成し、ghq/Go スタイルで利用しています(後述)。

工夫した点

dotfiles の成熟についてです。僕は 2 年半ほど前にこのリポジトリをつくりだしてから初期は、GitHub 上にある dotfiles リポジトリの多く(ページ数 80 以上)を見てきました。そこでパクったり自分流に改変したり、作りなおしたり書き換えたり取りやめたりを繰り返していくなかで研ぎ澄まされた知見について書き連ねます。

マルチプラットフォーム化

特定のプラットフォームに依存しないように心がけています。メインで使っているマシンは OS X ですが、よく簡易 Linux マシンを使ったり、Linux サーバにアクセスして dotfiles を踏まえた開発を行ったりする場面があります。

OS X のみならず、Linux ひいては Cygwin にも対応したスクリプトを書けるならそのほうがベターでしょう。対応できないのなら、エラー処理をするといいでしょう。

# ostype returns the lowercase OS name
ostype() {
    uname | tr "[:upper:]" "[:lower:]"
}

# os_detect export the PLATFORM variable as you see fit
os_detect() {
    case "$(ostype)" in
        *'linux'*)  PLATFORM='linux'   ;;
        *'darwin'*) PLATFORM='osx'     ;;
        *'bsd'*)    PLATFORM='bsd'     ;;
        *)          PLATFORM='unknown' ;;
    esac
    export PLATFORM
}

# is_osx returns true if running OS is Macintosh
is_osx() {
    os_detect
    if [ "$PLATFORM" = "osx" ]; then
        return 0
    else
        return 1
    fi
}

少し回りくどい書き方をしていますが、OS で分岐させる処理はめっちゃ大事です。Linux と OS X が行き来することも多いため、OS X 向けに書いていてそれがどこかで作用してエラーが起きるとかはよくあります。

オートメーション化

今流行の自動化です。dotfiles についても同様です。環境設定が一発すぐに環境すると気持ちいいし楽です。

僕の場合は、bash -c "$(curl -fsSL dot.b4b4r07.com)" で dotfiles その他環境設定が終わるようになっています。これについて賛否両論ありそうですが、僕はこれでいいのです。

より深い話については省略します。以前、以下の記事で書きましたのでよろしければどうぞ。

さいつよを支えるコマンドたち

何度も出てきましたが、この最強のターミナル開発環境は最高の dotfiles の設定と ghq/Go スタイルからなっています。すべての作業の起点だからです。

そして開発をバックアップしてくれるのが何らかに特化した自作コマンド群です。何個かだけ紹介します。

git-get

これはリモートリポジトリをクローンすること(git clone および ghq get 相当)だけに特化した git のサブコマンドです。シェルスクリプトで書いています(以下はコードを短くして掲載しました)。

#!/bin/bash

# Check arguments
if [[ -z $1 ]]; then
    echo "too few argument" 1>&2; exit 1
elif [[ ! $1 =~ ^(((https?|git)://)?github\.com/)?([A-Za-z0-9_-]+/)?[A-Za-z0-9_.-]+(\.git)?$ ]]; then
    echo "$1: invalid github.com URL" 1>&2
    exit 1
fi

# Format username/reponame
uri="$(echo "$1" | perl -pe "s/^(((https?|git):\/\/)?github\.com\/)?//;s/\.git$//")"

# if uri consists of "reponame" only
if [[ ! $uri =~ / ]]; then
    user="$(git config --get user.name)"
    uri="${user:-$USER}/$uri"
fi
username="${uri%/*}"
reponame="${uri#*/}"

# Destination
dest="${2:-$HOME/src/github.com/${username:?not set}}"
if [ -d "$dest" ]; then dest="$dest/$reponame"; fi

if [ -d "$dest" ]; then
    echo "${dest/$HOME/~}: already exists" 1>&2; exit 1
fi
mkdir -p "$dest" 2>/dev/null
git clone "https://github.com/${uri}.git" "$dest"

ghq get よりもフレキシブルな指定が可能となっています。

  • git get gomi としたとき: gomi をレポジトリ名として認識し、ユーザ名を git config --get user.name から補完します
  • git get b4b4r07/enhancd としたとき: https://github.com を補完します
  • git get github.com/b4b4r07/emoji-cli としたとき: https:// を補完します

git clone で用いるようなフル URL ももちろん受け付けます。そして、ダウンロード先は指定しない限り ~/src 以下のホスティングされたサービスのドメイン名以下のディレクトリになります。これは ghq/Go スタイルを踏襲しての設計です。

dot

dotfiles に関する機能を一手に担っているシェル関数です。ちょっと長くなるので省略しますが、リポジトリルートへの移動やファイル列挙が可能です。

gotcha

最近賑わっている Go 言語のパッケージを取得してくるコマンドです。このコマンド自体も Go 言語で書いたため並列処理で高速にダウンロードすることができます。Go は優秀な CLI ツールも多いため、専用の go get を作ったという背景です。

さいつよを支えるプラグインたち

主に zsh プラグインについてなので、vim の項と並んで zsh の項に書くべきですが、エディタと違ってシェルなので、さいつよコマンドに並べて紹介します。

外部プラグインについて詳細にまとめられた Qiita 記事もあるので、より詳しくは以下にお任せします。

また、GitHub に awesome もあるのでどうぞ。

zsh-users/antigen

プラグイン管理マネージャ(プラグイン)です。antigen bundle username/reponame で簡単にインストールできます。zsh プラグインのヘビーユーザはマストアイテムでしょう。

最近は tarjoilija/zgen という antigen の高速化バージョンもアツいようです。

zsh-users/zsh-history-substring-search

これはヒストリ検索をやりやすくしてくれます。いちいち C-r を使うまでもないとき、grep とだけコマンドラインにタイプし、C-p すると grep に限り遡ることができます。慣れると病みつきになります。。。

zsh-users/zsh-syntax-highlighting

コマンドラインにもシンタックスハイライトをもたらしてくれるプラグインです。fish のアレのような感じです。$PATH に確認できるコマンドや、クォーテーションした文字列、ディレクトリ部分などには色や装飾がつきます。

b4b4r07/enhancd

cd コマンド強化用のプラグインです。今流行の fzfpeco などのインタラクティブなフィルタを使って候補の絞込などができます。詳しくはリンクにある gif アニメを見ると分かりやすいと思います。

b4b4r07/emoji-cli

このプラグインはターミナル上で絵文字補完を行います。絵文字といえば、コロンから始まりコロンで終わる文字列ですが、「本」の絵文字が使いたいと思っても、様々な絵文字がある文字の単語部分が思い出せなかったりします。そんなときは、こいつが類推して変換してくれます。最近は、コミットメッセージなんかでも活発に利用されるため便利です。コレについてもリンクに gif アニメがあるのでどうぞ。

まとめ

この記事では、さいつよターミナル環境を作るための設定や工夫について紹介してきました。なんでここまでする必要があるのかと思った人もいるでしょう。ではまずここで Atom さんの話をしておきます。

最近では、エディタであるはずにも関わらず、ターミナルマルチプレクサちっくな側面とグラフィカルなシェルとカスタマイザブルなプラグイン機構(スクリプト含め)を内蔵した Atom とかいう鉄腕アトム的なフルスタックスーパーマンが台頭してきているようです。しかし、私はそれが嫌い好きではありません。

dotfiles はたまごっち

Atom を好きになれないのはたまごっち的な要素がないからでしょう!以下は僕の GitHub の Contributions ですが最近はこれを育てるのが楽しみの一つです。毎日草生やすことで(dotfilesだけに限りませんが)、リポジトリの育成記録として活躍しています。

Atom 含めそれら GUI アプリには設定やカスタマイズに関する機構があっても、それを育てていくという概念がないような気がします。一方で dotfiles は長い年月をかけ自分好みにカスタマイズ、リポジトリを育てていくことができます。そこに愛情を感じるのではないでしょうか。

よって dotfiles 含め環境構築はたまごっちです。