はてなブックマークのエントリーページで個別のブックマークを非表示にするテスト

はてなブックマークのブックマーク一覧ページで、特定のブックマークを非表示にできるようになった。
エントリーページ上の個別のブックマークを非表示にする機能を追加しました - はてなブックマーク日記 - 機能変更、お知らせなど

はてなダイアリーを書いてる人は、自分の日記につけられたブックマークを個別に指定して非表示にできる。

実験

というわけで、早速このエントリをはてなブックマークに追加して非表示にしてみることにした。
この「表示制御画面へ」というリンク先に移動して、

非表示にしたいブックマークにチェックを入れてボタンを押せば OK。

反映されるまでにちょっと時間がかかるけど(5分ぐらい?)、ちゃんとこのエントリのブックマーク一覧ページには出てこなくなった。ただし、ブックマークした本人(この場合は僕)と、ブックマークした人をお気に入りに追加してる人には見えるみたい。

あと、メタブでも同じように非表示にできる。自分でメタブしてメタブの一覧ページで非表示にしてみた。

感想

この機能があるってことは、せっかくブックマークが共有できるようになってるのにそれが見えなくなることがあるわけで、僕としてはあんまりうれしくない。

はてなダイアリーとかのブログ、サイト作成者がいい感じの基準でこの機能を使ってくれることを期待してます。

oh-my-zsh を使って zsh の便利な設定をまとめて取り入れる

最近 oh-my-zsh ってのがあるって聞いた。インストールするだけで zsh が便利になるみたいなので、早速試してみた。

oh-my-zsh って何?

oh-my-zshzsh の設定を管理するフレームワークで、いろんな設定を有効にして管理、更新できるようになる。プロジェクトは GitHub で管理されてる。

http://github.com/robbyrussell/oh-my-zsh

特徴としてこんなことが挙げられてる。

  • 40以上のプロンプト テーマ
  • 便利なプラグイン
  • 自動アップデート機能
  • コミュニティ主体の開発(みんなの設定を取り込んでいく)

インストールすると、だいたいこんなことが設定される。

  • プロンプトがかっこよく(?)なる
  • alias がいっぱい設定される
  • よく使う option が設定される

インストール直後はこんな感じ。

Git のブランチ名も表示される。

必要な環境なんだけど、zsh のバージョンは 4.3.9 以降を推奨してる。Mac の Snow Leopard の人はデフォルトの zsh で OK。あと、全体的に Git 使ってること前提っぽい。

インストール

インストール用に自動スクリプトがある。

% wget http://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh -O - | sh

こいつを実行すれば oh-my-zsy がローカル環境にインストールされる。でも、勝手に chsh でログインシェルを変えたりして色々やりすぎなので、あんまりおすすめしない。

手動でインストールする方法は以下。

% git clone git://github.com/robbyrussell/oh-my-zsh.git ~/.oh-my-zsh
# 自分の ~/.zshrc がすでにある場合はリネームしておく
% mv ~/.zshrc ~/.zshrc.orig
% cp ~/.oh-my-zsh/templates/zshrc.zsh-template ~/.zshrc

どっちの方法も Git が必要になる。Git 使えない人は GitHub のプロジェクトページから圧縮ファイルをダウンロードしてインストールしよう。

# ダウンロードファイルを展開して ~/.oh-my-zsh にコピーする
% unzip robbyrussell-oh-my-zsh-541da0c.zip
% mv robbyrussell-oh-my-zsh-541da0c ~/.oh-my-zsh
% cp ~/.oh-my-zsh/templates/zshrc.zsh-template ~/.zshrc

インストールした後適当に zsh を再起動すると oh-my-zsh が有効になる。

あと、インストール先の ~/.oh-my-zsh というディレクトリ名は固定で、変えたら動かない

プロンプトの設定

oh-my-zsh にプロンプトのテーマがいっぱい入ってる。~/.zshrc で ZSH_THEME を設定するとテーマを変更できる。

# ~/.zshrc 6行目
# デフォルトは robbyrussell
export ZSH_THEME="robbyrussell"

