2011/03/31

concat-path



xyzzy には、パス文字列を連結する merge-pathnames という関数がある。

;; test
(merge-pathnames "bar.l" "c:/foo")
"c:/foo/bar.l"


第1引数がスラで始まっているかどうかや第2引数がスラで終わっているかどうかを心配しなくても、きれいに連結してくれる。

ただ、引数が2個固定なのと、引数の並び順が今ひとつ直感的でない。merge-pathnames という関数名も覚えづらい。

どうやら、この関数の用途は パス文字列を連結するというより、xyzzy起動時の作業フォルダを基準にパスを作成することのようだ。

concat みたいな感じで使えるのがほしい。

そこで、先ほど覚えた dolist を使ってでっち上げとく。

(defun concat-path (path1 &rest path)
(let ((ret (string-right-trim "/" (map-backslash-to-slash path1))))
(dolist (p path ret)
(setq ret (concat ret "/" (string-trim "/" (map-backslash-to-slash p)))))))

;; test
(concat-path "D:/work/tmp" "hoge" "/hage/hagege" "\\foo\\foo-foo\\" "bar/bar-bar\\bar-bar-bar\\")
"D:/work/tmp/hoge/hage/hagege/foo/foo-foo/bar/bar-bar/bar-bar-bar"


これで、スラを気にせずに引数を左から順に連結してくれる。

下記の挙動は、オリジナルの merge-pathnames をまねてみた。



  • 連結後の パス文字列の両端は スラをつけない

  • 引数がバスラ区切りであってもスラ区切りに直す




2011/03/21

pme (print macro expansion) が便利



Emacs系で lisp を書き出して10年くらい経ってしまった。


でもいまだに マクロがよくわかってなくて、適当にクォートやらバッククォートつけながら試行錯誤している始末。


このままじゃ恥ずかしいので少しは勉強しようと、このサイトを拝見していたら、いいものを見つけた。


pme (print macro expansion)


マクロを書いてもそれがどういう S式 になるのか確認するのに、いままで macroexpand を使っていた。でもこいつは展開後の S式 をずらーと一行に吐き出す非常に厄介なやつだった。


pme は展開後の S式を適当にインデントして表示してくれるのでとても助かる。


マクロがちょっと身近になったかな。





lisp デバッグ用 msgbox



xyzzy のコマンドを作ったりしてるときはよく、



(msgbox "~S" hoge)


とかしてデバッグプリントしてたりする。実に原始的だ。


(べつにダイアログボックスに出さんでも、一時バッファに流したりすればいいんだが、それはそれでめんどくさい)


しかしこの msgbox、デバッグ用に使うにはちょっと勝手が悪い。


出力形式は常にS式でいいし、引数も任意の個数取れたほうがいい。


というわけでデバッグ専用の msgbox をでっち上げてみた。激しくガイシュツくさいが…。



