WSL2上でRust開発環境を整える（4日目）

手戻りが...

[1日目](https://qiita.com/doshiyo/items/1b3baceb831268714495)
[2日目](https://qiita.com/doshiyo/items/9f6c2f8fb6f1a06393f3)
[3日目](https://qiita.com/doshiyo/items/8939ab0bc094cdf5182f)

## COCからBultIn LSPへ移行

[rust-tools](https://github.com/simrat39/rust-tools.nvim) が coc に対応していなさそう。
仕方なくcocからBuiltIn LSPへ移行。

あと、lazy.nvim で初期化処理をなんでもかんでも `config` に突っ込むのは行儀が悪そう。
キーマップとかは `init` に移動。

参考記事

https://zenn.dev/botamotch/articles/21073d78bc68bf

https://zenn.dev/ryoppippi/articles/8aeedded34c914

とりあえず、動いてるやつはこんな感じ。

```lua:~/.config/nvim/lua/plugin.lua
require('lazy').setup({
  ...
  -- setupの最後に追加
  {
    'neovim/nvim-lspconfig',
    dependencies = { 'folke/neoconf.nvim' },
    config = function ()
      -- neoconfはlspの初期化前にsetupする必要がある
      require("neoconf").setup({})
    end
  },
  {
    'williamboman/mason.nvim',
    config = function ()
      require('mason').setup()
    end,
  },
  {
    'williamboman/mason-lspconfig.nvim',
    dependencies = { 'neovim/nvim-lspconfig', 'hrsh7th/cmp-nvim-lsp' },
    config = function ()
      require('mason-lspconfig').setup({
        ensure_installed = {
          "lua_ls",
          "rust_analyzer",
        },
      })
    end,
    init = function ()
      require('mason-lspconfig').setup_handlers({ function (server)
        local opt = {
          capabilities = require('cmp_nvim_lsp').default_capabilities(
            --vim.lsp.protocol.make_client_capabilities()
          )
        }
        require('lspconfig')[server].setup(opt)
      end })
    end,
  },
  {
    'hrsh7th/nvim-cmp',
    dependencies = {
      'hrsh7th/vim-vsnip',
      'hrsh7th/cmp-path',
      'hrsh7th/cmp-buffer',
      'hrsh7th/cmp-cmdline',
    },
    config = function ()
      local cmp = require('cmp')
      cmp.setup({
        snippet = {
          expand = function (args)
            vim.fn['vsnip#anonymous'](args.body)
          end,
        },
        sources = cmp.config.sources({
          { name = 'nvim_lsp' },
          { name = 'vsnip' },
        }, {
          { name = 'buffer' }
        }),
        mapping = cmp.mapping.preset.insert({
          ["<Tab>"] = cmp.mapping.select_next_item(),
          ["<S-Tab>"] = cmp.mapping.select_prev_item(),
          ["<C-space>"] = cmp.mapping.complete(),
          --["<C-e>"] = cmp.mapping.abort(),
          ["<CR>"] = cmp.mapping.confirm({ select = true })
        }),
        experimental = {
          ghost_text = true,
        },
      })

      cmp.setup.filetype('gitcommit', {
        sources = cmp.config.sources({
          { name = 'git' },
        }, {
          { name = 'buffer' },
        })
      })

      cmp.setup.cmdline({ '/', '?' }, {
        mapping = cmp.mapping.preset.cmdline(),
        sources = {
          { name = 'buffer' },
        }
      })

      cmp.setup.cmdline(':', {
        mapping = cmp.mapping.preset.cmdline(),
        sources = cmp.config.sources({
          { name = 'path' }
        }, {
          { name = 'cmdline' }
        }),
      })
    end,
  },
  {
    "ray-x/lsp_signature.nvim",
    event = "VeryLazy",
    opts = {
      toggle_key = '<C-p>',
    },
    config = function(_, opts) require'lsp_signature'.setup(opts) end,
    init = function ()
      vim.api.nvim_create_autocmd("LspAttach", {
        callback = function (args)
          local buffer = args.buf
          --local client = vim.lsp.get_client_by_id(args.data.client_id)
          require('lsp_signature').on_attach({}, buffer)
        end
      })
    end
  },
})
```

LSPのキーマップも追加
```lua:~/.config/nvim/lua/keymap.lua
vim.keymap.set('i', 'jj', '<Esc>', { noremap = true })

vim.keymap.set('n', 'K',  '<cmd>lua vim.lsp.buf.hover()<CR>')
vim.keymap.set('n', 'gf', '<cmd>lua vim.lsp.buf.formatting()<CR>')
vim.keymap.set('n', 'gr', '<cmd>lua vim.lsp.buf.references()<CR>')
vim.keymap.set('n', 'gd', '<cmd>lua vim.lsp.buf.definition()<CR>')
vim.keymap.set('n', 'gD', '<cmd>lua vim.lsp.buf.declaration()<CR>')
vim.keymap.set('n', 'gi', '<cmd>lua vim.lsp.buf.implementation()<CR>')
vim.keymap.set('n', 'gt', '<cmd>lua vim.lsp.buf.type_definition()<CR>')
vim.keymap.set('n', 'gn', '<cmd>lua vim.lsp.buf.rename()<CR>')
vim.keymap.set('n', 'ga', '<cmd>lua vim.lsp.buf.code_action()<CR>')
vim.keymap.set('n', 'ge', '<cmd>lua vim.diagnostic.open_float()<CR>')
vim.keymap.set('n', 'g]', '<cmd>lua vim.diagnostic.goto_next()<CR>')
vim.keymap.set('n', 'g[', '<cmd>lua vim.diagnostic.goto_prev()<CR>')
```

ついでに `temp.lua` を卒業。
```lua:~/.config/nvim/lua/base.lua
-- クリップボード
vim.opt.shortmess:append("c")
vim.opt.clipboard:append("unnamedplus")

vim.g.clipboard = {
  name = "WslClipboard",
  copy = {
     ["+"] = "win32yank.exe -i --crlf",
     ["*"] = "win32yank.exe -i --crlf",
   },
  paste = {
     ["+"] = "win32yank.exe -o --lf",
     ["*"] = "win32yank.exe -o --lf",
  },
  cache_enabled = 1,
}

-- Leaderキーの設定
vim.g.mapleader = " "
vim.g.maplocalleader = " "

local options = {
	encoding = "utf-8",
	fileencoding = "utf-8",
	title = true,
	backup = false,
	tabstop = 2,
	shiftwidth = 2,
	softtabstop = 2,
	expandtab = true,
	autoindent = true,
	copyindent = true,
	numberwidth = 4,
	wrap = false,
	cursorline = true,
	termguicolors = true,
	guifont = "HackGenNerd Console:style=Regular",
}

for k, v in pairs(options) do
  vim.opt[k] = v
end
```

```lua:~/.config/nvim/init.lua
require("base")
require("plugin")
require("keymap")
require("colorscheme")
-- 説明してないかもしれない。
require("autocmds")
```

完全に理解してないけど、なんとなく動いてるのでOK。
あとで整理するときにきちんと見る。

## デバッガーの導入

いろいろとドハマりして時間がかかってしまった。
Vim界隈のドキュメントは読み慣れてないとちょっと理解しにくい気がする。
単純にVimの理解が足りないのはある。

キーバインドはあとで設定するが、取り急ぎ動いたものを書き連ねる。
最終的に導入したのは以下の通り。

* [mfussenegger/nvim-dap](https://github.com/mfussenegger/nvim-dap)
* [jay-babu/mason-nvim-dap](https://github.com/jay-babu/mason-nvim-dap.nvim)
* [rust-lang/rust.vim](https://github.com/rust-lang/rust.vim)
* [simrat39/rust-tools.nvim](https://github.com/simrat39/rust-tools.nvim)
* [rcarriga/nvim-dap-ui](https://github.com/rcarriga/nvim-dap-ui)

```lua:~/.config/nvim/lua/plugin.lua
require('lazy').setup({
  ...
  -- setupの最後に追加
  { 'mfussenegger/nvim-dap' },
  {
    "jayp0521/mason-nvim-dap.nvim",
    config = function()
      require("mason-nvim-dap").setup({
        automatic_installation = true,
        ensure_installed = { "codelldb" },
      })
    end,
  },
  {
    'rust-lang/rust.vim',
    init = function ()
      vim.g.rustfmt_autosave = 1
    end,
  },
  {
    'simrat39/rust-tools.nvim',
    ft = 'rust',
    dependencies = {
      'mfussenegger/nvim-dap',
      'rcarriga/nvim-dap-ui',
    },
    config = function ()
      local mason_registry = require("mason-registry")
      local codelldb_root = mason_registry.get_package("codelldb"):get_install_path() .. "/extension/"
      local codelldb_path = codelldb_root .. "adapter/codelldb"
      local liblldb_path = codelldb_root .. "lldb/lib/liblldb.so"
      local rt = require('rust-tools')
      rt.setup({
        tools = {
          hover_actions = {
            -- 調査中にこれがfalseになっているものに出会ったが
            -- これがfalseだとFloating Windowが表示されたときにフォーカスが移らずドハマり。
            auto_focus = true,
          },
        },
        server = {
          on_attach = function(_, bufnr)
            require('dap')
            require('dapui')
            vim.keymap.set('n', '<C-space>', rt.hover_actions.hover_actions, { buffer = bufnr })
          end,
          standalone = true,
          flags = {
            debounce_text_changes = 150,
          },
          settings = {
            ["rust_analyzer"] = {
              checkOnSave = { enable = true, command = 'clippy' },
              cargo = { allFeatures = true },
            },
          },
        },
        dap = {
          adapter = require('rust-tools.dap').get_codelldb_adapter(codelldb_path, liblldb_path)
        },
      })
    end,
  },
})
```

Masonで `codelldb` をインストールする必要がある。
一応 `cpptools` もインストールしておく。
```vim
:MasonInstall codelldb
:MasonInstall cpptools
```

### 動作確認

```zsh
mkdir ~/workspace
cd ~/workspace
cargo new hello_world
cd hello_world
nvim src/main.rt
```
`main` にカーソルを合わせて `C-space` で実行できる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90538/46b658bf-6bbd-66e5-6069-6f040b29d1e9.png)

キーマップ設定してないのでブレークポイントの設定面倒だけど、
`:lua require'dap'.toggle_breakpoint()` でブレークポイントを設定してデバッグ実行すればきちんと止まる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90538/14db28ab-90a0-e9cc-8652-fb03ca904bc6.png)

`:lua require'dap'.continue()` で再開できるし、`:lua require'dap'.step_over()` でステップオーバーできる。
nvim-dap はキーマップしとかないと使い物ならないが、取り急ぎ動作確認はできたからヨシ。

---
明日の夜くらいに今回の設定を清書してGitHubに上げる予定。

https://github.com/marudashiteru/dotfiles