~/.oh-my-zsh/themes の中を見て、好きなものに変更しよう。

export ZSH_THEME="cypher"

zsh を再起動すると新しいテーマになる。

プラグイン

~/.oh-my-zsh/plugins/ 以下に独自のプラグインが入ってる。

% ls ~/.oh-my-zsh/plugins/
brew/  dirpersist/  git/         macports/  osx/  rails/  ssh-agent/  vi-mode/
cap/   gem/         lighthouse/  mysql/     pip/  ruby/   textmate/

このうち使用するものを ~/.zshrc で指定する。デフォルトはこんな感じ。

# ~/.zshrc 19行目
plugins=(git)

使用したいものを指定しよう。

plugins=(git ruby gem)

プラグインと言ってもそんな凝ったことしてるわけじゃなくて、 だいたい alias、便利な関数、 補完ファイルとかが読み込まれるだけ。

カスタム設定

自分の独自の設定は ~/.oh-my-zsh/custom に適当な名前(最後は .zsh)でファイルを作ってそこに書く。

# 例
% cat ~/.oh-my-zsh/custom/custom-aliases.zsh
alias v='vim'
alias vr='vim -R'
alias c='cd'

好きなように書いておこう。

自動アップデート

1週間に1回のタイミングで、zsh 起動時に自動的アップデートされる。アップデートといっても単純に GitHub から pull してくるだけ。なので Git 使わずにインストールした人はこの機能が使えない。

勝手にアップデートされるのがいやなら ~/.zhsrc で無効にできる。

# ~/.zshrc 12行目をアンコメント
export DISABLE_AUTO_UPDATE="true"

使ってみた感じ

使ってみた感想なんだけど、なんか全体的に作った人の「個人的な便利設定の集まり」みたいになってる。一般におすすめできるかというと、ちょっと疑問が残る。

作者の theunraveler さんの環境はたぶんこんな感じ。

典型的な(?) Rubyist だと思うので、そういう人意外にはありがたみがないかもしれない。

例えば textmate プラグインにこんな設定が入ってる。

alias ett='mate app config lib db public spec test Rakefile Capfile Todo &'

Textmate(Mac 用のエディタ)の設定のはずが、明らかに Rails 使ってること前提になってる。なので Rails やってない人はこのへん意味ない。(だからプラグインの形になってるわけね)

というか、そもそも alias って手癖みたいなもんで、めちゃ人に依存するとこだと思う。なので誰かの設定をそのまま持ってきても便利になるとは限らない。すでに zsh カスタマイズしまくりの人が oh-my-zsh 使ってもかえって混乱するだけだと思う。

なので、oh-my-zsh をおすすめするのは以下の人。

  • これから zsh を初めて使う人
  • 設定とかカスタマイズとか自分でやりたくない人
  • Mac で RubyRails な人

でもインストールするだけで zsh の補完とかがすぐ使えるようになるのは良いと思う。というわけで、「zsh ってよくわかんないし、設定難しいし、簡単にパワフルな機能使ってウヒョーってなりたい」ってひとは使ってみるといいと思うよ。

Kanasan.JS jQuery コードリーディング #2 に参加したので復習とコードの解説をする

2010/09/26(日) に京都で Kanasan.JS jQuery コードリーディング #2 が行われた(告知ページ)。みんなで jQueryソースコードを読む勉強会で、僕は初めての参加。事前に前回分も読んでおいたので準備万端、気合いを入れて参加した。

で、今回の内容なんだけど、642行目から1205行目まで読み終えた。全部で6240行なので全体の5分の1ぐらい終わったかな。今回は普段外部から使うものじゃなくて、jQuery 内部で使う関数のところが多かった。あとは jQuery マニアしか使わないようなメソッドとか。そんなわけで使い方がイメージしにくいところもあったので、その中でわかりにくかったとこを復習して挙げておく。

あと、今回読んだ jQuery のバージョンは 1.4.2。

前提

こんな感じでメソッドを追加してるところがある。

jQuery.extend({
  queue: // ... queue の実装
});
jQuery.fn.extend({
  queue: // ... queue の実装
});

