2007年 10月 25日

Chemr

今日のスナップショット

http://lab.lowreal.net/test/chemr/Chemr.2007-10-24.dmg

全部入りの dmg です。RubyCocoa さえ同梱してあります (svn head にちかめ)。たれかです。


あとキーバインドを設定からよむようにして (たぶん ~/.chemr/chemr-keys あたりを eval するだけ)、ユーザ CSS はかなぁ。実装自体よりどうやったら簡単かで悩むむ。

キーバインドはいまのところ

keybinds = {
	"C-j" => self.method(:nextCandidate),
	"C-n" => self.method(:nextCandidate),
	"C-k" => self.method(:prevCandidate),
	"C-p" => self.method(:prevCandidate),
	"¥r"  => self.method(:jumpToCurrent),
	"¥t"  => self.method(:completion),
	" "   => Proc.new {|s|
		@webview.stringByEvaluatingJavaScriptFromString <<-JS
			window.scrollBy(0, 200);
		JS
	},
	"C-u" => Proc.new {|s|
		@search.stringValue = ""
	},
	"G-[" => Proc.new {|s|
		@webview.goBack
	},
	"G-]" => Proc.new {|s|
		@webview.goForward
	},
	"G-=" => Proc.new {|s|
		@webview.makeTextLarger(self)
	},
	"G--" => Proc.new {|s|
		@webview.makeTextSmaller(self)
	},
}

こんなかんじにしてある。.call! .call! Duck Typing! JS よんでるのがすこしきもいけど、WebView の API しらべるより簡単だし、いろいろできそうな感じがしてこれはこれでいい気がした

とにかくもう Ruby で書いてあるからもうなんでもできますね。ってかんじだけれど、トピックツリーを処理させるようにすると、NSOutlineView のよびだし (でも delegate メソッドではない) で頻繁に落ちようになったり、あと謎のタイミングで落ちるようになったりしたので機能を無効化してある。どうせキーワード検索しかつかわない。

2ファイルにしか分離せずクラスに機能をめっさ詰めこんでる (デリゲート対象になりまくってる)。これたぶんよくないんだろうけど、めんどいしなぁ。

Enumerable#group_by

なんでないんだろう。いままで partition がこれだとおもってた。

module Enumerable
	def group_by(&block)
		self.inject({}) {|r,i| (r[yield i] ||= []) << i; r}.values
	end
end

foo = Array.new(10) { rand(40) }

require "pp"
pp foo.group_by {|i|
	("%02d" % i)[0]
}

partition より汎用的で、partition にするにも ! 一個足すだけだからこっちがあったほうがいいと思うんだけどなぁ

検索してみると既出すぎる……ActiveSupport にもあるんだ

Chemr どうにかしたいリスト

  • ページ内検索
  • 全文検索 (chmlib binding のほうに API だけは移植した)
  • InputMethod の変換中はキーバインドを無効にしたい (IM の有効無効をどうやってとるか謎い)

実装メモ

  • WebView の performFindPanelAction はうごかない
    • なんでっておもってたけど、そういうもんみたいだ。リファレンスにのっけておくなよ><
  • 全文検索で日本語が検索できない。
    • binding の実装がわるいんだろうけど (文字コードを NKF で変換できる範囲で変えてみたけどだめだった)
    • 実装しなおすにはフォーマットをちゃんと理解しないといけない
    • 閉じた仕様でなおかつ消えていきそうな仕様の理解を深めても……
    • とはいえ実装おったり、http://www.nongnu.org/chmspec/latest/Internal.html#FIftiMain 読んだりした……めんどくさい
  • OutlineView はやっぱ落ちまくる
    • Tree 表示のタブを選択するまで、データソースを設定しないようにしてみた
    • 表示させちゃうと (しかもたくさん CHM ひらいていると) 落ちやすくなる
  • IM 変換中のキーバインド無効はコメントをいただいたのをそのまま条件文に
2007年 10月 24日

RubyCocoa で chm 読むアプリケーションつくりはじめた

Mac でつかえる chm (HTML Help) よむやつでまともなのがないので作ってみた、けど、微妙にうまくいってない。

NSSearchField にフォーカスがあるとき、それ自身をサブクラスにしても親の NSWindow をサブクラスにしてもキーイベントがとれない。なんでだろ。これが解決しないことにはつかえないお……全部メニューコマンドにしちゃうかなぁ……Cmd+L でサーチエリアにフォーカスあたるようにしてる。ぎりぎり使えるかつかえないかレベル。HHK だと使う気にならない。


まともなのっていうのは

  • インデックスのインクリメンタルサーチができる
  • ストレスないぐらいには速い
  • 日本語がおかしかったりしない
  • キーバインドがまとも

っていう最低最低限レベルであって、なんか特別なことやりたいわけじゃない。探しかたがわるいだけなのかほんと見つからない。

作るなら Ruby で書きたいなと思って、chmlib っていう C のライブラリの ruby binding を swig 使って作って、それを利用して RubyCocoa 使ってすかすかつくった。chmlib をやるまえに pure ruby で書いてたんだけど、途中でめんどくさくなってやめた。swig は思ったより簡単だったけどめんどかった (でも一部の関数は使わないのもあって使えるようにしてない)

本体の処理は Chmox からだいたいパクってて、chmlib のバインディングのほうは PyCHM からパクってる。ぜんぶパクり。

あとユーザ CSS ほしいですね。すぐ実装できそう。

あとあと、ぜんぜんどうでもいいかもしれないのだけれど

url = "#{SCHEME}://#{doc.object_id}#{path}"
NSURL.URLWithString_relativeToURL(url, "#{SCHEME}://#{doc.object_id}/")

って感じで内部 URL を作るのに object_id を使っているのに萌えませんか! せんか!

