Emacs+MetalsでScalaのデバッガを使う

こういう話がありました。

Feature Request : Support for scala in dap-mode · Issue #196 · emacs-lsp/dap-mode を見てもdap-modeの使い方がよく分からなかったし別に時間をかける所じゃないなと思ったので、デバッグする時だけはIntelliJを使うことにしようとしたのですが、私の環境だとUIが崩壊してデバッグ設定以前の問題になってしまいます。

実はMetalsの(というかlsp-mode+dap-modeの)デバッガはいま普通に機能するけど、確かに使い方(使える状態にするコツ)がちょっとむずかしい感じがしますね。実際にはやることはあんまりないんだけど、いざやろうとすると時間を食うと思うので、時間を食われてやった側の人間としてやり方を書き記しておこうと思います。本当は最近のEmacsのモダンな環境ぜんぶ紹介するみたいなのを書いてそこで(他の言語の場合も含めて)書くつもりだったけど、取り急ぎScalaのことだけ書きます。

設定方法

実はこれだけ。

(add-hook 'lsp-mode-hook 'dap-mode)
(add-hook 'lsp-mode-hook 'dap-ui-mode)
(add-hook 'lsp-mode-hook 'lsp-lens-mode) ; これはdap-modeに必須ではないがScalaではほぼ必要

参考までに僕が実際に使っている設定を貼っておきます。

デバッガの使い方

lsp-modeというかdap-modeでのデバッガを利用するには、普通なら、M-x dap-debug-edit-templateデバッグテンプレートを書くか、dap-modeの各言語サポートで用意されているテンプレートを用いることになります。たとえばGoだとM-x dap-debugすると一覧が現れてGo Attach Executable Configurationを選ぶと実行中のプロセスに対してプロセスID指定でアタッチしてデバッグを開始できます。しかしScala(Metals)では(まだ)デバッグテンプレートが提供されていません。かと言って自分で書ける気がしない...... (書こうとしたことあるんだけど、なんかうまくいった試しがない。)

実はMetalsではM-x dap-debugするよりもっと簡単なやり方があって、それはCode Lensを使う方法。というかおそらくEmacs上ではいまこれがMetalsでデバッグ開始する唯一の方法なんじゃないかと思います。(リモートデバッグもBloopで最近サポートされたのでデバッグテンプレートちゃんと書けば動きそうではある。)

lsp-lens-modeを有効にしていると、mainメソッドを持つクラス(やオブジェクト)に対してrun|debugが表示されるようになります(コンパイルのタイミングとかで出ないときがあるのでそういうときは頃合いを見てM-x revert-bufferするとよさそう)。

あとはM-x lsp-avy-lens等でdebugのCode Lensを選択すると、デバッガが立ち上がります。M-x dap-breakpoint-toggleブレークポイント張れるし、M-x dap-nextで次のステップに進んだりできます(コマンド一覧はこちら)。

ちなみに、どういう原理なのかは知らないけどmainメソッドを直書きしてなくてもScalaTestなどのテストクラスにもCode Lens出るので、特定のテストクラスだけ単体で実行するのもこれでやれて非常にべんりです。

蛇足: デバッガ本当に使うのか

別記事にしました: