lisp-repl-mode for xyzzy
Lisp処理系には付き物のREPLですが、xyzzy lisp用の物はありそうで見つからなかったので作りました。
標準の*scratch*では面倒だった*package*の切り替えが簡単になったり、色々捗ります。
標準の*scratch*に比べて良い点
- カレントパッケージを切り替えられる
- *buffer-package*の更新も行うので、ac-modeやldocを導入している場合色々便利に
- REPL変数が使える
- 便利なREPLコマンド (自作可)
注意点
rx.lを導入している場合、rx.l内で使用されているシンボル'ed::**と
xl-repl.l中でlispパッケージよりexportしようとしている'lisp:**がコンフリクトします。
rx.lより先(ni/setupより先)にxl-replをロードするか、siteinit.lの先頭に
(export '(lisp::** lisp::*** lisp::++ lisp::+++ lisp::// lisp::///) :lisp)
というコードを書くなどして回避してください。
インストール
NetInstallerにhttp://youz.github.com/xyzzy/package.lを登録して*scratch*よりインストールし、.xyzzy (or siteinit.l) に
(require "xl-repl")
と追記してください。
設定
ac-modeやldoc2を導入している場合、以下の設定を.xyzzyに加えておくと便利です。
; ldoc2 を使っている場合 (push 'ed:lisp-repl-mode ed::*ldoc-activated-mode-list*) ; ac-mode を使っている場合 (push 'ed:lisp-repl-mode ed::*ac-mode-lisp-mode*)
REPLバッファ上で、パッケージ修飾子無しでもカレントパッケージからシンボル名補完ができたり、ldoc2での説明表示ができるようになります。
起動
M-x start-repl
キーマップ
REPLバッファ用キーマップ repl:*keymap* は、 ed:*lisp-mode-map* をベースにして以下のキーバインドを追加/上書きしています。
- RET -- repl::newline-or-eval-input (入力した式を評価 / 書きかけならlisp-newline-and-indent)
- C-l -- repl::clear-repl (REPLバッファをクリア)
- M-C-a -- repl::beginning-of-input (入力中の式の先頭へ移動)
- M-C-e -- repl::end-of-input (入力中の式の最後へ移動)
- C-p -- repl::previous-input (入力履歴 - 戻る)
- C-n -- repl::next-input (入力履歴 - 進む)
REPLコマンド
以下のキーワードシンボル(と引数)を入力するとREPLコマンドを実行します。
:cd (&optional dir) ; default-directoryをdirへ移動 (dir省略時はdefault-directoryを表示) :describe (symbol-or-package-name) ; パッケージ/変数/定数/関数の説明を表示 :dir (&optional wildcard) ; default-directoryのファイルを列挙 :expand (form) ; formをmacroexpandして表示 :help (&optional pattern) ; REPLコマンドの説明を表示 :load (name) ; *load-path*にdefault-directoryを含めて(load-library 'name)を評価 :ls (&optional pat (pkg *package*)) ; パッケージ内の変数/定数/関数シンボルを列挙 :lsall (&optional pattern) ; 全パッケージの変数/定数/関数シンボルを列挙 :lsext (&optional pattern (pkg *package*)) ; パッケージよりexportされている変数/定数/関数シンボルを列挙 :lspkg (&optional pattern) ; パッケージ名を列挙 :mkpkg (name &rest options) ; (make-package 'name [options])を評価し、*package*を作成したパッケージに変更 :package (name) ; (in-package 'name)を評価 :require (name) ; *load-path*にdefault-directoryを含めて(require 'name)を評価 :time (form) ; formを評価し、実行時間(秒)を表示
適当に省略してもOK。
user> :pa repl.command ; :packageコマンド #<package: repl.command> repl.command> :de package ; :describeコマンド <Function> repl.command::package (name) ; (in-package 'name)を評価
:cd コマンドは今の所引数に文字列しか受け付けないので注意
user> :cd site-lisp 不正なデータ型です: site-lisp: pathname user> :cd "site-lisp" c:/usr/xyzzy/site-lisp user> :cd "C:/Users/yz" C:/Users/yz
他のコマンドはシンボルを渡してもOK。
user> :dir *x*
[C:/Users/yz/]
.VirtualBox/
Dropbox/
lynx.rc
lynx_bookmarks.htm
VirtualBox VMs/
REPLコマンドの自作
パッケージrepl.command内に関数を定義すると、その関数がREPLコマンドとして使えるようになります。
定義例はソースを見てください。
repl.commandパッケージはlispパッケージをuseしていないので、(in-package :repl.command)と書いてから追加コマンドを定義するのは色々面倒です。
lispやeditorをuseしている適当なパッケージから(defun repl.command::hoge () ...)と書く方が良いでしょう。
(repl.commandパッケージがlispパッケージをuseしていないのは、loadやrequireといったlispパッケージにあるような名前のコマンドを簡単に作成したかった為です)
不具合等
見つかりましたら githubのissuesか@Yubeshiまで。