トップ 追記

活動日誌


2012-03-06

[zsh] GitやMercurialのワークツリーのルートに下線を引く

2012-03-06-vcs-info.gif

今使っている zsh の右プロンプトにはカレントディレクトリを表示しているのですが、 Git や Mercurial のワークツリー(ワーキングディレクトリ)の中にいるときは、そのルートディレクトリに下線を引くようにしています。

これがなかなか気に入っているので紹介します。

以下では主要な部分だけ抜き出して解説しています。 zsh 設定ファイルの全体は github にアップしています。https://github.com/kyanagi/dot.zsh.d

まず、vcs_info の設定で formats に %r を設定しておき、リポジトリ名を取得できるようにします。 次の例だと、$vcs_info_msg_2_ で取得できるようになります。 http://zsh.sourceforge.net/Doc/Release/User-Contributions.html#Configuration

zstyle ':vcs_info:*' formats '%F{white}%c%u%s%f%F{white}:%f%F{green}__branch-name__%f' '%b' '%r'

次に、RPROMPT の設定です。

local rprompt
rprompt=(
  "%F{$prompt_color}["
  "\${vcs_info_msg_0_:+\${vcs_info_msg_0_} }%f" # VCS の情報があれば表示
  "%F{$prompt_color}"
  # $PWD は ~ が展開されているので ~ に戻し、リポジトリ名の部分に下線を付ける。
  # リポジトリ名は $vcs_info_msg_2_ に入っている。
  "\${\${PWD/#\$HOME/~}/\${vcs_info_msg_2_}/%U\${vcs_info_msg_2_}%u}"
  " %*]%f"
)
RPROMPT=${(j..)rprompt}

