15
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ZOZOAdvent Calendar 2021

Day 22

nvim-dapを利用したGo言語デバッグ

Last updated at Posted at 2021-12-21

はじめに

Go言語のデバッグどのようにしていますか?
printデバッグだったり、Delveを使ってCLIでやったり、IDEのデバッグ機能だったりかと思います。
私は、nvim-dapを利用して、Neovimでデバッグしているので、その紹介となります。

intro.gif

準備

下記プラグインを利用していきます。

Delveが必要になるのでインストールしておきましょう。

go install github.com/go-delve/delve/cmd/dlv@latest

実際に使ってみる

サンプルコードはこちらにあります。
サンプルコードをダウンロードして、下記コマンドを実行すれば、試す環境は用意できるかと思います。
※Neovimは、0.5.0以上推奨

nvim -u vimrc

実行可能なコマンドリストは、:h dap-apiで確認できます。

ブレークポイント貼る

まずはブレークポイントを貼ってみたいと思います。

:lua require'dap'.toggle_breakpoint()

dap-breakpoint.png

起動

nvim-dapでデバッグを実行するためには、下記を実行します。
すでに、nvim-dap-goプラグインによって設定されているリストが表示されていますので、Debug test (go.mod)の4を押してみましょう。

:lua require'dap'.continue()

dap-continue.png

UI表示

うまく起動できれば、Bの文字が、→の文字に変わっているかと思います。(分かりやすいようにハイライト設定もできます。)
ただ、ブレークポイントに止まっただけで何もわかりませんので、
nvim-dap-uiプラグインでUIを表示してみましょう。

:lua require'dapui'.toggle()

dap-ui.png

するとっぽいUI画面が出てきます。

画面説明

レイアウトは自分で設定できます。
私の設定は、

A: スコープ内の変数
B: 監視対象の変数 (insert modeで変数名を入力すれば、その変数の値をリアルタイムに表示してくれます)
C: スタックトレース
D: ブレークポイントの場所
F: インタープリター (dlvっぽく使えます)

dap-ui-layout.png

UI自動表示・自動非表示

毎回nvim-dap起動させて、UI起動させてーだと非常に面倒なので、
nvim-dap起動されたら、自動的にUI起動させるようにしました。
下記をvimrcに追加することで、自動で起動させるようになります。
※DAPのeventはこちらに一覧があります。

lua << EOF
  require'dap'.listeners.before['event_initialized']['custom'] = function(session, body)
    require'dapui'.open()
  end
EOF

下記も追加することで、nvim-dap終了時にUIを消すこともできます。
使い勝手が良いようにカスタマイズできそうですね。

lua << EOF
  require'dap'.listeners.before['event_terminated']['custom'] = function(session, body)
    require'dapui'.close()
  end
EOF

実践

:!go test

テストを実行してみて、エラーになりました。
nvim-dapを使ってデバッグしてみましょう!

さきほどと同じようにDebug test (go.mod)の4を選択します。
するとヌルポになるので、ブレークポイントを設定していなくても途中で止まります。
UIを起動し、スタックトレースから該当箇所に移動してみます。
aNum, bNumのどっちが、nilなのか調べるために値を確認します。(プラグインによりvirtual textで値が表示されていますが、あえてwatchesで値を確認してみます。
bNumがnilになっているので、確認すると、evil関数でnilになっていることがわかりますね!
こんな感じでデバッグできます。

dap-intro.gif

特定テスト関数のみ実行

毎回全体テストしていたら、無駄に時間がかかってしまいます。
特定テストのみ実行できれば良いので、カーソル近くのテスト関数のみを実行してみましょう。

まずは、依存関係であるTreesitterを入れておきます。(nvim-treesitterプラグイン)

:TSInstall go

下記を実行すると近くのテスト関数のみを実行することはできます。

:lua require'dap-go'.debug_test()

vim-testのストラテジーをカスタムしてみる

テスト実行には、vim-testを利用することが多いかと思いますが、
カーソル近くのテスト関数のみ実行するTestNearestコマンドがありますね。
vim-testは、strategyをカスタマイズできますので、vim-test → nvim-dap実行するstrategyを作ってみます。(VimScript → Lua関数呼び出しをスマートにしたい。

大まかな処理の流れ

  • go test -run 'TestAdd$' ./.のような文字列がくるので、args部分の-run 'TestAdd$'-test.run 'TestAdd$'に変換
  • program部分の./.を抽出 (pathはいい感じに調整)
  • dap設定に渡してあげて、nvim-dap起動
lua << EOF
  Dap = {}
  Dap.vim_test_strategy = {
    go = function(cmd)
      local test_func = string.match(cmd, "-run '([^ ]+)'")
      local path = string.match(cmd, "[^ ]+$")
      path = string.gsub(path, "/%.%.%.", "")
      configuration = {
        type = "go",
        name = "nvim-dap strategy",
        request = "launch",
        mode = "test",
        program = path,
        args = {},
      }
      if test_func then
        table.insert(configuration.args, "-test.run")
        table.insert(configuration.args, test_func)
      end
      if path == nil or path == "." then
        configuration.program = "./"
      end
      return configuration
    end,
  }
  function Dap.strategy()
    local cmd = vim.g.vim_test_last_command
    local filetype = vim.bo.filetype
    local f = Dap.vim_test_strategy[filetype]
    if not f then
      print("This filetype is not supported.")
      return
    end
    configuration = f(cmd)
    require'dap'.run(configuration)
  end
EOF
function! DapStrategy(cmd)
  echom 'It works! Command for running tests: ' . a:cmd
  let g:vim_test_last_command = a:cmd
  lua Dap.strategy()
endfunction
let g:test#custom_strategies = {'dap': function('DapStrategy')}

ストラテジーをdapに設定することで、nvim-dapを起動できるようになりました。

:TestNearest -strategy=dap

TestNearestの挙動しか確認していないので、他だとうまく動かないかもしれないです。

まとめ

Go言語を触りはじめのときは、printデバッグ、dlvでのCLIデバックから、nvim-dapによるデバッグというような感じでデバッグ方法は推移していきました。
デバッグ環境を快適にしておくことで、問題解決までの時間を大幅に削減できるかと思うので、
この機会に是非デバック環境を整えて、より良いVimライフを送れるようにしておきましょう。

15
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?