よんちゅBlog

― このブログは自分用のメモや日々の問題などを共有するためのものです ―

20121005185841 お知らせ:  2013/07/17 ブログデザインをリニューアルしました。

zshのプロンプトにpyenv(Python)の状態を表示する

久々なのでひっそりと更新
リハビリも兼ねて軽めのものを1つ。

はじめに

最近重い腰をあげてようやく Python の開発環境をpyenvに移行しました。

まだ使い始めたばかりですがなかなかの好感触。
ただ、pyenv を使ってて気になったのが、現在どの Python を使っているのかが分かりづらいという点。

よくあるPATH書き換え方式ではないので、which(type) コマンドでパスを見ても分からないんですよね。
最初仕組みを理解してなくて悩んでしまいました…

$ pyenv version
system (set by /Users/yonchu/.pyenv/version)
$ which python
/Users/yonchu/.pyenv/shims/python


$ pyenv global 2.7.8
$ pyenv version
2.7.8 (set by /Users/yonchu/.pyenv/version)
$ which python
/Users/yonchu/.pyenv/shims/python

pyenv コマンドを使えば分かる話なのですが、pyenv を入れてる環境・入れてない環境・入れてるけど使ってない環境が混在すると混乱しちゃうんですよね。
統一しろよって話ですが…

というわけで、zsh のプロンプトに Python のバージョンと仮想環境名を表示させることにしました。

zsh-python-prompt を作った

https://raw.githubusercontent.com/yonchu/zsh-python-prompt/master/img/ScreenShot01.png

zsh のプラグインとして以下に公開しました。

zsh スクリプトのリハビリもしたかったので、autoload なんかも使って zsh らしく仕上げてみました。

導入方法

zsh-python-prompt を適当な場所に配置

$ git clone https://github.com/yonchu/zsh-python-prompt.git

.zshrc 内で以下のように source する。(パスは適宜書き換えて下さい)

source /path/to/zsh-python-prompt/zshrc.zsh

プロンプトに設定

PROMPT+='$ZSH_PYTHON_PROMPT'

以上

おわり

今回はこんな感じで、久々の更新でした。

キャッシュ機能付きでそこそこ動作も軽いので、良ければ使ってみてください。

補足

上で zsh で source して使うプラグインを作るのは止めにしよう - Qiita という記事へのリンクを張っておきながら、source してるじゃねーかと言われそうですが、コードの見通しや導入の簡単さなどを考えて、初期設定用のコードのみ source するようにしました。

zsh の補完関数で キャッシュ機能(cache-policy) を使う

今回は grunt コマンドの補完関数を例として キャッシュ機能(cache-policy) について解説していきます。
grunt については知らなくても大丈夫だと思います。

キャッシュ機能(cache-policy) についての解説がメインなので、zsh 補完関数の基本的な説明は省略します。
その代わり、コード内にコメントで簡単な説明を書きましたのでそちらを参考にして下さい。

※ とても長い記事なので、誤字脱字があるかもしれません。ご容赦下さい。m(_ _)m
(見つけたら教えてくれると助かります)

はじめに

grunt には標準で bash の補完がついています。
しかし、zsh 用の補完関数は無く、bash の補完と同じ方法で実装したのではオプションやタスクの説明が表示されません。
オプションの説明はベタ書きでいいとしても、タスクの説明はそうはいきません。

ということで作成したのが、grunt-zsh-completion です。

grunt のタスクは、"grunt --version --verbose" または "grunt --help" で取得することができますが、前者は実行が早い代わりにタスクの説明が取得できません、後者は実行が遅いかわりにタスクの説明も取得することができます。

bash の補完では前者が採用されており、今回作成した grunt-zsh-completion では後者を採用しました。

さらに、"grunt --help" の遅さをカバーするために キャッシュ機能(cache-policy) を実装しました。

今回は grunt-zsh-completion を例として解説するわけですが、実際のコードではちょっと複雑すぎるので解説用に余分な部分を省いたコードで見ていくことにします。