rprompt に配列を作ってから連結しているのはコメントを書くためです。 (j.. については http://zsh.sourceforge.net/Doc/Release/Expansion.html#Parameter-Expansion-Flags を参照)

いろいろと書いていますが、今回の記事に関係するのは

"\${\${PWD/#\$HOME/~}/\${vcs_info_msg_2_}/%U\${vcs_info_msg_2_}%u}"

の部分です。

以下ではこの内容をもう少し詳しく説明します。

プロンプトに変数の内容を表示する

右プロンプトに $PWD の値を出したいとします。

RPROMPT="$PWD"

とすると、(このコマンドを入力したときのカレントディレクトリが /var/tmp として)実際には

RPROMPT=/var/tmp

と展開されて実行されるので、その後ディレクトリを移動しても表示は常に /var/tmp のままになります。

右プロンプトの表示ごとにその瞬間の $PWD を表示するには、RPROMPT に「$PWD」という文字列を設定する必要があるので

RPROMPT="\$PWD"

としなくてはいけません。

設定解説

以上をふまえた上で、実際に右プロンプトの設定内容を見てみます。

~/tmp に tdiary-core をチェックアウトし、tdiary-core/spec/core に移動した状況を考えます。

各変数の内容は以下のような感じです。

変数 内容
$PWD /Users/ani/tmp/tdiary-core/spec/core
$HOME /Users/ani
$vcs_info_msg_2_ tdiary-core

まず、$PWD は ~ が展開されているので ~ に戻します。

${PWD/#$HOME/~} ~/tmp/tdiary-core/spec/core

(${name/pattern/repl} は name の pattern を repl に置換して展開するという意味です。# で始まるパターンは文字列の先頭を意味します。 http://zsh.sourceforge.net/Doc/Release/Expansion.html#Parameter-Expansion

次に、リポジトリ名 tdiary-core を下線付きにします。 リポジトリ名は $vcs_info_msg_2_ に入っています。 プロンプトで下線を引くには %U ... %u で囲います。

よって、$vcs_info_msg_2_ を %U${vcs_info_msg_2_}%u で置換します。

${${PWD/#$HOME/~}/${vcs_info_msg_2_}/%U${vcs_info_msg_2_}%u} ~/tmp/%Utdiary-core%u/spec/core

最後に、これを右プロンプトの表示ごとに解釈するため、$ をエスケープします。

\${\${PWD/#\$HOME/~}/\${vcs_info_msg_2_}/%U\${vcs_info_msg_2_}%u}

これで当初の設定どおりとなります。

なお、リポジトリ名と同じ名前のディレクトリがワークツリーより上にあった場合、そちらの方に下線が引かれてしまいます。 しかしこれはレアケースだと思いましたので、簡単のため特に対応していません。 (真面目にやるなら vcs_info formats の %R でフルパスが取れるので、それを使えば対処できると思います)

追記

RPROMPT の内容は以下のように修正しました。

"${${${PWD/#\$HOME/~}/\/${vcs_info_msg_2_}\///%U${vcs_info_msg_2_}%u/}/%\/${vcs_info_msg_2_}//%U\${vcs_info_msg_2_}%u}"

リポジトリ名が foo であるとき、カレントディレクトリが /foobar/foo だと foobar の foo に下線が引かれていたので、 下線はディレクトリ全体に対して置換するように修正しました。

読みづらいですが、リポジトリ名を foo とすると、まず /foo/ を /%Ufoo%u/ に置換し、 次に文字列末尾の /foo を /%Ufoo%u に置換しています。


2012-03-03

[Emacs] マウスでウィンドウの大きさを調整する

最近気付いたのですが、1つのフレームが上下に分割されているとき、 モードラインをドラッグしてウィンドウの大きさを調節することができます。 モードラインの要素にはクリックイベントが設定されているものがあるので、 空いているところをドラッグする必要があります。

2012-03-03-emacs.jpg

コマンドで調整するには enlarge-window を使います。

左右分割では、どうやらスクロールバーを表示しているときはドラッグで調節できないっぽいです。


2012-03-02

[Emacs] anything-minibuffer-history でのアクションは、ミニバッファの置き換えにする

anything-minibuffer-history(ミニバッファで C-r)はアクションが insert になっています。 しかしこれはミニバッファの現在の入力を置き換えた方が便利だと思います。

次のようにすると、現在のミニバッファへの入力にかかわらず、ヒストリの内容で置換されるようになります。


2012-03-01

[zsh] ^ で上のディレクトリに移動するのは、入力がないときだけにする

zsh を使っている方には、次のような設定を入れている方も多いと思います。

function cdup() {
  echo
  cd ..
  zle reset-prompt
}
zle -N cdup
bindkey '\^' cdup

これは ^ で上のディレクトリに移動できるようにする設定です。

普通に ^ を入力したいときは C-v ^ と入力するのですが、 テキストをコピペでターミナルに貼り付けたとき、テキストに ^ が混ざっていて意図しない結果になることが何度かありました。

この問題を改善するため、次のように変更しました。

function cdup-or-insert-circumflex() {
  if [[ -z "$BUFFER" ]]; then
    echo
    cd ..
    zle reset-prompt
  else
    zle self-insert '^'
  fi
}
zle -N cdup-or-insert-circumflex
bindkey '\^' cdup-or-insert-circumflex

これで、入力がないときは上のディレクトリに移動し、それ以外の場合は ^ が入力されるようになります。


2012-02-17

[Emacs] scratch バッファの便利な設定をまとめた scratch-ext.el を作りました

scratch バッファの便利な設定をまとめた scratch-ext.el を作りました。

このファイルを読み込むと

  • scratch バッファの kill は単にバッファの中身を消すだけにする。
  • scratch バッファをファイルに保存すると、新たに scratch バッファを作る。
  • scratch バッファを kill するか Emacs が終了する時点で、scratch バッファの内容を自動的にファイルに保存する。
  • 一番新しいログをバッファに読み込む

といったことができるようになります。

github で公開していますので、どうぞご利用ください。

https://github.com/kyanagi/scratch-ext-el

参考

*scratch* バッファを消さないようにする:長年利用していた設定です。バッファの自動保存を仕込むのを機に、同様の機能を再実装することにしました。


2012-02-13

[Emacs]anything を導入

これまでEmacsではanythingを使っていなかったのですが、 ふと思い立ってanythingを入れてみることにしました。 (正確に言うと何度か手を出してみたことはあったがすぐやめてしまった)

まだ触り始めたばっかりですが、とまどった点などを中心に書いておきます。

現在の設定は以下のとおり。

ミニバッファでC-hで文字を消せない

入力を修正しようと思って C-h を連打すると大変なことになってしまうので、 C-h は backward-kill-word に割り当て直しました。

最初 anything-map だけに設定していて、思い通りの動作にならずに迷いました。

ついでに C-w で単語削除できるようにもしてあります。

ウィンドウ表示

popwinと組み合わせようとしましたが、ミニバッファの履歴検索が動かなくなったので外しました。 このへんはきちんと調べていないので、ちゃんとやれば動くかもしれません。

バッファに対しては、カーソルを合わせただけで中身を表示する

anything ウィンドウでバッファを選ぶときは C-z を押さないと中身を見ることができません。

これまで使っていた iswitchb では、選択を確定する前に選択中のバッファを表示するようにしていたので、 この機能はぜひ欲しいと思っていました。

試してみた結果、anything-move-selection-after-hook で表示してうまくいってます。

auto-install-compatibility-setup

あとここには書いてないですが、auto-install-compatibility-setup が anything を読み込むというのに気付かなくて ちょっとはまってました。まあもういらないかなとも思ったので auto-install-compatibility-setup は外しました。


2012-01-27

[zsh]zsh の vcs-info を Cygwin で高速化する

zsh には vcs-info というものがあり、これを利用すると Git や Mercurial のブランチ名などをプロンプトに表示することができます。 (例: http://d.hatena.ne.jp/mollifier/20090814/p1

しかし使ってみるとわかるのですが、Cygwin だと結構遅いです。 シェルのプロンプトが表示されるたびにちょくちょく待たされる感じになってしまい、かなりストレスを感じます。

どうにかならないものかと思っていたのですが、ひとまず実用上問題なさそうなところまで高速化できたので共有しておきます。 (私が Mercurial メインで使っているので、Mercurial を使う際の高速化が中心です。Git だとまだ改善の余地が多いかと思います)

第一に:使っていないバージョン管理システムは外す

vcs_info はたくさんのバージョン管理システムに対応していますが、 現在のディレクトリがそれぞれのシステムに対応しているか調べるため、 多くのシステムを有効にしていると重くなってしまいます。

デフォルトでは全部有効になっているので、使うものだけを指定するようにします。

 zstyle ':vcs_info:*' enable hg git

ここでは Mercurial と Git を指定しています。 ここに書かれた順にチェックがされるので、Mercurial の作業コピーで作業することが多い人は、 このように hg を先に書いた方がレスポンスが速くなります。

なぜ遅いか

調べてみたところ、Cygwin だとコマンド置換 $(...) が遅いのが一番のネックになっているようです。 例えば私の環境では

 zsh -fc 'repeat 100 $()'

が、Linux(Debian) では 0.04 秒ほどで終了するのに対し、Cygwin では 4 秒弱かかりました。

そこで、なるべくコマンド置換をしないように修正します。

対処方法

 --- /usr/share/zsh/4.3.12/functions/VCS_INFO_bydir_detect       2011-08-08 04:59:41.001000000 +0900
 +++ ./VCS_INFO_bydir_detect     2012-01-19 21:52:35.293434600 +0900
 @@ -6,7 +6,7 @@
  local dirname=$1
  local basedir="." realbasedir file

 -realbasedir="$(VCS_INFO_realpath ${basedir})"
 +realbasedir="${basedir:A}"
  while [[ ${realbasedir} != '/' ]]; do
      [[ -r ${realbasedir} ]] || return 1
      if [[ -n ${vcs_comm[detect_need_file]} ]] ; then
 @@ -20,7 +20,7 @@
      fi

      basedir=${basedir}/..
 -    realbasedir="$(VCS_INFO_realpath ${basedir})"
 +    realbasedir="${basedir:A}"
  done

  [[ ${realbasedir} == "/" ]] && return 1

現在のディレクトリが Mercurial 管理下にあるかどうかを調べるため、 .hg ディレクトリがあるかどうかを現在のディレクトリからルートディレクトリまで順に探しています。

../ 混じりのパスを実際のパスに直すため VCS_INFO_realpath という関数を使っているのですが、 これは変数展開の A 修飾子でできるのでそちらを使います。

 --- /usr/share/zsh/4.3.12/functions/VCS_INFO_formats    2011-08-08 04:59:41.001000000 +0900
 +++ ./VCS_INFO_formats  2012-01-20 02:42:04.744074700 +0900
 @@ -29,7 +29,16 @@
  )
  hook_com[base-name]="${${hook_com[base]}:t}"
  hook_com[base-name_orig]="${hook_com[base_name]}"
 -hook_com[subdir]="$(VCS_INFO_reposub ${hook_com[base]})"
 +
 +# コマンド置換が遅い Cygwin で高速化するために VCS_INFO_reposub を展開
 +#hook_com[subdir]="$(VCS_INFO_reposub ${hook_com[base]})"
 +local base=${hook_com[base]%%/##}
 +if [[ ${PWD} == ${base}/* ]]; then
 +  hook_com[subdir]=${PWD#$base/}
 +else
 +  hook_com[subdir]='.'
 +fi
 +
  hook_com[subdir_orig]="${hook_com[subdir]}"

  VCS_INFO_hook 'post-backend'

VCS_INFO_reposub はここでしか使われていなかったので、中身を展開してしまいました。

Mercurial だけを使うならここまででいいのですが、とりあえず Git に対しても vcs-info を使うようにしていたところ、 特にバージョン管理下にないディレクトリにいるときに重い状態でした。

これは、バージョン管理下にないディレクトリに対しては、Mercurial のワーキングコピーであるかどうかのチェックと Git のワーキングコピーであるかどうかのチェックが両方走っていて、Git のチェックが重かったのが原因でした。

よって次の修正を加えています。

 --- /usr/share/zsh/4.3.12/functions/VCS_INFO_detect_git 2011-08-08 04:59:46.001000000 +0900
 +++ ./VCS_INFO_detect_git       2012-01-23 17:40:41.272189100 +0900
 @@ -6,8 +6,10 @@

  [[ $1 == '--flavours' ]] && { print -l git-p4 git-svn; return 0 }

 -if VCS_INFO_check_com ${vcs_comm[cmd]} && ${vcs_comm[cmd]} rev-parse --is-inside-work-tree &> /dev/null ; then
 -    vcs_comm[gitdir]="$(${vcs_comm[cmd]} rev-parse --git-dir 2> /dev/null)" || return 1
 +if VCS_INFO_check_com ${vcs_comm[cmd]} ; then
 +    local gitdir
 +    ${vcs_comm[cmd]} rev-parse --git-dir 2> /dev/null | read gitdir || return 1
 +    vcs_comm[gitdir]=$gitdir
      if   [[ -d ${vcs_comm[gitdir]}/svn ]]             ; then vcs_comm[overwrite_name]='git-svn'
      elif [[ -d ${vcs_comm[gitdir]}/refs/remotes/p4 ]] ; then vcs_comm[overwrite_name]='git-p4' ; fi
      return 0

現在のディレクトリが Git の管理下にあるかどうかを調べているのですが、 git rev-parse --git-dir の戻り値をチェックすれば git rev-parse --is-inside-work-tree は不要だと思うので前者だけにしました。 コマンド置換が read になっているのは、ほぼ気分の問題です。(微妙に速くなってる気もしますが、大して変わりません)

おまけ

use-simple true の設定にするときは hexdump を忘れずに入れるようにしましょう。これがないと速くなりません。util-linux パッケージにあります。 (ただし、check-for-changes を有効にするときは use-simple false でないといけません)

まとめ

Cygwin 上で zsh の vcs_info の高速化を試みました。

  • vcs_info は使うシステムに対してのみ有効化すべきです。
  • Cygwin ではコマンド置換が遅いのでなるべく使わないようにすると速くなります。

この修正を加えたスクリプトは https://github.com/kyanagi/faster-vcs-info にあります。(zsh 4.3.12 のスクリプトを修正したものです)

使う際は適当なディレクトリに置いて、そのディレクトリを$fpath の頭の方(システムの vcs_info より優先されるように)に加えてください。


2012-01-09

[Emacs]find-fileで *Completions* バッファに ../ と ./ を出さない

C-x C-f (find-file) でファイルを開くとき、ディレクトリの先頭で補完を行うと補完対象の最初に ../ と ./ が表示されます。

これは邪魔でしかないので消せないものかと思っていたのですが、以下のように find-file-read-args を再定義することで除外することができました。


2012-01-01

[Emacs]Emacs23 に移行

普段 Windows ではエディタに Emacs を使っていますが、これまで、intlfonts が好みだったため、Emacs22 を使い続けていました。 (Windows の Emacs23 は BDF フォントが使えないようなので)

しかし、さすがに移行するべきかなということで、思い切って Emacs23.3 にアップデートしてみました。

フォントは、MeiryoKe_Gothic と Inconsolata の組み合わせがなかなかいい感じだったので、以下のように設定しました。

 (set-face-attribute 'default nil :family "Inconsolata" :height 150)
 (let ((fn (frame-parameter nil 'font)))
   (dolist (target '(katakana-jisx0201
                     japanese-jisx0208
                     japanese-jisx0212
                     japanese-jisx0213.2004-1
                     ))
     (set-fontset-font fn target '("MeiryoKe_Gothic" . "iso10646-1"))))
 (setq face-font-rescale-alist
       '((".*MeiryoKe_Gothic.*" . 0.89)
         ("-cdac$" . 1.3)))
 (setq-default line-spacing 2)
 (setq scalable-fonts-allowed t)
 (setq w32-enable-synthesized-fonts t)

メイリオの大きさは、英数字の行に日本語が混ざっても高さが変化しないぎりぎりで設定してあります。全角文字と半角文字の幅は2:1にはなっていませんが、高さが変わらないことの方を優先しました。


2010-08-30

Padrino 0.9.15 と ActiveRecord 3.0.0 を組み合わせたときに発生する migration の add_index のエラーを修正する

Padrino 0.9.15 と ActiveRecord 3.0.0 の組み合わせで、migration の add_index でエラーが発生しました。

% padrino rake ar:migrate:reset
...(略)
undefined method `key?' for nil:NilClass
/usr/local/lib/ruby/gems/1.8/gems/padrino-core-0.9.15/lib/padrino-core/cli/rake.rb:9:in `init'
(See full trace by running task with --trace)

調べてみると、add_index の第3引数を書かないと padrino は options に nil を渡すのですが、ActiveRecord 側で nil を渡されると動かないようになっていました。 ひとまず、以下のコードを lib/ar_add_index_fix.rb に置いて対処しました。

module ActiveRecord::ConnectionAdapters::SchemaStatements
  alias orig_add_index add_index
  def add_index(table_name, column_name, options = {})
    orig_add_index(table_name, column_name, options || {})
  end
end

2005|02|03|04|05|06|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|03|04|05|06|10|
2008|04|10|
2009|10|
2010|05|08|
2012|01|02|03|
トップ