;;; @@@ msgbox for lisp debug
;;; usage: (dbg-msgbox args)
(defmacro dbg-msgbox (&rest vars)
`(msgbox
(concat ,@(make-list (length vars) :initial-element "~S\n"))
,@vars))


こういうのが数行で書ける LISP って神としか思えん。


にしても本当は Emacs みたいに edebug がほしいなあ。





文字コードは誰を不幸にするのか(2)



Wikipedia によると 0x5C に通貨の記号が割り付けられているのは日本だけじゃないみたい。


韓国ではウォン記号が出るんだと。Wみたいな形。パス区切りやエスケープ文字でこれは目につらいな。


でももっと厳しそうなのを見つけてしまった。根本的に文字コードと無関係だが、


ココによると、ギリシャではセミコロンは疑問符を表す模様。



uchar huge_complicated_process( void )
{
printf("catastrophic error occured.");
return 0x33; /* err code */
}


「エラー起きた?エラーコード返す?」みたいな (w


若干楽しそうではある。


韓国人もギリシャ人も耐えてるな。日本人も耐えるしかないのか。





文字コードは誰を不幸にするのか(1)



視力も落ちてきて、小さいフォントだと windows のパスを読み取るのも億劫になってきた。


なにが見づらいって パス区切り文字の「円記号」だ。


英語圏のフォントなら、パス区切り文字はバックスラッシュだから Unix 系と似た感じでこれはこれで見やすいからいい。


なんで日本のフォントではパス区切りが「円記号」になるのか。


Wikipedia によれば、これは実にしょうもない問題だった。


簡単に言えば、英語圏で使っている文字コードの バックスラッシュがおかれている番地に、日本の文字コードでは「円記号」を割り付けてしまったことによる。

当初「ここらへんの番地は各国で自由に割付けていい」*1と決められていたので、日本の文字コードを決めた偉い人は安心してこの番地(具体的には 0x5C )に「円記号」を割り付けた。

その後、Microsoft が DOS を発表したが、このときパス区切り文字として採用されたのがバックスラッシュだった*2。DOSを日本に持ってきて、日本の文字コードのフォントで表示させると区切り文字は「円マーク」になった。


その後 Microsoft は Windows を発表したが、パス区切り文字は DOS のバックスラッシュをそのまま引き継いだ。もし Windows が失敗していればこんな些細な問題は歴史に埋もれていったんだろうが、あろうことか爆発的に普及してしまったせいで問題となっている。


これが経緯だと思う。


たぶん、0x5C に「円記号」を割り付けた人に罪はないんだろう。約束を破られた被害者だし。


じゃあ Microsoft が悪いのか。確かに「国によって違う文字が表示される」ような文字をパス区切り文字に使おうとしたのはどうかと思う。しかし、時は1980年代初頭、自分が売るOSが世界的に普及したときのことを考えろってのは、さすがに無理がある。それに似たようなことは Microsoft 以外にも起きているから、一人悪者にするのもどうか。


たとえば、プログラムを書いているとき改行文字はどう書くのか。


\n とかで表す言語が多いよなあ。


FORTRAN は違うみたいだけど、LISP は最初から \n だったのかな。


たとえば、正規表現はどうか。


sed は、すでにバックスラッシュを使ってた様子。


ed でもそうなんだろうか。


そもそも誰が最初に、バックスラッシュをエスケープ文字に選んだのか。


まあ今となっては誰でもいいんですよ。


でもね、Unicode が浸透してずいぶん経つのに、なんで旧来の文字コードの暗い過去を引きずっているのか、それが納得いかんだけなんです。時々ね。




*1:これは、「各国で自由に割付けていい」=「国によって違う文字が表示される」だ。


*2:参考 http://www.seasip.demon.co.uk/Cpm/optchar.html





2011/03/19

よく開くファイルを登録しとく



いっつも開くファイルなんてたかだか 5~6 個だけど、探すのがめんどくさい。


とくに今はカスタマイズ中なので、.xyzzy は頻繁に開くし、自前のライブラリとかもしょっちゅう開く。


じゃあ、登録しとけばってことで、こんなのを作ってみた。



;;;
;;; @@@ find-file-frequently
;;;
(defvar *find-file-frequently-list* '((merge-pathnames ".xyzzy" (user-homedir-pathname))
(append-trail-slash (path-delim-to-slash (get-special-folder-location :desktop)))
(default-directory)))

(defvar *find-file-frequently-count* 0)

(add-hook '*enter-minibuffer-hook*
#'(lambda (buf his)
(setq *find-file-frequently-count* 0)))

(defun find-file-frequently-sort-function (x y)
(cond ((and (not (file-directory-p x)) (file-directory-p y)) t)
((and (file-directory-p x) (not (file-directory-p y))) nil)
(t (string-length-lessp x y))))

(defun find-file-frequently ()
(interactive)
(let ((old (buffer-substring (point-min) (point-max)))
(lst (mapcar #'truename-mod (mapcar #'eval *find-file-frequently-list*))))
(let ((s (nth (mod *find-file-frequently-count* (length lst))
(sort lst #'find-file-frequently-sort-function))))
(if (or (string= s old)
(find s (mapcar #'get-buffer-file-name (buffer-list)) :test 'string=))
(progn
(incf *find-file-frequently-count*)
(find-file-frequently))
(progn
(delete-region (point-min) (point-max))
(insert s)
(incf *find-file-frequently-count*))))))

(define-key ed::minibuffer-local-completion-map #\C-\f #'(lambda () (interactive)
(if (= (point) (point-max))
(find-file-frequently)
(forward-char 1))))

; (setq *find-file-frequently-list* (append *find-file-frequently-list*
; '("~/lisp/discrete.l" "~/lisp/lib.l" "~/lisp/")))


使い方


C-x C-f でミニバッファに入ったら、C-f する。


すると登録している候補が出てくる。C-f するごとに順に次の候補が出てくる。


C-f は末尾のときだけ機能するような変態キーバインドにしてみた。


キーバインドは ed::minibuffer-local-completion-map をいじる。


候補のリストは *find-file-frequently-list* をカスタマイズする(最下行を参考)。


候補の順が気に入らなければ、find-file-frequently-sort-function を差し替えるとよろしい。


そうそう、こんなの↓が要る。



;;; @@@ string<, string-lessp
(defun string-length< (x y)
(cond ((< (length x) (length y)) t)
((> (length x) (length y)) nil)
((string< x y) t)
(t nil)))

(defun string-length-lessp (x y)
(cond ((< (length x) (length y)) t)
((> (length x) (length y)) nil)
((string-lessp x y) t)
(t nil)))

;;; @@@ truename
;;; mod: fixed removing trailing slash
(defun truename-mod (path)
(let ((endc (char path (1- (length path)))))
(if (or (eq endc #\/)
(eq endc #\\))
(append-trail-slash (truename path))
(truename path))))





なんやかんやで xp になっていた



久々に はてな にログインしてみた。2年ぶりか。


というか、ログインできたからちょっとびっくり。


そういえば、なんやかんやで Linux から windows xp になってしまった mini 9。


いつもながらあほくさい経緯だ。


寝転んでドット絵を打ちたいと思って linux のドット絵エディタを探した。けど、linux では gimp くらいしかなかった。


windows では edge という使いやすいのがあったので mini 9 をドット絵マシンにすべく、やむなく xp を入れたのだった。


しばらくドット絵を練習していたものの大した成果も出ず、そのうちネットブックとして使うようになっていた。


で、久々に lisp でも勉強するかと xyzzy をインストールしてみた。


せっかく はてな にも入れたし、もう一度 mini 9 を開発マシンにすべく立ち上がろうか。


あんましやる気はないけど。