キャッシュ機能を有効にする

解説の前に、まずはキャッシュを有効にしましょう。

いくら補完関数がキャッシュ機能を実装していても、それを使用するユーザがキャッシュを有効にしていなければ意味がありません。

最低限以下の設定を .zshrc に書いておいて下さい。

zstyle ':completion:*' use-cache yes

補完関数を作る予定のない方でも、キャッシュを有効にしておいた方が良いかと思います。
(といってもキャッシュに対応した補完関数はあまり多くありませんが)

キャッシュの保存場所について

キャッシュは ~/.zcompcache ディレクトリ配下に、キャッシュ毎にファイルが作られます。

今回の場合、grunt という名前でキャッシュファイルが作られるはずです。
キャッシュファイル名は、実装者が自由に決めることができます。

$ ls ~/.zcompcache
grunt

キャッシュファイルの中には、変数名とその値が書かれていて、
ファイルをそのまま source すればキャッシュを復元できるような形式になっています。
キャッシュの復元は専用の関数が用意されているので自身で source する必要はありません

補完関数の全体コード

それでは実装の説明です。
まずは全体のコードを見てみましょう。

以下のコードは実際に動かして動作確認を行うこともできます。
ただし、補完されるオプションやタスクは解説用のダミーになっています。

それでは、コード内の番号が振ってあるところを中心に解説していきたいと思います。

実装解説

1.cache-policy を設定
###############################
#    1.cache-policy を設定
###############################
zstyle -s ":completion:${curcontext}:" cache-policy update_policy
if [[ -z $update_policy ]]; then
    zstyle ":completion:${curcontext}:" cache-policy __grunt_caching_policy
fi

まず先頭の、

zstyle -s ":completion:${curcontext}:" cache-policy update_policy

という構文は、コンテキスト ":completion:${curcontext}:" の スタイル cache-policy の値を
update_policy 変数に設定するという意味になります。
-s は文字列として取得するという意味です。

そして if 文の中にある、

zstyle ":completion:${curcontext}:" cache-policy __grunt_caching_policy

という構文は、cache-policy に __grunt_caching_policy という文字列を設定しています。

コンテキスト や スタイル といった用語は、ここではあまり深く考えずにそういう用語だと思って下さい。

コンテキスト が名前空間、スタイル は キー だと考えると分かりやすいと思います。
難しそうに見えますが、一度自分で使ってみるとすぐに理解できます。

例えば以下のように自分で使用することもできます。
(コンテキストが既存のものと被っていなければ自由に使えます)

# ":hoge:hoge" fuga に something という文字列を設定
$ zstyle ":hoge:hoge" fuga something

# 変数 var に設定されている値を取得する
$ zstyle -s ":hoge:hoge" fuga var

$ echo "$va"
something

このように、zstyle を使用することでグローバル空間を汚染することなく値を保存することができます。

zsh のプラグインを作る場合などに、設定値を保持するのに利用すると良いでしょう。
グローバルなシェル変数や環境変数を使用するよりスマートです。

話を戻します。

cache-policy に設定した __grunt_caching_policy という文字列は、キャッシュが有効かどうか
判別するのに使用する関数の名前です。自分で定義した関数の名前を設定しています。

この関数の中身やこれがいつ呼ばれるかなどについては、また後で説明します。

2.キャッシュの復元と更新を行う
########################################
#    2.キャッシュの復元と更新を行う
########################################
# グローバル変数 __grunt_tasks にタスク情報が設定される
if __grunt_retrieve_update_cache; then
    update_msg='(cache updated)'
fi

__grunt_retrieve_update_cache 関数を実行すると、 グローバル変数 __grunt_tasks にタスク情報が設定されるようになっています。

詳しくは後述しますが、まずは全体の流れを知ってもらいたいので、ここでは __grunt_tasks 変数にタスク情報が設定される、ということだけ理解しておいて下さい。

