【SLIME】
REPLプロンプトにパッケージ名を表示する
(slime-current-package)

関連記事

1. SLIMEのプロンプトとパッケージ名

以前に、SLIMEのREPLプロンプトを CL-USER> から * に変更しました。

しかし、しばらく使っていると、別のパッケージに切り替えたとき、今どこにいるかわからなくなる問題に気づきました。
そこで、デフォルトパッケージのときだけ * を表示し、それ以外はパッケージ名を出す方法に切り替えました。

1. SLIMEのプロンプトとパッケージ名

1.1. COMMON-LISP-USER とは何か

Common Lispのデフォルトパッケージは COMMON-LISP-USER で、CL-USER はそのニックネームです。

このパッケージは COMMON-LISP パッケージを use した状態で用意されています。
標準シンボルである defuncar は、COMMON-LISPにあります。
自分でパッケージを定義するときに (:use :cl) を省くと、defun を書くのにも cl:defun と修飾が必要になります。

ライブラリ作者は、あえて(:use :cl) を省いて、意図せずに cl のシンボルを外部に公開しないようにすることもあります。

2. カスタマイズの方針

現在のパッケージ名は、slime-current-package 関数で取得できます。

SBCLでは "COMMON-LISP-USER" のように大文字の文字列が返ります。
これを使って、次のように振る舞いを分けます。

  • COMMON-LISP-USER のとき → *
  • それ以外のとき → MY-PACKAGE>

処理系によっては挙動が異なる可能性があるので、M-:(slime-current-package) を評価して確認しておくと安心です。
CL-USER という文字列が返ってくる場合は、my-slime-prompt-string の比較対象を変更してください。

(with-eval-after-load 'slime-repl

  (defun my-slime-prompt-string ()
    (if (string= (slime-current-package) "COMMON-LISP-USER")
        "* "
      (concat (slime-current-package) "> ")))

  (defun my-slime-insert-prompt-string (prompt)
    (slime-propertize-region
     '(face slime-repl-prompt-face
       read-only t
       slime-repl-prompt t
       rear-nonsticky t
       front-sticky (read-only)
       inhibit-line-move-field-capture t
       field output)
     (insert-before-markers prompt)))

  (defun my-slime-repl-insert-prompt ()
    (goto-char slime-repl-input-start-mark)
    (unless slime-repl-suppress-prompt
      (slime-save-marker slime-output-start
        (slime-save-marker slime-output-end
          (unless (bolp)
            (insert-before-markers "\n"))
          (let ((prompt-start (point)))
            (my-slime-insert-prompt-string (my-slime-prompt-string))
            (set-marker slime-repl-prompt-start-mark prompt-start)
            (setq buffer-undo-list nil)
            prompt-start)))))

  (advice-add 'slime-repl-insert-prompt :override #'my-slime-repl-insert-prompt))Code language: Lisp (lisp)
  • my-slime-prompt-string は、パッケージ名を見てプロンプト文字列を返します。
    ここだけ変えれば表示形式を自由に調整できます。
  • my-slime-insert-prompt-string はプロンプトにテキストプロパティを付けて挿入します。
    read-only t によってユーザーがプロンプト部分を誤って編集できないようになっています。
    slime-propertize-region はSLIME側が用意しているユーティリティです。
  • my-slime-repl-insert-prompt は位置の制御とマーカーの保護を担います。
    slime-save-marker で出力の開始・終了マーカーを守りながら、上の2つの関数を呼びます。

最後に advice-add:override を指定し、SLIMEの元の関数をこの実装で完全に置き換えます。

3. 動作確認

M-x slime でREPLを起動すると、プロンプトが * になっています。

別のパッケージに切り替えてみます。

* (defpackage :my-package
    (:use :cl))
* (in-package :my-package)
MY-PACKAGE> Code language: Lisp (lisp)

COMMON-LISP-USER に戻すと * に戻ります。

MY-PACKAGE> (in-package :cl-user)
* Code language: Lisp (lisp)