Alive 拡張機能は VSCode を強力な Common Lisp の開発プラットフォームにします。 対象プラットフォーム上で動作する Common Lisp の処理系以外に依存はありません。現在は次に対応しています。
- シンタックスハイライト
- コード補完
- コードフォーマッタ
- 定義へのジャンプ
- スニペット
- REPL 統合
- 対話的デバッガ
- REPL の履歴
- インライン評価
- マクロ展開
- 逆アセンブル
- インスペクタ
- ホバーテキスト
- 関数の引数や let の束縛のリネーム
- コードの折りたたみ

前提条件
VSCode の Alive 拡張機能は ANSI Common Lisp と互換性があり、Alive REPL が正常に起動する限り、これらの手順はどの処理系でも動くはずです。例ではすべて SBCL を使います。
VSCode を REPL に接続する

- VSCode 内で、編集したい lisp ファイルを開きます。
- まだない場合は、
hello.lispという新しいファイルを作成します。
- まだない場合は、
- VSCode 内で、上部メニューの
View/Command Paletteから Command Palette を開き、Alive: Start REPL And Attachを選んで、VSCode の REPL に接続された Swank サーバーを動かす SBCL インスタンスを起動します。REPL Connectedと書かれた小さなウィンドウがポップアップします。REPL Connectedメッセージが出ない場合は、上部メニューのView:Outputから VSCode の Output を開き、プルダウンでSwank Traceを選びます。この出力は実行中の lisp イメージからの出力で、何がうまくいっていないのかを調べる出発点になります。
これで、稼働中の SBCL イメージのポート 4005 で動く Swank サーバーに接続された REPL を持つ VSCode インスタンスができました。ファイル内の文を評価でき、それらは実行中の SBCL インスタンスで処理されます。
REPL を切断し、SBCL インスタンスを終了するには、上部メニューの View/Command
Palette から Command Palette を開き、Alive: Detach from REPL を選びます。
すべての操作にはキーバインドがあります。必要に応じて調べ、変更してください。
レシピ
特に明記しない限り、すべてのレシピは、VSCode でファイルを開き、REPL が接続されている状態を前提とします。
式を評価するときは、評価したい S 式の中、または直後のどこかにカーソルを置いて、評価する式を選びます。
文をインラインで評価する

