長きに渡り活躍したWIDEプロジェクトのIRCサーバが役割を終えようとしています。そして惜しまれる中、livedoorがIRCサーバの提供をかって出てくれました。
livedoor ラボ「EDGE」 開発日誌 : livedoorからIRCnetへIRCサーバを提供します - livedoor Blog(ブログ)
WIDEプロジェクトIRCワーキンググループによるIRCサーバ運用終了について
という発表がありましたが IPv6を応援し、IRCをこよなく愛するlivedoorは、IRCnetへIRCサーバを提供することを決定しました。
※IPv4とIPv6で利用可能なデュアルスタック環境を用意する予定
※接続数などの仕様は現行と同じです
現在、関係各所と調整を行っているところですが近日中に接続先情報などはお知らせ出来ると思いますので、お待ちください。
宜しくお願いいたします。
http://blog.livedoor.jp/edge_labs/archives/1092902.html
すばらしいですね。これを期にIRCユーザがまた増え出すといいですね。
ぜんぜん関係ないですが、今日はvimからIRC出来るスクリプトを書いてみました。IRCプロトコルを喋るのではなく、freenode.netのウェブインタフェースを叩いています。
curlコマンドを使っているのでお使いのvimがperl拡張(if_perl)やpython拡張(if_python)、ruby拡張(if_ruby)でコンパイルされている必要はありません。Windowsでも動きます。
生のIRCと違い、プロキシさえ通れば防火壁内の人でもvimからIRC出来ます。
一つ問題があるとすれば、クライアントサーバをサポートしたvimである事と起動方法が難しい事。クライアントサーバはUNIX系OSであればgvimで、Windowsであればコマンドライン版でもOKです。クライアントサーバをサポートしているかどうかは、一つvimを起動しておいて
# vim --serverlist
とする事で確認出来ます。vimは内部で非同期に生成したプロセスとやりとりするのが苦手なので、vimを2つ使っています。
以下起動手順。
- 新しく端末を開きvimを起動する
- さらに新しく端末を開きもう一つvimを起動する
- 片方のvimで「:Irc」と入力します。
- もう片方のvimで「:IrcServer #mychannel mynick」と入力します。
場合により上記vimをgvimで置き換えて下さい。
これで「IrcServer」と入力した側がIRCサーバとなり、「Irc」と入力した側がIRCクライアントになります。内部でremote_expr()による通信をしています。
実際にはサーバがremote_expr()でコンテキスト、発言者、メッセージを飛ばし、受け側であるクライアント側がバッファに追加しています。
Linux版で試した所、若干とろい気もしますが十分楽しめます。(ネタとして)