また、この関数はキャッシュを更新した場合に戻り値が真になるようになっています。

update_msg 変数は、キャッシュが更新されたことをユーザに知らせるため、補完を表示するときに使用します。
必須ではありませんが、デバッグにも役立つのでおすすめです。
(ホントはデバッグ用に使ってたんだけど、便利だったので本実装にも残したってだけなんですけど)

3.タスク補完
######################
#    3.タスク補完
######################
case $state in
    tasks)
        ### 3.タスク補完
        # __grunt_tasks 変数と _describe 関数を使用してタスクを補完
        _describe "grunt task$update_msg" __grunt_tasks || return 1
    ;;
esac

ここでは、__grunt_tasks 変数と _describe 関数を使用してタスクを補完します。

_describe 関数は zsh が提供している関数で、第1引数に補完グループ名を、第2引数に補完情報の入った変数の変数名を指定します。

グループ名は自由につけることができます。

$ grunt [Tab]
 -- grunt task (cache updated) --     << ここに補完グループ名が表示される
clean  -- Clean files and folders
fuga   -- fuga task
hoge   -- hoge task
4.キャッシュの復元と更新

続いて、後述すると言った __grunt_retrieve_update_cache 関数の説明をします。
おそらく一番重要な部分です。
キャッシュの種類が増えたり、キャシュの更新/復元条件が複雑になると、実装が難解になってきます。

############################################################
#    4.キャッシュの復元と必要ならキャッシュの更新を行う
############################################################
#     キャッシュファイル名: grunt
#     キャッシュ変数名: __grunt_tasks
function __grunt_retrieve_update_cache() {
    if ( ! (( $+__grunt_tasks )) \
        || _cache_invalid 'grunt' ) \
        && ! _retrieve_cache 'grunt'; then
        ### キャッシュの更新が必要
        # 新たに grunt のタスク情報を取得
        __grunt_tasks=(${(f)"$(__grunt_get_tasks)"})
        ### キャッシュを保存
        _store_cache 'grunt' __grunt_tasks
        return 0
    fi
    return 1
}

まず、