URL はクラスを横断したりするから、ObjectSpace._id2ref だけでとれるとすごいスッキリ! 後処理も doc の参照はずすだけでいいし!

dylib をアプリケーションバンドルにふくめるにはどうしたらいいんだろう

static link しようとおもったらできないしなぁ。どうやるんだろう……
ld の仕組みもいまいちよくわかってない…… .a が static アーカイブ? でも直接指定しても otool -L するとシステムのほうを参照してるしファイルサイズ増えないしなぞい。OS X はリンクするときフルパスでリンクするんだなぁ……

DYLD_LIBRARY_PATH つかうのかなぁ。ruby の require の前に DYLD_LIBRARY_PATH をバンドルの Resource dir にしたらいけるかなぁ……わかんないけどやってみよう……

あれもしかして standaloneify ってこれもやってくれるのかな。やってくれるのかな、っていうか、実行すると dylib もあつめてつかってるライブラリとおなじディレクトリにほうりこむみたいだ。これでうごくの?

sudo mv /usr/local/lib/libchm.0.dylib /usr/local/lib/libchm.0.dylib.t 

とかやって standaloneify 後のアプリひらいてみたけどちゃんと起動した。すげ

CHM メモ

Gauche のへるぷで落ちまくってたけど、がんばってデバッグしたら (うそ。Chmox では読めたので (同じライブラリつかっているのに) ロジックをパクってきた) みれるようになった。よいかんじ

Gauche とか、あんまり知らない言語はほんとにリファレンスをひきまくるから、かんたんにひけると超絶早く言語が習得できそう。

2007年 10月 23日

zsh で blosxom クローン

http://coderepos.org/share/browser/lang/shellscript/blosxom.zsh/

entries[$i]="foo 1 bar 2"
typeset -A entry
: ${(AA)entry::=${(z)entries[$i]}}

とかやると、entry に { foo => 1, bar => 2 } みたいな連想配列が入る (実際には Perl みたいには書けない) 連想配列のキーをとりだすには ${(k)aarray} する。

typeset -A は連想配列の宣言 typeset -a だと配列の宣言になる。基本的に宣言なしで変数は使えるけど、連想配列は絶対に宣言しないといけない。

(AA) は連想配列をつくるやつ。(A) だと配列になる。(z) はコマンドラインにそれが書かれたかのようにアンエスケープしながら分割する。: は何もしないコマンド。引数評価だけされる。

エスケープは (q) でできる

foo="aaa  (aa)  "

echo ${(q)foo}    #=> aaa\ \(aa\)\ \
echo ${(qq)foo}   #=> 'aaa (aa)  '
echo ${(qqq)foo}  #=> "aaa (aa)  "
echo ${(qqqq)foo} #=> $'aaa (aa)  '

foo が空のとき (q) だとなんもなくなるのでまずい。(qq) のほうが安全

man zshall /Parameter Expansion Flags

2007年 10月 22日

Vim で blosxom クローン書いてみた

なんかいくつかの意味にとれますね。でもちゃんとうごくまでいくまえにめんどくなった (トップページだけなんとなく動く、っていう微妙な感じ)。

http://coderepos.org/share/browser/lang/vim/blosxom.vim.cgi/blosxom.vim.cgi

#!/bin/sh
""exec /usr/local/vim7/bin/vim -u NONE -i NONE --noplugin -e --cmd ":so $0"
" vim:ft=vim:
" -e で ex モードにすることで、エスケープシーケンスを排除してる。
"  完全じゃないっぽい?

で起動して、ダブルクオートは vim script ではコメントなので、vim に処理がうつったあとは exec が無視され、あとにつづくスクリプトが実行される。

開いた Vim 上で出力を生成して、

" Output
silent exe "w " . tempname()
silent exe "!cat %"
q!

最後に保存して cat で出力してみた (cat は反則な気がするけど、echo だとエスケープシーケンスがでてしまう)。もっと簡単な方法あるのかなぁ……


もうちょいアグレッシブに、

  • テンプレートをよみこむ
  • ヘッダ部分を s/// で置換する
  • エントリ部分を /entry-start^MV/entry-endYp でコピーしながら置換する

とかやったほうがおもしろいかも

Emacs で CGI 書く

#!/bin/sh
#@56
exec /usr/bin/emacs -Q --batch --no-unibyte --kill -l $0
; #@count は count 文文字をよみとばす elisp の機能
; vim:ft=scheme:expandtab:
; ↑ vim で elisp かよぷぷぷ scheme モードのほうがインデントがいい

(require 'cl)

(defun list-files (dir)
  (let ((ret '()))
    (loop for f in (directory-files dir t) do
          (let* ((attr (file-attributes f))
                 (dir?  (eq (car attr) t))
                 (file? (null (car attr)))
                 (mtime (nth 5 attr)))
            ;(print (list f dir? file?))
            (if (null (string-match "\\(\\.\\|\\.\\.\\)$" f))
              (progn
                (if dir?  (setf ret (append ret (list-files f))))
                (if file? (setf ret (append ret (list f)))))
              )
            )
          )
    ret)
  )

(princ "Content-Type: text/html; charset=utf-8\n\n")

(princ "<h1>aaaa</h1>")
(princ "<pre>")

(princ "Hello\n\n")

(print (pwd))
(print (list-files "data"))

(print system-configuration)
(print system-name)
(print (emacs-version))

(print (format-time-string "%Y-%m-%d %H:%M:%S" (current-time)))

(print (getenv "PATH_INFO"))
(print invocation-name)
(print process-environment)

(princ "</pre>")

Scheme と同じノリで書けるかと思ったら全然違う。Blosxom クローンつくろうとおもったけど途中までしか書いてない。続き書くかわからない。