1つ目の jQuery.extend の方は jQuery のグローバルな関数というか jQuery のクラスメソッドを定義してる。そいつは $.queue() みたいな感じで呼び出せる。

2つ目の jQuery.fn.extend の方は jQuery オブジェクトのインスタンスメソッドを定義してて、$("div").queue() みたいな感じで呼び出す。インスタンスメソッドの方はたいてい一つ目の方法で定義した関数を使って実装されてる。なので、jQuery.extend の方の実装を理解するのが大事。

こうやってメソッドを追加してるとこは今回に限らずいろんなとこで出てくるので、基本ルールとして押さえておく。

DOM に関係ない関数

361行目から719行目までで jQuery.extend({ ... }); 形式で jQuery のクラスメソッドを定義してる。気になったものは以下。

map

よくある map 関数なんだけど、最後がちょっとわかりにくい。

return ret.concat.apply([], ret);

これは何をしているかというと、jQuery の map は map 用の callback が配列を返したとき、その配列を展開した各要素が結果に追加される、という仕様になってる。で、 ret は map した結果がどんどん追加される配列なんだけど、最後の return するところで配列を一段階取り除いてる。

// concat で配列をなだらかにする例
[].concat(1, [2, 3], [4, 5]); //=> [1, 2, 3, 4, 5]

つまり Ruby でいうところの flatten。

proxy

そもそも $.proxy って何ですかってことで調べてみたら、わかりやすい解説があった。
jQuery1.4から追加されたjQuery.proxy()を試してみる | THE HAM MEDIA BLOG
$.proxy(fn, thisObject) みたいな感じで呼び出すと、「その中の this が thisObject になった新しい fn 関数」を返す。

proxy 関数の実装は、余計なところを取り除くとこうなる。

proxy: function(fn, thisObject) {
  return function() {
    return fn.apply(thisObject, arguments);
  };
}

つまり、proxy を使うと this をすり替えて実行してくれる新しい関数がもらえるので、bind する時にわざわざ function { thisObject.fn(); } とかしなくてもよくて便利だよ、ってことらしい。うん、まあ半年に一回くらいしか使わないだろう。

IE の DOMContentLoaded

759行目、IE で DOMContentLoaded イベントが発生しないので、その代わりのテクニックを使ってる。

function doScrollCheck() {
  try {
    // If IE is used, use the trick by Diego Perini
    // http://javascript.nwbox.com/IEContentLoaded/
    document.documentElement.doScroll("left");
  } catch( error ) {
    setTimeout( doScrollCheck, 1 );
    return;
  }

  // and execute any waiting functions
  jQuery.ready();
}

IE の「DOM ツリーができあがる前に doScroll を呼び出すと例外が発生する」という仕様なのかバグなのかよくわかんない動作を利用して、doScroll しまくって例外がでなくなったら DOM ツリー完成、という風にしてる。

このテクニックはその筋の人には有名みたいで、コメントにもある通り IEContentLoaded - An alternative for DOMContenloaded on Internet Explorer に詳細が書いてある。

この場合 doScroll でほんとにスクロールしてしまったら困るので "left" を指定して画面が移動しないようにしてる。だれかが「"up" でもいいんじゃないの?」って言ってたような気がするけど、"#main" みたいなページ内アンカーに飛んできた場合は最初の位置がページの一番上じゃないこともあるわけで、やっぱり "left" がいいと思う。

jQuery.support

みんな大好きバッドノウハウのコーナーということで、829行目からはブラウザが標準から外れた動作(というかバグ)をするかどうかをチェックしてる。

特に目を引いたのがこの1行。

div.innerHTML =
  "   <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";

この HTML 1行で10種類のバグがあるかどうかチェックしてる。

  • leadingWhitespace
  • tbody
  • htmlSerialize
  • style
  • hrefNormalized
  • opacity
  • cssFloat
  • checkOn
  • optSelected
  • parentNode