一人で寂しいよー。
どうぞ遊んでやって下さい。
mattn's pureirc-vim at master - GitHub
vimscript for IRC. This make possible to access freenode.net from vim via HTTP protocol. it don't require if_xxx. using 'curl'
http://github.com/mattn/pureirc-vim
vimを使っていて人のスクリプトの一部が気に入らない場合、直接書き換える事もするのですが、最近はGLVS(GetLatestVimScripts)を使う事の方が多く、せっかく書き換えたスクリプトを新しいアップデートで上書きされたりして悲しい事になったりします。書き換えて違うファイル名で保存する...なんてのも方法かもしれませんが、いっそvimscriptの中のある関数だけ書き換えられればいいんじゃないか...と思って書き換える方法を考えてみました。
まず、vimにはグローバルスコープ、スクリプトスコープ、ローカルスコープとあり、スクリプトスコープとは1スクリプトファイル内で実行される関数と変数群に位置します。
通常、スクリプトスコープ内の関数には<SID>というスクリプトID識別が付与され、ファイル単位でユニークに格納されています。
ただ実際には識別子が付いているだけで、外部から参照も出来ますしfunction()で関数リファレンスを取る事も出来ます。スクリプトファイルに対する<SID>は
:scriptnames
で一覧出来ますから、この出力をredirで盗み取ってしまえばいいのです。
ちなみにウチのubuntuで:scriptnamesを実行した結果は以下の通り。
1: /usr/share/vim/vimrc
2: /usr/share/vim/vim72/debian.vim
3: /usr/share/vim/vim72/syntax/syntax.vim
4: /usr/share/vim/vim72/syntax/synload.vim
5: /usr/share/vim/vim72/syntax/syncolor.vim
6: /usr/share/vim/vim72/filetype.vim
7: /home/mattn/.vimrc
8: /usr/share/vim/vim72/syntax/nosyntax.vim
9: /usr/share/vim/vim72/ftplugin.vim
10: /usr/share/vim/vim72/indent.vim
11: /home/mattn/.vim/plugin/autodate.vim
12: /home/mattn/.vim/plugin/calendar.vim
13: /home/mattn/.vim/plugin/codepad.vim
...
この左数字部分がIDです。これをsplitとmapを使い、スクリプトファイル名から<SID>を得られるハッシュマップ(vim語ではDictionary)に変換します。
function! GetScriptID(fname)
let snlist = ''
redir => snlist
silent! scriptnames
redir END
let smap = {}
let mx = '^\s*\(\d\+\):\s*\(.*\)$'
for line in split(snlist, "\n")
let smap[tolower(substitute(line, mx, '\2', ''))] = substitute(line, mx, '\1', '')
endfor
return smap[tolower(a:fname)]
endfunction
ちなみに、tolowerしてるのはほぼWindows用で、ちょっとした大文字小文字の違いで<SID>が取れなくなって悲しくならない為のおまじないです。
次に書き換えるべき関数リファレンスを取得します。<SID>内で定義される関数リファレンスは
<SNR>SID_foo
という識別になります。これをfunction()関数に渡してあげれば関数リファレンスが取得出来ます。
これだけでも、実はスクリプトスコープ内の関数を外部から呼び出せてウマーなのですが、ここから本題。
関数を書き換えるにはfunction!と「!」付きで宣言すれば良いのですが引数が決められません。書き換え関数の引数を外部から指定して貰っても良いのですが面倒ですよね。書き換え前の関数引数と書き換え後の関数引数が同じである事は書き換えた側の責任でもありますし、call()関数を使えば引数を配列として呼び出す事も出来ます。そこで以下の様なトリックを使いました。
function! funcA(...)
return call('funcB', a:000)
endfunction
a:000とは可変個引数を宣言した際に使える引数リストです。受け取った引数リストをcall()関数に渡しています。後はこれを動的に実行してやれば書き換え関数の完成です。全体のコードだと以下の様になりました。
function! GetScriptID(fname)
let snlist = ''
redir => snlist
silent! scriptnames
redir END
let smap = {}
let mx = '^\s*\(\d\+\):\s*\(.*\)$'
for line in split(snlist, "\n")
let smap[tolower(substitute(line, mx, '\2', ''))] = substitute(line, mx, '\1', '')
endfor
return smap[tolower(a:fname)]
endfunction
function! GetFunc(fname, funcname)
let sid = GetScriptID(a:fname)
return function("<SNR>".sid."_".a:funcname)
endfunction
function! HookFunc(funcA, funcB)
if type(a:funcA) == 2
let funcA = substitute(string(a:funcA), "^function('\\(.*\\)')$", '\1', '')
else
let funcA = a:funcA
endif
if type(a:funcB) == 2
let funcB = substitute(string(a:funcB), "^function('\\(.*\\)')$", '\1', '')
else
let funcB = a:funcB
endif
let oldfunc = ''
redir => oldfunc
silent! exec "function ".funcA
redir END
let g:hoge = oldfunc
exec "function! ".funcA."(...)\nreturn call('" . funcB . "', a:000)\nendfunction"
endfunction
さて、このスクリプトの使い方。例えば引数で与えられた文字列XXXを使い「Hello: XXX」を表示するスクリプト内関数s:funcAがあったとして、これを「GoodNight: XXX」と表示するスクリプト内関数s:funcBに書き換えたいとします。それぞれ関数リファレンスを得て書き換えたいタイミングでHookFuncを呼べば、それ以降は書き換えられた関数が実行されます。
so hookfunc.vim
function! s:foo(text)
echo "Hello, " . a:text
endfunction
function! s:bar(text)
echo "GoodNight, " . a:text
endfunction
call s:foo("World")
call s:bar("World")
call HookFunc(GetFunc(expand("%:p"), "foo"), GetFunc(expand("%:p"), "bar"))
call s:foo("World")
ちなみにfuncAとfuncBは違うスクリプトファイルに宣言されていても問題ありません。
イメージはコード内のコメントで分かって頂けると思います。時と場合によっては使えそうな機能ですね。
まぁ、ほとんど使い道ないでしょうが...苦笑