xyzzyの拡張書くときは ~/work/<プロジェクト名>
にこんな風にファイルが配置される。
- ~/work/<プロジェクト名>/
- README.md
- site-lisp/
- <プロジェクト名>.l
- <プロジェクト名>/
- packages.l
- util.l
- ...
最初は <プロジェクト名>.l
に全部書いてるんだけど、何度も書いては捨ててるうちに毎回書くもの(パッケージ定義とかユーティリティとかある程度形が決まってきたものとか)を別ファイルに分割していくので、この時点では主に <プロジェクト名>.l
で色々やってる。
~/work/<プロジェクト名>/site-lisp/
が *load-path*
に追加される形を想定しているので、各ファイルのモジュール名はこうなる。
~/work/<プロジェクト名>/site-lisp/<プロジェクト名>.l
- -->"<プロジェクト名>"
~/work/<プロジェクト名>/site-lisp/<プロジェクト名>/packages.l
- -->"<プロジェクト名>/packages"
~/work/<プロジェクト名>/site-lisp/<プロジェクト名>/util.l
- -->"<プロジェクト名>/util"
なので <プロジェクト名>.l
から他のファイルを require
している。
(eval-when(:execute:compile-toplevel:load-toplevel)(require"<プロジェクト名>/packages.l")(require"<プロジェクト名>/util.l") ...)
諸々の事情(Windows Updateなど)で xyzzyを再起動したりした時には、~/work/<プロジェクト名>/
が *load-path*
に登録されていないので、こいつらを見つけられなくなって、全部のファイルを順番に手動でロードしたり repl から手動で *load-path*
に追加したりしてたんだけど、めんどくなったので勝手に *load-path*
へ追加するようにした。
(in-package :editor)(defun provide-module-name ()(save-excursion (goto-char (point-min))(when(scan-buffer "^(provide \"\\([^\"]+\\)" :regexp t)(formatnil"~A.l"(match-string 1)))))(defun module-root-pathname (pathname module-name)(let((path (reverse(split-string pathname"/")))(name (reverse(split-string module-name "/"))))(while name (unless(string=(car path)(car name))(error"モジュール名とファイル名が一致しません: ~S" module-name))(setf path (cdr path) name (cdr name)))(formatnil"~{~A/~}"(reverse path))))(defun add-module-root-to-load-path ()(let((root (module-root-pathname (get-buffer-file-name)(provide-module-name))))(pushnew root *load-path*:test#'path-equal)))(defconstant+original-require-function+#'require)(defunrequire(module-name &optionalpathname)(handler-case(funcall+original-require-function+ module-name pathname)(error(e)(if(and(typep e 'simple-error)(string=(princ-to-string(simple-error-format-string e))"ファイルが見つかりません"))(progn(add-module-root-to-load-path)(funcall+original-require-function+ module-name pathname))(error e)))))
今編集してる lispファイルを保存したときに(コンパイルして)ロードしてるので、現在のバッファでモジュール名とか探してる。他のところからロードしたときは使えねーわ。