「こんなにがんばってチェックしてるんだし、IE もバージョンがあがればよくなるはずだし、if (jQuery.browser.msie) { /* fu*k */ } とか書くのやめようぜ」ってことらしい。もう職人芸だね。

jQuery.support.hrefNormalized

jQuery.support には hrefNormalized ってのがあって、こんな感じの実装になってる。

hrefNormalized: a.getAttribute("href") === "/a",

getAttribute("href") したら普通は href 属性に書いてある値がそのままとれるんだけど、IE の場合は 'http://' から始まる絶対 URL 形式の値が返ってくる。

で、この hrefNormalized って名前逆じゃね? って発言があった。僕もそう思う。

これに限らず、jQuery のコードにはよくない名前がけっこうある(なので安易にまねしない方がいい)。

jQuery.support.deleteExpando

続きを読んでると jQuery.support.deleteExpando ってのが出てきた。「というか expando って何?」って話になったけど、オブジェクトに動的に追加したプロパティのことをそう呼ぶらしい(知らなかった)。Wiktionary にも expando のページがある。

この deleteExpando チェックの内容なんだけど、まず JavaScript の仕様としてはオブジェクトの存在しないプロパティを delete しても特に問題なくて、例外が発生したりしない。

var a = document.createElement("a");
delete a.hoge;  // true が返る

でもこの delete で例外が発生するよろしくないブラウザ(つまり IE)があって、そのときには jQuery.support.deleteExpando が false になるようだ。

jQuery.data 関数

1001行目から jQuery.data の実装が始まる。普通の jQuery プログラミングではあんまり使用しない関数なんだけど、jQuery の内部では結構使われているので大事だ。データ構造を押さえておくことにする。

jQuery.data(element, key, value) の基本的な機能は、emelent(DOM 要素)ごとに名前と値の組としてデータを格納する、というもの。

データを格納する時は DOM 要素ごとに一意的な ID を割り振って、その ID をキーとして jQuery.cache というグローバルなオブジェクトに値を格納する。

jQuery.cache のイメージはこんな感じ。

jQuery.cache = {
  id1 : {
    // element1 用のデータ
    key1_1 : value1
    key1_2 : value2
  },
  id2 : {
    // element2 用のデータ
    key2_1 : value3
  }
}

対象となった DOM 要素側でも ID を覚えてるので、あとからそれをキーとしてデータを取ってこれる。

jQuery.data の実装としては中でいろいろやってるんだけど、基本的なとこだけを残すとこうなる。

// グローバルな変数の初期化
var uuid = 0;
JQuery.expando = "jQuery" + (new Date).getTime();
JQuery.cache = {};

// jQuery.data の実装
jQuery.data = function(element, key, value) {
  // 要素ごとに一意的な ID を割り振る
  var id = ++uuid;
  element[jQuery.expando] = id;

  if (!jQuery.cache[id]) {
    jQuery.cache[id] = {};
  }
  jQuery.cache[id][key] = value;

  return value;
}

DOM 要素側で ID を覚えておく際に、現在時刻を取ってプロパティ名としてかぶらない名前を使うようになってる。

jQuery.queue 関数

早速1117行目からの jQuery.queue 関数で jQuery.data を使ってる。

jQuery.queue(element, queueName, value) は、指定された DOM 要素に queueName という名前のキューを作ってそこに値を追加する関数。

こいつも結局 jQuery.data を使って、queueName という名前で配列データを作ってキューとして使用してる。

// jQuery.queue のイメージ
jQuery.queue = function(element, queueName, value) {
  var queueName = (queueName || "fx") + "queue";
  // 現在のキュー(配列)を取得する
  var q = jQuery.data(element, queueName);
  q.push(value);

  return q;
}

キューにためるデータとしては何でもいいんだけど、関数というかイベントハンドラを登録することを想定しているようだ。「上に移動した後、色を変える」とか順番に行いたい処理をキューにためるといいんだろう。

最後に

読む上での注意なんだけど、tkyk さんもブログで指摘してたように、ソースを読む前にリファレンスマニュアルを読むのが大事。処理の概要がわかるし、引数を省略した場合の扱いとかも書いてある。つまり、リファレンスマニュアルは API の利用者だけでなく、実装を読んだり改造したりする人にとっても重要ってことだね。