if ( ! (( $+__grunt_tasks )) \
    ....
fi

という構文は、__grunt_tasks 変数が定義されているかどうかを判別しています。
$+__grunt_tasks は $+ に続く変数が定義されていれば 非0 を、定義されていなければ 0 を返します。
そして、( ( ... ) ) は算術式評価といって、中の式が 非0 なら "真"、0 なら "偽" になります。

よってこの構文は、__grunt_tasks 変数が未定義なら "真" となります。

続いて、

_cache_invalid 'grunt'

という部分は、キャッシュが無効かどうかを判別しています。
_cache_invalid 関数は zsh が提供する関数で、引数に指定したキャッシュが 無効なら "真"、有効なら"偽" を返します。

引数に指定するキャッシュ名は自由に決めることができます。
そして、このキャッシュ名が前述の キャッシュファイル名 として利用されます。

続いて、

! _retrieve_cache 'grunt'

という部分は、名前の通りキャッシュを取得(復元)しています。
引数にキャッシュ名を指定し、キャッシュが有効なら復元され戻り値が "真" となります。

例え _cache_invalid が偽を返したとして(キャッシュが有効でも)、ユーザがキャッシュ機能を無効にしていた場合には、キャッシュの復元に失敗します。
そのため、戻り値のチェックを行なっています。

結局、キャッシュが復元出来なければ if 文の中が実行されるようになっています。
(ちょっとトリッキーな書き方ですが、この書き方が一番簡潔かと思います)

続いて、if 文の中身についてです。

### キャッシュの更新が必要
# 新たに grunt のタスク情報を取得
__grunt_tasks=(${(f)"$(__grunt_get_tasks)"})
### キャッシュを保存
_store_cache 'grunt' __grunt_tasks
return 0

キャッシュが利用できないので grunt のタスク情報を新たに取得します。
そして、取得したタスク情報を、

_store_cache 'grunt' __grunt_tasks

という部分でキャッシュとして保存しています。
第1引数にキャッシュ名を、第2引数以降に保存する変数名を指定します。

キャッシュを保存すると、キャッシュファイル(~/zcompcache/grunt) が作られます。
中身は以下のようになるはずです。

$ cat ~/.zcompcache/grunt
__grunt_tasks=( 'hoge:hoge task' 'fuga:fuga task' 'clean:Clean files and folders' )

そして、前述の _retrieve_cache 関数でキャッシュを復元すると、_store_cache 関数で指定した変数名の変数にキャッシュが復元されます。
(上記キャッシュファイルが source されると考えると分かりやすいです)

また、今回は1変数しか保存しませんでしたが、_store_cache に複数の変数を渡すこともできます。

_store_cache 'grunt' __grunt_tasks hoge fuga

注意すべき点として、_store_cache 関数は常に新しいキャシュを生成するため、複数行に分けて実行することはできません。
複数行に分けて実行した場合は、最後のみ有効になります。(変数名を変えてもダメです)
必要なら別のキャッシュ名を指定しましょう。

最後に、キャッシュを更新したので return 0 で "真" を返しています。

5.cache-policy に設定する関数

cache-poilcy に設定する関数の説明です。

この関数は、_cache_invalid または、_retrieve_cache 関数実行時に、キャッシュが有効かどうかチェックするために呼ばれます。

この関数では、$1 変数にキャッシュファイルのパスが設定されます。
今回の場合は、~/.zcompcache/grunt が設定されるはずです。

また、戻り値が "真" (return 0) ならキャッシュが無効と判断され、"偽" (return 非ゼロ) なら有効と判断されます。

#######################################
#    5.cache-policy に設定する関数
#######################################
#  $1 にキャッシュファイルのパスが入っています
#
#  戻り値:
#    真 (return 0)      : キャッシュ無効
#    偽 (return 非ゼロ) : キャッシュ有効
function __grunt_caching_policy() {
    local -a oldp
    # Nm+7  と指定するとキャッシュの有効期限が 7日 となる
    # Nmw+1 と指定すると 1週間
    # Nmh+1 と指定すると 1時間
    # Nmm+1 と指定すると 1分
    oldp=( "$1"(Nm+7) )
    (( $#oldp ))
}

まず、

oldp=( "$1"(Nm+7) )

という構文についてです。

この中の "$1"(Nm+7) という部分は、グロブ修飾子 (Glob Qualifiers) を用いた ファイル名生成(グロビング) といって、ファイル名の末尾に (Nm+7) のようなグロブ修飾子をつけることで、条件にマッチしたファイル名のみ残すという手法です。

(N) は、条件にマッチするファイルがない場合にエラーとしないグロブ修飾子です。

(m+7) は、ファイルの最終変更日時から7日以上経っているもの、という意味のグロブ修飾子です。

キャッシュファイルが変更されてから7日以上経っていれば、条件にマッチするので "$1" がそのまま残ります。
7日未満なら、条件にマッチしないので空になります。
(このときエラーにしないために、(N) というグロブ修飾子を使っています)

他にも (a+7) でアクセス日時、(c+7) でiノード変更日時をチェックすることができます。

続いて、

oldp=(...)

という部分は、配列を oldp 変数に代入しています。
これは、ファイル名生成(グロビング) を実行するためにこういう書き方をしています。

これで、キャッシュファイルが変更されてから7日以上経っていれば、oldp 配列にキャッシュファイル名が設定されるようになります。

最後に、

(( $#oldp ))

という部分です。
これはすでに紹介した算術式評価の構文で、oldp 配列の length が 非0 なら "真"、0 なら "偽" となります。

つまり、キャッシュファイルが変更されてから7日以上経っていれば、oldp 配列にキャッシュファイル名が設定されるので length が 1 となり、算術式評価の結果が "真" となります。

そして、関数内で return 文を省略すると暗黙の return が実行され、最後に評価した式の戻り値が関数全体の戻り値となります。

これは、単に return と書いた場合や、return $? と書いた場合と同じ意味になります。

実装説明終わり

実装の説明は以上です。

いかがでしたでしょうか?
少しでも理解の助けになれば幸いです。

補完関数を書く上で参考になりそうなリンク

最後に、補完関数の基本を理解するのに役立ちそうな記事のリンクを張っておきます。

他におすすめの記事などあれば教えてください。

それと、以下の書籍 "zshの本" が超絶おすすめです。
キャッシュに関しては残念ながら記述はありませんでしたが、それ以外ならだいたい書いてます。
(索引が弱いのだけが難点)

zshの本 (エッセンシャルソフトウェアガイドブック)

広瀬 雄二 技術評論社 2009-06-17
売り上げランキング : 231694
by ヨメレバ

用語やフラグを調べたい場合は、以下の方法がおすすめです。

おわり

キャッシュ機能が必要になるケースは稀かもしれませんが、もし必要になった時にはこの記事を思い出して頂ければと思います。

あと、実際の grunt 補完をご利用になりたい方は、以下の最新版をご使用下さい。

解説用のサンプルと比べるとかなり複雑になっています。
興味のある方は解析してみて下さい。

以上で解説は終わりです。

質問や、もっとこの辺を詳しく書いて欲しいなどありましたら、お気軽にお尋ねください。

シェルスクリプトのデバッグは typeset または declare を使うと良いかも

はじめに

つい最近知った便利なデバッグ方法
(長年シェルスクリプトを書いているのに知らなかった。これが常識だったら恥ずかしい…)

シェルスクリプトのデバッグでは echo で変数の中身を見るという原始的な方法をよく使うかと思います。
いわゆる プリントデバッグ というやつですね。

もう少し詳しいデバッグが必要な場合は、 set -x と set +x でデバッグしたい部分を囲むという方法もあります。

今回は プリントデバッグ で使う echo の代わりに typeset or declare を使うと良いというお話です。

プリントデバッグは typeset or declare を使おう

typeset or declare は変数宣言などでよく使うコマンドですが、変数の中身を見るのにも使えます。

echo と比べて何が良いのかというと、変数の中身はもちろん変数名や変数の型も表示してくれ、配列の場合にも良い感じに表示してくれるのです。

わざわざ echo "hoge=$hoge" とか echo "hoge=${hoge[@]}" などとしなくても良い。

typeset or declare はビルトインコマンドなので使用するシェルによって若干の違いがあります。
今回は私がよく使う sh/bash と zsh について触れます。
(sh と bash は今回の場合は同じなので区別しません)

sh/bash

bash では、typeset は obsolete となっています。
declare が使用できる環境では declare を使うと良いでしょう。
(typeset の方が馴染み深いかもしれませんが)

## 文字列
$ str='This is a pen.'

$ declare -p str
declare -- str="This is a pen."


## 配列
$ array=('This is' a pen.)

$ declare -p array
declare -a array='([0]="This is" [1]="a" [2]="pen.")'

変数名や型が表示されていて、配列も見やすく整形されているのが分かりますね。

zsh

zsh では typeset と declare は全く同じです。

## 文字列
$ str='This is a pen.'

$ typeset str
str='This is a pen.'

$ typeset -p str
typeset str='This is a pen.'


## 配列
$ array=('This is' a pen.)

$ typeset array
array=('This is' a pen.)

$ typeset -p array
typeset -a array
array=('This is' a pen.)

# 配列内のデータが多い場合などは以下のようにして改行区切りで表示させると良いでしょう
# j フラグについては後述
$ echo "${(j:\n:)array[@]}"
This is
a
pen


## 連想配列
$ typeset -A associative
$ associative=(key1 val1 key2 val2)

$ typeset associative
associative=(key1 val1 key2 val2 )

$ typeset -p associative
typeset -A associative
associative=(key1 val1 key2 val2 )

zsh だと 型情報なしですが -p オプションを付けなくても表示されるので、タイプ数が少なくてすみますね。

(連想配列の表示はもう少し良い感じに表示してくれても良いのではと思わなくもない。
というか、配列もbashの方が分かりやすいような気も…)

それと、気づいた人もいるかもしれませんが、typeset or declare の出力をそのままファイルに保存して、あとでそのファイルを source することでデータを復元することができます。(sh/bash, zsh ともに可能)
(というか元々こういう用途なのかもしれない)

シリアアライズのようなものですね。

色々と使い道がありそうです。

おまけ - zsh の変数展開のデバッグについて

ここからはちょっと濃い話になります。
zsh を使わない方でも、zsh の凄さが分かるので、処理結果だけでも見てみて下さい。

zsh には、フラグを使った変数展開という機能があります。

とても便利な機能なのですが、デバッグするのが非常に大変です。
見慣れてない人だと、場合によっては発狂しかねません。

そこで今回紹介するのが、変数展開の q フラグです。

実際に例を見てみましょう。

例えば、以下の様な複数行のカンマ(,)区切りのデータがあるとします。

$ data='1,2,3
a,b,c
höge,fuga,piyo'

$ echo "$data"
1,2,3
a,b,c
höge,fuga,piyo

このデータを改行で分割したい。
→ f フラグを使うと改行で分割できます。

$ echo "${(f)data}"
1,2,3 a,b,c höge,fuga,piyo

これで改行で分割できました。出来てるはずです。

…でもこれじゃ改行は消えてるけど、どこで分割されてるのか分からないですよね。

では、qフラグを使ってみます。

$ echo "${(qqqf)data}"
"1,2,3" "a,b,c" "höge,fuga,piyo" 

分割された部分がダブルコーテーションで囲われて分かりやすくなっていますね。
これが q フラグです。

さらにカンマでも分割したい。
→ j フラグ(join)を使うと、j:,: のように書いて、要素をカンマ(,)で結合できます (任意の文字でも可)
→ s フラグ(split)は s:,: のように書いて、要素をカンマ(,)で分割できます (任意の文字でも可)

$ echo "${(j:,:s:,:qqq)${(f)data}}"
"1" "2" "3" "a" "b" "c" "höge" "fuga" "piyo"

いかがでしょう。
非常に分かりやすいですよね。

最後に応用編です。

for文で1個ずつ処理をしたい場合。

$ for val in "${(j:,:s:,:)${(f)data}}"; do echo "Hello $val san."; done
Hello 1 san.
Hello 2 san.
Hello 3 san.
Hello a san.
Hello b san.
Hello c san.
Hello höge san.
Hello fuga san.
Hello piyo san.

行ごとに & カラムごとに別の処理をしたい。

i=0
for row in "${(f)data}"; do
    (( i++ ))
    echo -n "$i: "
    uppers=()
    for val in "${(s:,:)row}"; do
        uppers+=("${(U)val}")
    done
    echo "${(j:, :)uppers}"
done

# 結果 (行番号を入れつつ、大文字に変換してみました)
# 1: 1, 2, 3
# 2: A, B, C
# 3: HÖGE, FUGA, PIYO

※ 上記の例では qqq を使用しましたが、q の数によって使用されるコーテーションが変わります。
q が1つの場合はバッククォート(`)、2つの場合はシングルコーテーション(')、3つの場合はダブルコーテーション()"、4つの場合は $' ' でクォートされます。

このように zsh はとても高機能です。
外部コマンドを使わずとも、シェルの機能だけでこれだけのことが出来てしまいます。
今回紹介したものも、ほんの一部にすぎません。

みなさんも対話シェル (Interactive shell) としてだけでなく、シェルスクリプトでも zsh を使ってみてはいかがでしょうか。

zsh についてもっと詳しく知りたい方は、以下の書籍 "zshの本" が超おすすめです。
zsh でシェルスクリプトを書かない方でも、zsh ユーザなら絶対に持っておきたい1冊です。
zsh の代名詞である補完関数についても詳しく書かれています。


zshの本 (エッセンシャルソフトウェアガイドブック)

広瀬 雄二 技術評論社 2009-06-17
売り上げランキング : 231694
by ヨメレバ

おわり

最後は zsh の宣伝になってしまいましたが、最低限 typeset or declare については覚えておいて下さい。

それと、zsh 好きな方は是非お友達になりましょう!

Vim Advent Calendar 2012 に"はてブ数"を表示させるグリモンとブックマークレットを作ったよ!

Vim Advent Calendar 2012 の197日目の記事です。

前回(196日目)の記事は @supermomonga さんの homebrewを使ってちょっと新しめのMacVim KaoriYaを使おう - かなりすごいブログ でした。

まえおき

ついに中間発表を終え、後半戦へと突入したVim Advent Calendar 2012

参加者も90人を越え、200日目も目前となって参りました。

しかし!!
あまりにも記事が多すぎて、「どれから読めばいいんだ!」とか「もしかし見逃してるんじゃ?」とか「やだ、私のVim力低すぎ…」などと不安になっている方もいるのではないでしょうか。

そこで、そんな不安を吹き飛ばすため、
Advent Calendar のページにはてなブックマーク数を表示する Greasemonkey (グリースモンキー) と ブックマークレット を作ってみました。

f:id:yonchu:20130614193818p:plain

Greasemonkey版とブックマークレット版の2種類がありますが、ランキング表示が行えるのはGreasemonkey版のみです。

Greasemonkey版のインストール方法

まずスクリプトを以下からダウンロードして下さい。
(Chromeの場合ユーザスクリプトをダウンロードすると警告が出ますが気にしないでください)

続いて各ブラウザにスクリプトをインストールします。

Chromeの場合

ダウンロードしたスクリプトを拡張機能の管理ページ(chrome://extensions/)にドラッグ&ドロップして下さい。
(関係ないけど、拡張機能の管理ページをブックマークバーに追加しておくとすぐにアクセスできるのでおすすめです。)

FireFoxの場合

FireFoxの場合は、Greasemonkeyを使用するために以下のAdd-On が必要になります。
インストールしていない方はまずそちらをインストールしてください。

それから、ダウンロードしたスクリプトをFireFoxへドラッグ&ドロップし、Greasemonkeyの管理画面で有効化を行います。

ブックマークレット版のインストール方法

以下のリンクをブックマークに追加してください。
もしくは、コードをコピーして手動で新しいブックマークを作成して下さい。

javascript:(function(){var s=document.createElement("script");s.charset="UTF-8";s.src="https://github.com/yonchu/atnd-hatena-bookmarks/raw/master/atnd-hatebu-min.user.js";document.body.appendChild(s)})();


スクリプトをサーバから読み込まないバージョンも用意しました。

javascript:(function(){var t,e,n,r,a,i,o,d,l,c,u,m,f,h,p,s,y;try{if(top!==self){throw 0}}catch(b){i=b;return}t=function(t){var e,n;if(typeof GM_addStyle!=="undefined"&&GM_addStyle!==null){GM_addStyle(t);return}n=document.createElement("style");n.setAttribute("type","text/css");n.setAttribute("media","screen");n.appendChild(document.createTextNode(t));e=document.getElementsByTagName("head")[0];return e.appendChild(n)};r=function(){var t,e;t="http://b.st-hatena.com/entry/image/";e=document.createElement("img");e.className="hatebu";return function(n){var r;r=e.cloneNode();r.setAttribute("src",t+n);return r}}();a=".hatebu{padding-bottom: 2px !important; margin-left: 5px !important;}";t(a);u=document.querySelectorAll("#post-body table tr");for(f=0,p=u.length;f<p;f++){c=u[f];e=null;y=c.children;for(h=0,s=y.length;h<s;h++){l=y[h];n=l.firstChild;if(!n){continue}d=n.tagName;if(!(d&&d==="a"||d==="A")){continue}e=n;break}if(!e){continue}m=e.href;if(!m){continue}o=r(m);l.appendChild(o)}})();


インストール作業はこれだけです。

あとは Vim Advent Calendar 2012 のページを開き、
Greasemonkey版なら何もしなてくも、ブックマークレット版ならブックマークレットを実行すれば、ブックマーク数が表示されます。
ランキング表示は若干時間がかかります。
(ランキングの同一順位を考慮してないのでそこは多めに見てほしい。)

ちなみに、ATNDの他のイベントページでも Vim Advent Calendar と同じようなテーブルレイアウトを使用している場合はブックマーク数を表示することができます。
Vimmer以外の方もインストールしておけば幸せになれるかもしれません。

※ 動作確認は、Chrome/FireFox/Safari にて行いました。IEは知りません。

注意

ブックマークレット版では、一部の記事でブクマ数が正常に表示されません。

記事執筆後に "はてなダイヤリー" から "はてなブログ" へ移行したが、VACのURLがはてなダイヤリーのままになっているためと思われます。はてなブックマークのAPIはリダイレクトに対応していないようです。

Greasemonkey版ではリダイレクトの解決を自身で行うよう対応しています。
インストールが面倒でなければGreasemonkey版をお使い下さい。

技術的な話

ソースコードは以下にて公開しています。
不具合報告などありましたらよろしくお願いします。

制作時間は、ブックマークレット版が 約15分。
Greasemonkey版は3時間ぐらい。(リダイレクト関連で結構悩みました)
JavaScript は CoffeeScript で書いています。

Greasemonkeyはひな形を用意しておくことで、比較的短時間で作成することができます。
Chrome Extension なんかより簡単に作れるのでおすすめです。

しかし、欠点としてGreasemonkeyは自動更新が行えません。この縛りは結構つらいです。
幸いGreasemonkeyをChrome拡張に変更するのは非常に簡単なので、今回のGreasemonkeyも、もし需要があるようならChrome拡張版を用意しようかと思います。

ブックマークレット版は、あらかじめGreasmonkey版を作り、動作確認を行なっておくことで、スムーズに作成することができます。
サーバ読み込みバージョンは、サーバ上のGreasemonkeyを読み込んでいるだけです。
非サーバ読み込みバージョンは、GreasemonkeyをUglifyJSを使ってMinify(圧縮)しただけです。
簡単ですね。

Vimは関係ありませんが、思いついたちょっとしたアイディアをすぐに形にできるよう、
みなさんも Greasemonkey と ブックマークレット のひな形を用意してはいかがでしょうか。


以上、
Vim Advent Calendar 2012 197日目の記事でした。
(Vim script が1行も出てこなくてごめんなさい。)

明日 198日目は、 @deris0126 さんです。

vimの "set guifont" に設定するフォント名について (Mac限定)

"set guifont" に設定するフォント名には何を指定すればいいのかという話。
よく忘れるのでメモっとく。ただしタイトルの通りMac限定です。

手順

まず、"Font Book" というアプリケーションを起動します。

続いて、メニューの [プレビュー] から [フォント情報を表示] を実行します。
(英語表記だと [Show Font Info] )

そして、使用するフォントを選択すると以下のように表示されます。

f:id:yonchu:20130519013149p:plain

この中の右ウィンドウに表示されている "PostScript name" が "set guifont" に指定する名前になります。

よってこの場合は、以下のように設定します。

set guifont=Ricty-RegularForPowerline:h14

"h14" はフォントサイズです。

また、名前にスペースが含まれている場合は、"¥ " のようにエスケープしてあげる必要があります。