zshをtcshなキーバインドで
ログインシェルとしてはもう十何年も tcsh をずっと使って来ていたのですが、All about Ruby on Rails & Data recovery software を素直に動作させるのが難しかったので zsh へ移行することを決意しました*1。
【連載】漢のzsh | マイナビニュースを参考にしてだいたいは違和感なく移行できたのですが、最後までなかなか馴染まなかったのがキーバインディングでした。
最近ようやく tcsh とほぼ同じ感じになってきたので、どう設定したのかを以下にメモしておきます。
M-p と M-n を変更
tcsh の M-p と M-n にはカーソルより左側が一致する履歴をどんどん表示する機能が割り当てられています。そこで zsh では以下のようにしました。
autoload history-search-end zle -N history-beginning-search-backward-end history-search-end zle -N history-beginning-search-forward-end history-search-end bindkey "^[p" history-beginning-search-backward-end bindkey "^[n" history-beginning-search-forward-end
M-f や M-b などの単語を扱う機能の調節
この機能が一番のくせ者でした。結論から言えば、以下を ~/.zshrc に書き、
autoload -Uz select-word-style select-word-style default zstyle ':zle:*' word-chars '*?_-.[]~=' fpath=( ~/.home/zsh $fpath ) autoload -Uz tcsh-forward-word-match zle -N forward-word tcsh-forward-word-match
以下を ~/.home/zsh/tcsh-forward-word-match に書きました。
# modified from /usr/share/zsh/4.3.12/functions/forward-word-match emulate -L zsh setopt extendedglob autoload -Uz match-words-by-style local curcontext=":zle:$WIDGET" word local -a matched_words integer count=${NUMERIC:-1} if (( count < 0 )); then (( NUMERIC = -count )) zle ${WIDGET/forward/backward} return fi while (( count-- )); do match-words-by-style # For some reason forward-word doesn't work like the other word # commands; it skips whitespace only after any matched word # characters. # if [[ -n $matched_words[4] ]]; then # # just skip the whitespace # word=$matched_words[4] # else # # skip the word and trailing whitespace # word=$matched_words[5]$matched_words[6] # fi if [[ -n $matched_words[4] ]]; then # skip the whitespace and the word word=$matched_words[4]$matched_words[5] else # jist skip the word word=$matched_words[5] fi if [[ -n $word ]]; then (( CURSOR += ${#word} )) else return 1 fi done return 0
M-f M-b の各シェルの動作
上記の設定の意味の解説をする前に、まずは tcsh, bash, zsh での動作を確認しておきます。(以下ではカーソル位置はスタイルシートの background-color で表現してありますので、RSS リーダーでご覧の場合には見えないかもしれません)
tcsh の場合 M-f を押すたびに次のようにカーソル(赤い四角)が移動します。
% ls -l /usr/bin % ls -l /usr/bin % ls -l /usr/bin % ls -l /usr/bin % ls -l /usr/bin
逆に M-b を押すたびに次のようにカーソルが移動します。
% ls -l /usr/bin % ls -l /usr/bin % ls -l /usr/bin % ls -l /usr/bin % ls -l /usr/bin
M-f と M-b では停止位置が微妙に違うところがポイントです。
bash の場合 M-f の動作は tcsh と全く同じです。
$ ls -l /usr/bin $ ls -l /usr/bin $ ls -l /usr/bin $ ls -l /usr/bin $ ls -l /usr/bin
しかし M-b の動作は -l
の箇所の停止位置(青い四角)が tcsh とは異なります。
$ ls -l /usr/bin $ ls -l /usr/bin $ ls -l /usr/bin $ ls -l /usr/bin $ ls -l /usr/bin
zsh を select-word-style bash で動作させた場合は、M-f の動作は次のようになります。
% ls -l /usr/bin % ls -l /usr/bin % ls -l /usr/bin % ls -l /usr/bin % ls -l /usr/bin
bash の動作とは全く異なります。逆に M-b を押した場合は次のようになり bash の動作と一致します。
% ls -l /usr/bin % ls -l /usr/bin % ls -l /usr/bin % ls -l /usr/bin % ls -l /usr/bin
また、M-f での停止位置と M-b の停止位置が一致しています。
zsh を select-word-style default で動作させた場合は、M-f の動作は次のようになります。
% ls -l /usr/bin % ls -l /usr/bin % ls -l /usr/bin % ls -l /usr/bin
各引数の最初の文字に停止します。M-b を押した時も停止位置は同じです。
% ls -l /usr/bin % ls -l /usr/bin % ls -l /usr/bin % ls -l /usr/bin
M-f M-b 解説
コマンドラインを構成する文字は単語を構成する文字(w
とする)と単語を構成しない文字(.
とする)の2種類にわけることができます。
すると tcsh と bash の場合のカーソルが停止する位置は、
- M-f の場合はカーソルより右側の
w
と.
の境目 (www...
) - M-b の場合はカーソルより左側の
.
とw
の境目 (...www
)
となります。
zsh の場合は、
となります。
そして単語を構成する文字は以下のようになっています。
tcsh | [:alnum:] と '*?_-.[]~=' |
bash | [:alnum:]*2 |
zsh で select-word-style bash | [:alnum:] |
zsh で select-word-style default | [:alnum:] と '*?_-.[]~=/&;!#$%^(){}<>' |
そこで、まずは zsh の単語を構成する文字を tcsh と一致させるために次のような設定をしました。
autoload -Uz select-word-style select-word-style default zstyle ':zle:*' word-chars '*?_-.[]~='
select-word-style default 時は word-chars に設定した文字に加えて [:alnum:] が単語を構成する文字になりますので、これで tcsh と一致します。
そして M-f の時の動作を変更するために次のような設定をし、
fpath=( ~/.home/zsh $fpath ) autoload -Uz tcsh-forward-word-match zle -N forward-word tcsh-forward-word-match
~/.home/zsh/tcsh-forward-word-match を作成しました。tcsh-forward-word-match はカーソルより右側の w
と .
の境目 (www...
) へカーソルを移動させる関数です。
これでようやく tcsh とほぼ同じ感じで動作するようになりました。
*1:C Shell 系ではなく Bourne Shell 系のシェルを使いたいとずっと思っていたというのもあります
*2:未確認ですがおそらくこうなっています
Objective-C の __block の参照カウンタを調査中…
『エキスパートObjective-Cプログラミング』をBlocksまで読破。ブロックをcopy後は、__block変数の__forwarding先を現在のスコープ(?)が所有しスコープから抜けた時に開放するようにしないと、変数の寿命よりcopy後ブロックが短い場合に困るのでは
2011-11-24 17:58:17 via web
ないかと、そのような記述を探してみたがよくわからなかった。-rewrite-objcはブロック部分だけどC++へ展開するけど、それ以外はobjcのママなのであんまり手がかりにならないし。アセンブリを見るしかない?
2011-11-24 18:00:24 via web
@ganaware copyしたblockの方がスタックよりも寿命が短いケースは実装上想定されてないのではないかと考えています。このへんに動作をまとめていますので参考になるかと思います。 URL URL
2011-11-24 21:49:58 via web to @ganaware
という設定で上記の @splhack さんの記事のコード(以下に再掲)をビルドし、
#import <Foundation/Foundation.h> #import <stdio.h> extern const char *_Block_byref_dump(void *); void dump(int line, int *p) { p -= 4; printf("\ndump line:%d\n", line); puts(_Block_byref_dump(p)); } int *test() { __block int total = 11; dump(__LINE__, &total); void (^block_on_stack)() = ^{ ++total; dump(__LINE__, &total); }; block_on_stack(); printf("\n___ Block_copy ___\n"); void (^block_on_heap)() = Block_copy(block_on_stack); dump(__LINE__, &total); block_on_stack(); block_on_heap(); printf("\n___ Block_release ___\n"); Block_release(block_on_heap); dump(__LINE__, &total); block_on_stack(); return &total; } int main() { dump(__LINE__, test()); }
Assembly を見ると、test() の最後で以下のようなコードが実行されているのが見つかります。
.loc 1 45 1 ## (略)/main.m:45:1 movl -112(%ebp), %eax ## 4-byte Reload movl %eax, (%esp) movl $8, 4(%esp) calll __Block_object_dispose
どうやら __block 変数の __forwarding 先の参照カウントは、Block_copy() した時にスタックからの参照分とヒープから参照分だけカウンタを増やしておいて、Block_release() 時とスコープの終わりに挿入される _Block_object_dispose() 時に減らしているようですね。
https://llvm.org/svn/llvm-project/compiler-rt/trunk/BlocksRuntime/runtime.c
void _Block_object_dispose(const void *object, const int flags) { // (略) if (flags & BLOCK_FIELD_IS_BYREF) { // get rid of the __block data structure held in a Block _Block_byref_release(object); } // (略) }
というわけで
『エキスパートObjective-Cプログラミング』をBlocksまで読破。ブロックをcopy後は、__block変数の__forwarding先を現在のスコープ(?)が所有しスコープから抜けた時に開放するようにしないと、変数の寿命よりcopy後ブロックが短い場合に困るのでは
2011-11-24 17:58:17 via web
ところで、実行してみたところ次のような出力を得ました。
dump line:17 byref data block 0xbffff9c0 contents: forwarding: 0xbffff9c0 flags: 0x0 size: 20 dump line:23 byref data block 0xbffff9c0 contents: forwarding: 0xbffff9c0 flags: 0x0 size: 20 ___ Block_copy ___ dump line:31 byref data block 0x13e450 contents: forwarding: 0x13e450 flags: 0x1000004 size: 20 dump line:23 byref data block 0x13e450 contents: forwarding: 0x13e450 flags: 0x1000004 size: 20 dump line:23 byref data block 0x13e450 contents: forwarding: 0x13e450 flags: 0x1000004 size: 20 ___ Block_release ___ dump line:40 byref data block 0x13e450 contents: forwarding: 0x13e450 flags: 0x1000002 size: 20 dump line:23 byref data block 0x13e450 contents: forwarding: 0x13e450 flags: 0x1000002 size: 20 dump line:49 byref data block 0x13e450 contents: forwarding: 0x13e450 flags: 0x1000001 size: 20
@splhack さんの記事の結果とは以下の点が若干異なっています。
- 謎1: flags の下位 16bit の参照カウントが、Block_copy() で 4 増え、Block_release() で 2 減る
- _Block_object_dispose() 内では flags を 1 しか減らしていないように見えるのですが…
- 謎2: 最後の dump line:49 では参照カウントが 1 のまま
- 参照カウントは OSAtomicCompareAndSwapInt() で減らされるので、最後はちゃんと 0 になるべきであるはず
@ganaware おそらく私が調べた時とランタイムが異なるからだと思います。現在はlibclosure URL が使われているのではないかと。
2011-11-25 04:01:40 via YoruFukurou to @ganaware
というお返事をいただいたので libclosure-53 を覗いてみると、
http://www.opensource.apple.com/source/libclosure/libclosure-53/Block_private.h
enum { BLOCK_DEALLOCATING = (0x0001), BLOCK_REFCOUNT_MASK = (0xfffe), BLOCK_NEEDS_FREE = (1 << 24), (略) };
となっており、参照カウントは1bit左へシフトされていました。上記の結果になるのも納得です。
win-ssh-agent 1.07
win-ssh-agent を使用すると、cygwin の openssh の ssh-agent をよりスマートに利用できるようになります。
通常 ssh-agent を利用するためには、ssh-agent を起動したシェル (例: bash) からその他のプログラムを起動する必要があります。これは、ssh-agent が設定する環境変数 SSH_AUTH_SOCK を他のソフトウェアから参照できなければならないためです。
win-ssh-agent は、ssh-agent が設定する環境変数を全てのプログラムが参照できるようにしますので、特定のシェルから他のプログラムを起動する必要がなくなります。
詳しくは README-ja.txt (README.txt)を参照してください。
ダウンロード:
2011/11/02 1.07:
win-ssh-askpass 1.06
(2011-11-02 追記) 最新版はこちら ⇒ win-ssh-agent 1.07 - GANAwareはてな版
win-ssh-agent は X 用の ssh-askpass と同様の機能を提供します。詳しくは README-ja.txt (README.txt)を参照してください。
ダウンロード:
2011/10/14 1.06:
メモ: Lion で Firefox をビルド
Building Firefox for macOS - Mozilla | MDN を参考に:
(2) homebrew を入れる
(3) Mercurial を入れる
$ brew install Mercurial
Error: No available formula for Mercurial
Install Mercurial with pip:
easy_install pip && pip install Mercurial
Or easy_install:
easy_install Mercurial
$ sudo easy_install pip
$ sudo pip install Mercurial
(4) 他に必要な物を homebrew で入れる
$ brew install pkg-config $ brew install libIDL
(5) autoconf213 を homebrew で入れる
- その前に Lonnen から autoconf213.rb をダウンロードして /usr/local/Library/Formula/autoconf213.rb へ置いておく
$ brew install autoconf213
(6) ソースを入手
$ hg clone http://hg.mozilla.org/mozilla-central/ mozilla
(7) .mozconfig を作成
- webm と libjpeg-turbo はとりあえず使用しないことにした
$ cat > mozilla/.mozconfig . $topsrcdir/browser/config/mozconfig mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-ff-dbg mk_add_options MOZ_MAKE_FLAGS="-s -j4" ac_add_options --enable-debug ac_add_options --disable-optimize ac_add_options --disable-webm ac_add_options --disable-libjpeg-turbo mk_add_options AUTOCONF=/usr/local/Cellar/autoconf213/2.13/bin/autoconf213
(8) ビルド
$ cd mozilla $ make -f client.mk build
(9) 実行
$ cd mozilla
$ open obj-ff-dbg/dist/NightlyDebug.app
Win32 Subversion 1.5.0 からは APR-iconv は不要
Win32 Subversion は 1.5.0 以降は APR-iconv を必要としないので、APR_ICONV_PATH を設定する必要はありません。バイナリパッケージをダウンロードする時に Win32Svn (32-bit client, server and bindings, MSI and ZIPs; maintained by David Darj) を選択しインストールした場合 APR_ICONV_PATH が環境変数に設定されますが、これは不要です(メールフォームからフィードバックしておきました)。
Win32 Subversion が APR-iconv に依存しないようにしようという話は "SVN Win32 Developers -- need some help" や "[PATCH] Remove APR ICONV dependency on Windows" あたりのスレッドで議論され、r865724 で対策コードが commit されました。
- 1.5.0 タグによれば、1.5.x ブランチの r871773 が 1.5.0 に相当
- 1.5.x ブランチは trunk の r869154 に相当
- 1.4.6 タグが打たれたのが r868664
ということで、対策コードは 1.5.0 から含まれるようになりました。
(2011-09-14 追記) David Darj から返事が来て、1.7.0 のリリースからは APR-iconv を含めないようにするとのことです。
はてなブックマーク / みたくないリンク (Google Chrome 拡張版) ver 0.3
はてなブックマーク/見たくないリンク - Chrome Web Store
私は複数マシンで Chrome を使用しているのですが、それぞれでURL情報を共有するのは結構めんどくさいものでした。
そこでエロサイトのURL情報を wedata で管理し、そこから定期的にURL情報をロードするように変更しました。
ver 0.3 から新たに拡張が外部サイトへアクセスするようになるので、0.2 から 0.3 へ自動でアップデートした場合は拡張が一時的に無効状態になるようです。Chrome の拡張は最初にインストールした時より拡張の能力が増える場合は自動的に無効になり、ユーザーに条件を確認させるようになっているのですね。