Lem Advent Calendar 2023 - Lisp Mode - Swank RPC
これは Lem Advent Calendar の記事です。
概要
前回、話したようにLemではSLIMEをフォークしたmicrosを使っています。
SLIME/microsはサーバーとクライアントから構成され、非同期通信によってやりとりされます。
これはSwank RPCというプロトコルを使っており、クライアントはエディタ(Lem)でサーバーはユーザーのcommon lispコードを実行するプロセス(micros)です。
Protocol
サーバー/クライアントでやりとりされるデータは、メッセージの長さを表す6桁の16進数文字列とS式を表す文字列からなります。
メッセージ
主に使われるメッセージは下記の通りです。
-
(:emacs-rex S式 パッケージ スレッド リクエストID)
クライアントからサーバーにEvalのリクエストを行います。
パラメータのパッケージ内でS式をevalします。
スレッドは評価されるサーバー側のスレッドを指定します。
スレッドがT
であれば、新しいスレッドその中でevalされます。
:repl-thread
であればREPLのスレッドでevalされます。
-
(:return 結果 リクエストID)
:emacs-rex
によってevalされた結果としてこのメッセージが返されます。
リクエストIDは:emacs-rex
のリクエストIDに対応します。
結果は以下の形式となります-
(:ok value)
valueにevalの結果が入っています。 -
(:abort condition)
eval中にエラーが起きたときこのメッセージが返されます。
conditionは文字列でエラー内容が入っています。
-
-
(:write-string string id type)
サーバーでprintされる場合にその内容をクライアントに通知します。
lemではREPLにstringを表示します。 -
(:read-string thread tag)
サーバー側で標準入力などから読み込みが必要な場合にクライントに通知します。 -
(:emacs-return-string thread tag string)
:read-string
の結果をクライアントからサーバーに通知するときに使われます。
関数
:emacs-rex
を使う事によってサーバー側でevalできることがわかりました。
evalしたい式の中でswank/microsが提供する関数を使うことで、様々なIDEの機能を実現することができます。
例えば補完については fuzzy-completions
という関数が提供されています。
;; client to server
(:emacs-rex (fuzzy-completions "M-V-B" "CL-USER") "SWANK" <request-id>)
;; server to client
(:return ((("MULTIPLE-VALUE-BIND" "28.67" ((0 "M") (8 "-V") (14 "-B")) "-f---m--")
("MOST-NEGATIVE-DOUBLE-FLOAT" "14.45" ((0 "M") (4 "-") (11 "V") (13 "-") (17 "B")) "b-------")
("MOST-POSITIVE-DOUBLE-FLOAT" "14.45" ((0 "M") (4 "-") (11 "V") (13 "-") (17 "B")) "b-------"))
NIL)
<request-id>)
serverとclientを同じプロセスで動かす
EmacsでSLIMEを使う場合はEmacs LispによるクライアントとCommon Lispによるswankサーバーという形で分けられています。
なのでEmacs Lispの編集にはSLIMEは使えませんが、Lemの場合はサーバーもクライアントも同じCommon Lispプロセス上で動かせるので、
Lem側でmicrosサーバーを立ち上げることでLem本体の開発に対してもIDEの恩恵を受けることが出来ます。
これは一つの言語で完結しているメリットと言えるかもしれません。
また、LemではLisp Modeが有効になればバックグランドで自動で接続されるようになっているので、ユーザーはそれを意識する必要はありません。
おわりに
九日目はこれで終わりです。
次回はLisp Modeの他の機能についての詳細について見ていきたいと思います。
Discussion