なんか今回でコツがつかめたような気がするので、次回も楽しみにしてます。

jQuery ソースコードを読むための参考資料一覧

2010/09/26(日) に京都で Kanasan.JS jQuery コードリーディング #2 が行われる(告知ページ)。みんなで jQueryソースコードを読むイベントで、今回が2回目だ。参加者募集中です。

jQuery はファイル1つだけのライブラリなのですごい環境とかもってなくても大丈夫なんだけど、読むうえで参考になるサイトとかをまとめてみた。この辺の準備をしておくと理解が深まると思う。

ソースコード

http://code.jquery.com/jquery-1.4.2.js
http://github.com/jquery/jquery

まずは jQueryソースコードを取ってこないと始まらない。今回はバージョン 1.4.2 を使用する。jQuery の公式サイトから圧縮していないコードをダウンロードしよう。

それと、jQuery ソースコードは Git で管理されてる。Git が使える人はソースツリーを取ってくるといろいろできて便利。

% git clone git://github.com/jquery/jquery.git
# バージョン 1.4.2 に移動
% git checkout 1.4.2

src の下に分割されたソースコードがいっぱいはいってて、git log とか git blame で見れる。結合したいときは make, rake, ant のどれかで dist/jquery.js ってとこにソースコードができあがる。

あと、 test ディレクトリの下に test/unit/core.js とかテストコードがあって参考になる。

Git 使えない人でも GitHub にリポジトリがあるのでブラウザからログとか見れるよ。

リファレンスマニュアル

コードを読むときにリファレンスマニュアルもあわせて参照すると便利。その関数が何をするものなのか、とか呼び出し方の例とかが書いてあって参考になる。

公式のリファレンスマニュアル。何はともあれ、このページが一番詳しいし信用できる。

日本語リファレンスもある。これは 1.4.2 に対応してるのでいい感じ。

これは別の日本語リファレンス。うさぎがヌーヌー言ってるやつ。バージョン 1.3.2 対応のもようでちょっと古い。

チケット管理

http://dev.jquery.com/

jQueryソースコードを読んでると、こんな感じで #xxxx みたいな数字がコメントに書いてあることがある。

// 例えば 452 行目
// aren't supported. They return false on IE (#2968).

これはバグ管理システムのチケット ID で、「この部分はバグとして登録されてるよ」ってことを表してる。

登録されたチケットの詳細は jQuery の Bug Tracker ページから参照できる。チケット ID が分かってる場合は http://dev.jquery.com/ticket/2968 みたいな感じで「/ticket/チケットID」形式の URL を開くとそこが詳細ページになってる。あと、「Search Tickets」の欄に「#2968」とかチケット ID を入力すると詳細ページに移動できるので、そっちでも OK。

チケット詳細ページを見ると「どんな問題があったのか」、「どうやって修正するか」とかの議論が見れる。「IE の場合は XXX でムキー!」とか書いてあるので参考になる。

コーディング規約

http://docs.jquery.com/JQuery_Core_Style_Guidelines

jQuery にもコーディング規約がある。まあインデントスタイルとかは読む分には関係ないんだけど、大事そうなところを挙げておく。

'==', '!=' ではなくて '===', '!==' を使用する。

'==', '!=' はいろいろキモい動きをするので、代わりに '===', '!==' を使う。でも == null っていうのは === null または === undefined っていう意味で便利なので、この場合は '==' とか '!=' を使う。

for/in の hasOwnProperty チェックはしない

Object を for/in でぐるぐるループさせて連想配列として使うことがある。

// 素朴な書き方
for (name in obj) {
  // 何か処理
}

でも、もし Object.prototype を拡張してたらそいつまで for/in に出てきてしまってうまく動かなくなる。それを防ぐために hasOwnProperty でチェックするっていうテクニックがよく使われる。