- エディタウィンドウの開いているファイルに、次を入力します。
(+ 2 2)
- 上部メニューの
View/Command Paletteから Command Palette を開き、Alive: Inline Evalを選びます。 -
=> 4 (3 bits, #x4, #o4, #b100)と書かれた小さなポップアップが表示されます。これが結果です。文をインラインで評価することは、それを REPL に送ることとまったく同じです。違いは表示方法だけです。
文を評価する

- エディタウィンドウの開いているファイルに、次を入力します。
(+ 2 2)
- 上部メニューの
View/Command Paletteから Command Palette を開き、Alive: Send To REPLを選びます。 - 式が REPL に表示され、結果も一緒に表示されます。
CL-USER>
(+ 2 2)
4
CL-USER>
ファイルをコンパイルする

- エディタウィンドウの開いているファイルに、次を入力します。
(+ 2 2)
- 上部メニューの
View/Command Paletteから Command Palette を開き、Alive: Compileを選びます。 - REPL にコンパイルの詳細が表示され、ファイルシステムに fasl ファイルができます。
CL-USER>
; compiling file "/Users/jason/Desktop/hello.lisp" (written 14 SEP 2021 04:24:37 AM):
; wrote /Users/jason/Desktop/hello.fasl
; compilation finished in 0:00:00.001
対話的デバッガを使って中断する

- エディタウィンドウの開いているファイルに、次を入力します。
(defun divide (x y)
(/ x y))
- まだそうなっていなければ、最後の括弧の後にカーソルを置きます。上部メニューの
View/Command Paletteから Command Palette を開き、Alive: Inline Evalを選んで、defineした関数を image にロードします。 - 開いているファイルに新しい行を追加し、次を入力します。
(divide 1 0)
- まだそうなっていなければ、最後の括弧の後にカーソルを置きます。上部メニューの
View/Command Paletteから Command Palette を開き、Alive: Inline Evalを選んで、divide 関数を image 内で実行します。 - 対話的デバッガがポップアップします。
Restartsの節で、選択肢 2 を選んで中断します。 - エディタとまだ動いている REPL に戻り、何も起きなかったかのように続けられます。
対話的デバッガを使って実行時に問題を修正する

- エディタウィンドウの開いているファイルに、次を入力します。
(defun divide (x y)
(assert (not (zerop y))
(y)
"The second argument can not be zero.")
(/ x y))
- まだそうなっていなければ、最後の括弧の後にカーソルを置きます。上部メニューの
View/Command Paletteから Command Palette を開き、Alive: Inline Evalを選んで、defineした関数を image にロードします。 - 開いているファイルに新しい行を追加し、次を入力します。
(divide 1 0)
- まだそうなっていなければ、最後の括弧の後にカーソルを置きます。上部メニューの
View/Command Paletteから Command Palette を開き、Alive: Inline Evalを選んで、divide 関数を image 内で実行します。 - 対話的デバッガがポップアップします。
Restartsの節で、選択肢 0 の “Retry assertion with new value for Y” を選びます。 - ポップアップメニューに
y'と入力します。 - 次のポップアップメニューに
1と入力します。 => 1 (1 bit, #x1, #o1, #b1)と書かれた小さなポップアップが表示されるはずです。これは新しい値の結果です。デバッガへクラッシュした後、クラッシュの原因になった値を変更させてもらい、誤った0という値を入力しなかったかのように処理を進めた状態で、エディタとまだ動いている REPL に戻っています。
デバッガでできることのさらなるアイデアはエラー処理のページにあります。
マクロを展開する

- エディタウィンドウの開いているファイルに、次を入力します。
(loop for x in '(a b c d e) do
(print x))
- まだそうなっていなければ、最後の括弧の後にカーソルを置きます。上部メニューの
View/Command Paletteから Command Palette を開き、Alive: Macro Expandを選んで for-loop マクロを展開します。 - 次のようなものが見えるはずです。
(BLOCK NIL
(LET ((X NIL)
(#:LOOP-LIST-559
(SB-KERNEL:THE* (LIST :USE-ANNOTATIONS T
:SOURCE-FORM '(A B C D E))
'(A B C D E))))
(DECLARE (IGNORABLE #:LOOP-LIST-559)
(IGNORABLE X))
(TAGBODY
SB-LOOP::NEXT-LOOP
(SETQ X (CAR #:LOOP-LIST-559))
(SETQ #:LOOP-LIST-559 (CDR #:LOOP-LIST-559))
(PRINT X)
(IF (ENDP #:LOOP-LIST-559)
(GO SB-LOOP::END-LOOP))
(GO SB-LOOP::NEXT-LOOP)
SB-LOOP::END-LOOP)))
関数を逆アセンブルする

- エディタウィンドウの開いているファイルに、次を入力します。
(defun hello (name)
(format t "Hello, ~A~%" name))
- まだそうなっていなければ、最後の括弧の後にカーソルを置きます。上部メニューの
View/Command Paletteから Command Palette を開き、Alive: Inline Evalを選んで関数を image にロードします。 - まだそうなっていなければ、最後の括弧の後にカーソルを置きます。上部メニューの
View/Command Paletteから Command Palette を開き、Alive: Disassembleを選んでコンパイル済み関数の機械語を出力します。 - 次のように始まります。
; disassembly for HELLO
; Size: 172 bytes. Origin: #x70052478B4 ; HELLO
; 8B4: AC0A40F9 LDR R2, [THREAD, #16] ; binding-stack-pointer
; 8B8: 4C0F00F9 STR R2, [CFP, #24]
; 8BC: AC4642F9 LDR R2, [THREAD, #1160] ; tls: *STANDARD-OUTPUT*
; 8C0: 9F8501F1 CMP R2, #97
; 8C4: 61000054 BNE L0
; 8C8: 4AFDFF58 LDR R0, #x7005247870 ; '*STANDARD-OUTPUT*
; 8CC: 4C1140F8 LDR R2, [R0, #1]
; 8D0: L0: 4C1700F9 STR R2, [CFP, #40]
; 8D4: E0031BAA MOV NL0, CSP
; 8D8: 7A0701F8 STR CFP, [CSP], #16
; 8DC: EAFCFF58 LDR R0, #x7005247878 ; "Hello, "
; 8E0: 4B1740F9 LDR R1, [CFP, #40]
; 8E4: B6FBFF58 LDR LEXENV, #x7005247858 ; #<SB-KERNEL:FDEFN WRITE-STRING>
; 8E8: 970080D2 MOVZ NARGS, #4
; 8EC: FA0300AA MOV CFP, NL0
; 8F0: DE9240F8 LDR LR, [LEXENV, #9]
; 8F4: C0033FD6 BLR LR
; 8F8: 3B039B9A CSEL CSP, OCFP, CSP, EQ
; 8FC: E0031BAA MOV NL0, CSP
; 900: 7A0701F8 STR CFP, [CSP], #16
; 904: 4A2F42A9 LDP R0, R1, [CFP, #32]
; 908: D6FAFF58 LDR LEXENV, #x7005247860 ; #<SB-KERNEL:FDEFN PRINC>
; 90C: 970080D2 MOVZ NARGS, #4
; 910: FA0300AA MOV CFP, NL0
; 914: DE9240F8 LDR LR, [LEXENV, #9]
; 918: C0033FD6 BLR LR
; 91C: 3B039B9A CSEL CSP, OCFP, CSP, EQ
; 920: E0031BAA MOV NL0, CSP
; 924: 7A0701F8 STR CFP, [CSP], #16
; 928: 2A4981D2 MOVZ R0, #2633
; 92C: 4B1740F9 LDR R1, [CFP, #40]
; 930: D6F9FF58 LDR LEXENV, #x7005247868 ; #<SB-KERNEL:FDEFN WRITE-CHAR>
; 934: 970080D2 MOVZ NARGS, #4
; 938: FA0300AA MOV CFP, NL0
; 93C: DE9240F8 LDR LR, [LEXENV, #9]
; 940: C0033FD6 BLR LR
; 944: 3B039B9A CSEL CSP, OCFP, CSP, EQ
; 948: EA031DAA MOV R0, NULL
; 94C: FB031AAA MOV CSP, CFP
; 950: 5A7B40A9 LDP CFP, LR, [CFP]
; 954: BF0300F1 CMP NULL, #0
; 958: C0035FD6 RET
; 95C: E00120D4 BRK #15 ; Invalid argument count trap
Common Lisp システムのひな形を作成する

このレシピは新しい Common Lisp システムを作成するため、稼働中の REPL は不要です。
- 新しいプロジェクト用に
experimentというフォルダを作成します。 - 新しく作成したディレクトリで vscode を開きます。
cd experiment
code .
- 新しい Common Lisp システムを作成します。
- VSCode 内で、上部メニューの
View/Command Paletteから Command Palette を開き、システムのひな形を生成します:Alive: System Skeleton - 前のコマンドは、次のディレクトリ構成を生成しているはずです。
- experiment.asd
- src/
- app.lisp
- test/
- all.lisp
- VSCode 内で、上部メニューの
それらのファイルの内容は次のとおりです。
experiment.asd:
(in-package :asdf-user)
(defsystem "experiment"
:class :package-inferred-system
:depends-on ("experiment/src/app")
:description ""
:in-order-to ((test-op (load-op "experiment/test/all")))
:perform (test-op (o c) (symbol-call :test/all :test-suite)))
(defsystem "experiment/test"
:depends-on ("experiment/test/all"))
(register-system-packages "experiment/src/app" '(:app))
(register-system-packages "experiment/test/all" '(:test/all))
src/app.lisp:
(defpackage :app
(:use :cl))
(in-package :app)
test/all.lisp:
(defpackage :test/all
(:use :cl
:app)
(:export :test-suite))
(in-package :test/all)
(defun test-suite ()
(format T "Test Suite~%"))
任意のカスタム設定
Quicklisp と連携するよう VSCode Alive を設定する
quicklisp がインストール済みで、初期化時にロードされるよう設定されていると仮定すると、quicklisp はそのまま動きます。
既定のコンテキストの CLPM と連携するよう VSCode Alive を設定する
CLPM がインストール済みかつ設定済みであると仮定し、vscode の設定を変更して次のようにします。
- VSCode の設定に次を追加します。
"alive.swank.startupCommand":[
"clpm",
"exec",
"--",
"sbcl",
"--eval",
"(asdf:load-system :swank)",
"--eval",
"(swank:create-server)"
],
これは既定の clpm コンテキストで sbcl を起動します。
bundle の clpmfile を使う CLPM と連携するよう VSCode Alive を設定する
CLPM がインストール済みかつ設定済みであり、 ホームディレクトリのルートに swank を開発用の依存として含む bundle が設定されていると仮定し、vscode の設定を変更して次のようにします。
- VSCode の設定に次を追加します。
"alive.swank.startupCommand":[
"clpm",
"bundle",
"exec",
"--",
"sbcl",
"--eval",
"(asdf:load-system :swank)",
"--eval",
"(swank:create-server)"
],
これは bundle の clpm コンテキストで sbcl を起動します。
Roswell と連携するよう VSCode Alive を設定する
Roswell がインストール済みであると仮定し、 vscode の設定を変更して次のようにします。
"alive.swank.startupCommand": [
"ros",
"run",
"--eval",
"(require :asdf)",
"--eval",
"(asdf:load-system :swank)",
"--eval",
"(swank:create-server)"
]
VSCode Alive を Docker コンテナに接続する

これらの手順は、リモート接続、wsl 接続、github Codespaces でも、それぞれ Remote - SSH、Remote -
WSL、Github Codespaces の拡張機能を使って動きます。拡張機能がインストールされていることを前提とします。この例では、Containers 拡張機能がインストール済みかつ設定済みであることを確認してください。
- sbcl がインストールされた docker イメージを pull します。この例では最新の clfoundations sbcl を使います。
docker pull clfoundation/sbcl
- docker イメージ内で bash を実行し、起動して動かし続けます。
docker run -it clfoundation/sbcl bash
- VSCode の Side Bar で
Remote Explorerのアイコンをクリックします。 - Dev Containers の一覧で clfoundation/sbcl を右クリックし、
Attach to Containerを選びます。 - 開いた新しい VSCode ウィンドウの Side Bar で、
Explorerをクリックします。ファイルがまだ表示されていない場合は、コンテナ内のファイルを表示するよう指定する必要があるかもしれません。 - コンテナ内のファイルを表示できたら、VSCode の
Side Bar内で右クリックし、New Fileを選びます。ファイル名をhello.lispにします。 - VSCode の Side Bar で
Extensionsのアイコンをクリックします。 AliveプラグインのInstall in Container...ボタンをクリックします。hello.lispファイルを開き、このレシピの冒頭にある “Connect VSCode to a REPL” の手順に従います。- これで、docker コンテナ内の SBCL イメージで動く Slime サーバーに接続された REPL を持つ VSCode が 動いています。
Page source: ja/vscode-alive.md