// 行儀のいい書き方
for (name in obj) {
  if (obj.hasOwnProperty(name) {
    // 何か処理
  }
}

jQuery のコードでは一つ目の素朴な書き方で書いてる。Object.prototype を拡張してしまったらちゃんと動かなくなるけど、そんな邪悪な環境はサポートしないそうだ。

型チェック

型をチェックする方法も書いてある。
チェック方法は以下。

  • String, Number, Boolean, Object

typeof object === "string" など

  • Plain Object, Function, Array

それぞれ jQuery.isPlainObject(object), jQuery.isFunction(object), jQuery.isArray(object)

  • Element

object.nodeType

  • null

object === null

  • null または undefined

object == null

  • undefined
    • グローバル変数の場合 : typeof variable === "undefined"
    • ローカル変数の場合 variable === undefined
    • オブジェクトのプロパティの場合 : object.prop === undefined

Plain Object ってのは、何か継承したのじゃない単なるオブジェクトのこと。要するに {} 形式で書いたやつ。

正規表現

正規表現を使う場合、.test() と .exec() を使う。string.match() は使わない。理由は書いてないので分からない。単にどっちかに統一したかっただけなのかもしれない。

その他の参考記事

jQuery ソースコードを読む連載記事。バージョンは 1.2.2 で古いけど、詳しい解説があって参考になる。

ソースコードを読むための基礎知識。

jQueryソースコード ビューアー。メソッド名を入れると対応するコードが表示される。メソッドがどこで定義されてるのかわかんないときに見る。

この辺を押さえておくとだいぶコードが読みやすくなると思うので、是非コードリーディングに挑戦してみてください。

Twitter のユーザーページに発言頻度を表示する Greasemonkey スクリプトを修正した

以前 id:hitode909 さんが Twitter のユーザーページに発言頻度を表示する Greasemonkey スクリプトを作った。ソースコードgist で公開されてる

でも、なんかたまに表示がおかしくなることがある。

調べてみたら、つぶやきの日付を取ってくるところがよくないようだ。つぶやきが公式 RT だった場合、HTML の中に元の日付と RT したときの日付が入ってるんだけど、元のコードでは前者のほう、RT 元の日付を取ってしまっている。

その場合つぶやきの日付が本来よりも古くなって、一番上と下のつぶやき時刻を比べるときに一番上の方が過去の日付になってしまうことがあった(普通は一番上が新しい)。

フォローするかどうかに使ってて困ったので、元のコードをフォークして直した。
gist: 572201 - GitHub
公式 RT の場合でもその人が RT したときの日付を取ってくるように変更した。twitter-average-length2 という別名のスクリプトになってるよ。

zsh で Git の作業コピーに変更があるかどうかをプロンプトに表示する方法

2012/12/13 追記

zsh 4.3.11 以降の新しい機能を使って改良しました。 -> 「zsh の vcs_info に独自の処理を追加して stash 数とか push していない件数とか何でも表示する - Qiita


Git を使ってファイルを編集した場合、それをいったんインデックスに追加(add)してその後コミットってのが基本的な流れになる。なんかいろいろやってると、ちゃんと add したのかどうかわかんなくなることがある。

そういうときは status コマンド使えばいいんだけど、以前エントリ書いた zshvcs_info の機能を使うといい感じにプロンプトに表示できるようになるので紹介する。

zshrc の書き方

こんな風に zshrc に書いておけば OK。

autoload -Uz add-zsh-hook
autoload -Uz colors
colors
autoload -Uz vcs_info

zstyle ':vcs_info:*' enable git svn hg bzr
zstyle ':vcs_info:*' formats '(%s)-[%b]'
zstyle ':vcs_info:*' actionformats '(%s)-[%b|%a]'
zstyle ':vcs_info:(svn|bzr):*' branchformat '%b:r%r'
zstyle ':vcs_info:bzr:*' use-simple true

autoload -Uz is-at-least
if is-at-least 4.3.10; then
  # この check-for-changes が今回の設定するところ
  zstyle ':vcs_info:git:*' check-for-changes true
  zstyle ':vcs_info:git:*' stagedstr "+"    # 適当な文字列に変更する
  zstyle ':vcs_info:git:*' unstagedstr "-"  # 適当の文字列に変更する
  zstyle ':vcs_info:git:*' formats '(%s)-[%b] %c%u'
  zstyle ':vcs_info:git:*' actionformats '(%s)-[%b|%a] %c%u'
fi

function _update_vcs_info_msg() {
    psvar=()
    LANG=en_US.UTF-8 vcs_info
    [[ -n "$vcs_info_msg_0_" ]] && psvar[1]="$vcs_info_msg_0_"
}
add-zsh-hook precmd _update_vcs_info_msg
RPROMPT="%1(v|%F{green}%1v%f|)"

こんな感じで、リポジトリに変更がある場合はプロンプトに + とか - とか表示される。

作業コピーを編集して、まだインデックスに追加していないとき

変更をインデックスに追加済みのとき

変更をインデックスに追加済みで、それ以外にも作業コピーに変更があるとき

+, - は好きな文字列に変えて使おう。

check-for-changes についてもうちょっと詳しく

check-for-changes ってのは zsh のバージョン 4.3.10 から入った vcs_info の機能で、今いるリポジトリにローカルで変更を加えたかどうかを通知してくれる仕組み。

設定方法は以下。

まず最初に、4.3.10 ってのはけっこう新しいバージョンなので、まだそれより古いって人もいると思う。そのときは使えないんだけど、せめて変なエラーメッセージが出ないようにしておこう。

autoload -Uz is-at-least
if is-at-least 4.3.10; then
  # この部分はバージョン 4.3.10 以降で有効になる
fi

こんな風に書いておくと、古いバージョンの時は何も設定されずにエラーが出なくなる。1つの zshrc をいろんな環境で使ってる人はこう書いておいた方がいいよ。ちなみに Mac の Snow Leopard にデフォルトで入ってる zsh は 4.3.9 (残念)。

ここまでが準備。次に肝心の中身だけど、まずはこんな風に書いてその設定を有効にする。

zstyle ':vcs_info:git:*' check-for-changes true

現時点では check-for-changes は Git でしか動かないので、Git の場合のみ有効にしてる。Mercurial(hg) 対応は今やってるとこみたい。そのうち使えるようになるだろう。

で、実際に表示する文字列を設定する。

# インデックスに追加された場合に表示される文字列
zstyle ':vcs_info:git:*' stagedstr "+"

# 作業コピーに変更があった場合に表示される文字列
zstyle ':vcs_info:git:*' unstagedstr "-"

"+"、"-" は適当な文字列に置き換えよう。デフォルトではそれぞれ "S"、"U" になってるので、そのままでいい人は書かなくても OK。

最後に、プロンプトに表示するフォーマットを指定する。

zstyle ':vcs_info:git:*' formats '(%s)-[%b] %c%u'
zstyle ':vcs_info:git:*' actionformats '(%s)-[%b|%a] %c%u'

%cstagedstr%uunstagedstr に置き換えられる。ここも適当に変更してかっこいいプロンプトにしよう。

パフォーマンスについて

この check-for-changes の機能は便利なんだけど、リポジトリのサイズによってはかなり遅くなる可能性がある(って man に書いてある)。なのでデフォルトでは無効になっている。

実際にどのくらい遅くなるのか試してみた。zsh の git リポジトリ(git://zsh.git.sf.net/gitroot/zsh/zsh)で確認。

まずは check-for-changes なしの場合

% time (vcs_info)
(; vcs_info; )  0.01s user 0.03s system 102% cpu 0.043 total

次に check-for-changes ありの場合

% time (vcs_info)
(; vcs_info; )  0.08s user 0.03s system 103% cpu 0.104 total

合計で2倍ぐらい時間かかってる。

僕が見た感じでも、ちょっと遅くなってるのが分かる。使って困るというほどでもないけど、あんまり遅すぎるようだったら無効にしよう。

参考

いい感じのプロンプトになったと思う。もっと細かく調整したい人は man zshcontrib の GATHERING INFORMATION FROM VERSION CONTROL SYSTEMS を見てね。