【Mac】Lazy.nvimでPythonとLuaのLSP環境を構築する方法

24 min

こんにちは。ナミレリです。この記事ではNeovimのプラグインマネージャであるLazy.nvimを使って、PythonとLuaのLSP(Language Server Protocol)環境を構築する方法を紹介します。

以前に、プラグインマネージャのPacker.nvimを使ったLSP環境の構築方法の記事を書きましたが、パッケージマネージャを現在の主流であるLazy.nvimに移行し、Neovim全体の設定ファイルを見直しました。

Lazy.nvimに移行してみた感想ですが、Lazy.nvimはUIも快適で、何より高速なでパフォーマンスが高く、プラグインの読み込み遅延を細かく設定できる点が気に入っています。

Alacritty + tmux + starship + Neovim / Alpha.nvimの起動画面

Alacritty + tmux + starship + Neovim / Alpha.nvimの起動画面
Alacritty + tmux + starship + Neovim / Alpha.nvimの起動画面
Lazy.nvimの導入や初期設定について

Lazy.nvimの導入や初期設定については下の記事を参考にしてください。

この記事はこんな人にオススメ

  • NeovimでLSP環境を構築したいが難しそう
  • Pythonでプログラミングすることが好きな方
  • Neovimの設定をLuaでカスタマイズすることが好きな方
  • Neovimを使い始めたばかりの方
  • Neovimを使い始めたが、より深く活用したいと考えている方
この記事のMac環境
Parallels Desktop 20 for Macの無料トライアル もありますので、ぜひダウンロードして試してみてください。M1/M2/M3のMac上で快適にMacやUbuntu、Windowsが動作します。

LSP系のプラグインの相互関係と役割

まずは、今回インストールし設定するLPS関連のプラグインの関係と役割について、概要を説明します。

以下、簡単ですが図にしてみました。

pyrightなどのLSPの管理・設定にmason、mason-lspconfig、nvim-lspconfigの3つのプラグインを使い、blackやisortなどのフォーマッターやリンターなどのツール系の管理・設定にmason、mason-null-ls、none-lsの3つのプラグインを使います。

LSP関連のプラグインの相互関係

LSP系プラグインの相互関係
LSP系プラグインの相互関係

LSP関連のプラグインの役割

プラグイン役割
mason.nvimLSPやフォーマッター、リンターなどのツールを
インストール・管理するプラグイン。
mason-lspconfig.nvimmason.nvimでインストールされたLSPを
nvim-lspconfigと自動的に連携させるプラグイン。
nvim-lspconfig LSPをNeovimで使用するための設定を
簡素化するプラグイン。
mason-null-ls.nvimmason.nvimでインストールされた
フォーマッターやリンター等を
none-ls.nvimで使用できるように連携するプラグイン。
none-ls.nvimLSP以外のフォーマッターやリンターを
LSPクライアントとして使用するためのプラグイン。
LSP関連のプラグインの役割

mason.nvim

LSPやフォーマッター、リンターなどのツールをインストール・管理するプラグイン。

  • 役割: masonは、LSP、Lintツール、フォーマッターなどの開発ツールを簡単にインストールし、管理するためのNeovimプラグインです。コマンド一つで必要なツールをインストールし、NeovimのLSPエコシステムと連携させます。公式リポジトリからLSPを自動的にインストールし、バージョン管理や依存関係の解決も行ってくれます。
  • 関係性: masonlspconfigと連携して、ユーザーが必要とする言語サーバーやツールのインストールを担当します。lspconfigで設定されたLSPをmasonを通じて簡単にインストールできます。

mason-lspconfig.nvim

mason.nvimでインストールされたLSPをnvim-lspconfigと自動的に連携させるプラグイン。

  • 役割: lspconfigでセットアップフックを登録すると、mason.nvimでインストールされたLSPを必要な設定でセットアップします。
  • 関係性: mason.nvimでインストールされたLSPをnvim-lspconfigと自動的に連携させるプラグイン。

nvim-lspconfig.nvim

LSPをNeovimで使用するための設定を簡素化するプラグイン。

  • 役割: lspconfigは、Neovimの内蔵LSPクライアントの設定を簡単にするためのプラグインです。各言語サーバーの設定テンプレートを提供し、ユーザーは必要最低限の設定のみを行うことでLSPを利用できるようにするプラグインです。
  • 関係性: lspconfigは、LSPの設定の基礎となります。

mason-null-ls.nvim

mason.nvimでインストールされたフォーマッターやリンター等をnone-ls.nvimで使用できるように連携するプラグイン。

  • 役割: mason-null-ls.nvimは、masonnull-lsを連携させるプラグインです。masonでインストール可能なLintツールやフォーマッターを自動的にnone-ls(null-ls)に統合し、設定を簡単にします。
  • 関係性: このプラグインはmasonnone-ls(null-ls)の橋渡しをする役割です。

none-ls.nvim

LSP以外のフォーマッターやリンターをLSPクライアントとして使用するためのプラグイン。

  • 役割: null-lsは、LSPプロトコルをサポートしていないツール(フォーマッター、リンターなど)をLSPクライアントとして使えるようにするプラグインです。
null-ls.nvimnone-lsについて

null-lsは2023年8月11日以降、アーカイブされ更新されないとのことです。
https://github.com/jose-elias-alvarez/null-ls.nvim/issues/1621

none-lsは、プラグインマネージャでjose-elias-alvarez/null-ls.nvimnvimtools/none-ls.nvimに置き換えるだけで、null-lsの設定はそのままで使うことができます。

null-ls.nvimnone-lsについて、以下のサイトを参考にさせていただきました。

より詳しくは

以下の2つのサイトにはより詳しいLSP系の各プラグインの説明がされていて参考にさせていただきました。

Pythonユーザーにおすすめの本

「自分が書いたコードは、仕事で通用するか不安……」

「動くものは作れる。そこからどう上達すればいい?」

そんな悩みを抱えるあなたに、VTuberサプーがPythonでのコードの書きかたをお教えします! 本書は、コードの見た目の整えかたから、読みやすさ、シンプルさ、安全性……などを意識した「プロ」の知識とテクニックをまとめました。中の人のエンジニア経験から得た知見をもとに解説しているので、実際に現場でちゃんと役立つコードに改善できます。この1冊で、自分の書くコードをワンランクアップさせましょう!

Amazon

VTuberサプーが教える! Python 初心者のコード/プロのコード

補完系プラグインとアイコン

以下は、補完系の便利で素晴らしいプラグインです。LSPの補完候補を表示するhrsh7th/cmp-nvim-lspをはじめ、この記事では下記のプラグインもインストールしていきます。

補完系プラグイン説明
hrsh7th/cmp-nvim-lspLSPから提供される補完候補を
nvim-cmpで利用するプラグイン
hrsh7th/cmp-buffer現在のバッファにある単語を
補完するプラグイン
hrsh7th/cmp-pathファイルシステムの
パス補完するプラグイン
hrsh7th/cmp-cmdlineコマンドラインモードでの
補完機能を提供するプラグイン
hrsh7th/nvim-cmpメインの補完プラグインで、
入力補完のためのエンジン
onsails/lspkind.nvimvscodeのようなアイコンを追加
するプラグイン

Neovimのディレクトリ構成

ディレクトリ構成はこだわりや好みで自由に構成することができます。

このブログではLazy.nvim用に下のような構成にします。

ディレクトリ・ファイル説明
~/.config/nvim/init.luaLazy.nvimのブートストラップスクリプトを書きます。
~/.config/nvim/lua/plugins/このディレクトリ配下の個別ファイルにプラグインを記述。
~/.config/nvim/lua/plugins/plugins_lazy.luaインストールするプラグインをこのファイルに列挙。
~/.config/nvim/lua/core/このディレクトリ配下に、プラグイン以外の基本的な設定を記述。
~/.config/nvim/lua/user/このディレクトリ配下に、個別カスタマイズの設定を記述。
~/.config/nvim/
├── init.lua
└─lua/
       ├── plugins/
       │       ├── plugins_lazy.lua<= 前回
       │       ├── lsp_cfg.lua<= 今回
       │       └── nvim_cmp_cfg.lua<= 今回
       ├── core/
       │       ├── autocmds.lua
       │       ├── keymaps.lua<= 今回
       │       └── options.lua
       └── user/
               ── ui.lua
Lazy.nvimの導入や初期設定について

Lazy.nvimの導入や初期設定については下の記事を参考にしてください。

事前の設定

それでは早速、~/.config/nvim/lua/plugins/lsp_cfg.luaにLSPの設定をしていきます。

Pythonの設定について

言語サーバはpyrightを使い、フォーマッターとリンターにはruffを使います。

luaの設定について

言語サーバはlua_lsを使い、フォーマッターにはstyluaを使います。

リンターにはluacheckを使いたいですが、luachecknone-lsではサポートされていないようなので、seleneを使います。

https://github.com/nvimtools/none-ls.nvim/issues/58

今回インストールするLSP、フォーマッター、リンターの一覧

今回はnone-lsでサポートされているフォーマッターやリンターを設定します。下のBUILTINS.mdを参考にしてください。

https://github.com/nvimtools/none-ls.nvim/blob/main/doc/BUILTINS.md

言語サーバ言語フォーマッターリンター
pyrightpythonruffruff
bashlsshshfmtbashlsに含む
lua_lsluastyluaselene
yamllsyamlprettieryamllint
jsonlsjsonjsonlsに含むjsonlsに含む
taplotomltaploに含むtaploに含む
rust_analyzserrustrust_analyzerに含む
ts_lsjavascriptprettier
htmlhtmlhtmlに含むhtmlに含む
csslscssprettiercsslsに含む

実現したいこと

LSPやフォーマッター・リンターを1つ1つのセットアップを書かずに、効率的に管理したいため力業ですがテーブルに必要なLSP、フォーマッター、リンターをリストし、自動的にインストールおよび設定するようにしています。(もっと良い方法はきっとあると思いますがとりあえず)

LSPの設定 (lsp_serversテーブル)

下のように、lsp_serversテーブルに必要なLSPサーバーをリストし、mason-lspconfigで自動的にインストールおよび設定するようにしてみます。

~/.config/nvim/lua/plugins/lsp_cfg.lua


local lsp_servers = {
    "pyright",
    "ruff",
    "bashls",
    "lua_ls",
    "yamlls",
    "jsonls",
    "taplo",
    "rust_analyzer",
    "ts_ls",
    "html",
    "cssls",
}

フォーマッターとリンターの設定 (formattersテーブル, diagnosticsテーブル)

下のように、formattersテーブルとdiagnosticsテーブルに必要なツールをリストし、nonel-lsを利用してフォーマッターとリンターを設定するようにします。

~/.config/nvim/lua/plugins/lsp_cfg.lua


local formatters = {
    "djlint",
    "black",
    "isort",
    "stylua",
    "shfmt",
    "prettier",
}
local diagnostics = {
    "yamllint",
    "selene",
}

補完候補にアイコンを表示するプラグインの設定

onsails/lspkind.nvimは、LSPや後ほどインストールする補完プラグインと連携して、補完候補にアイコンを表示するためのプラグインです。

補完候補にアイコンを表示

補完候補にアイコンを表示
補完候補にアイコンを表示

設定は、以下のようにしています。

~/.config/nvim/lua/plugins/lsp_cfg.lua


    -- lsp icons like vscode
    {
        "onsails/lspkind.nvim",
        event = "InsertEnter",
    },
event = "InsertEnter"について

onsails/lspkind.nvimは、event = "InsertEnter"で、インサートモードに入った時に読み込まれる設定にしています。

masonのLSP関連の設定(mason, mason-lspconfig, lspconfig)

ここからLSP関連の本題です。masonmason-lspconfiglspconfigの設定は以下の通りです。

~/.config/nvim/lua/plugins/lsp_cfg.lua


    -- mason / mason-lspconfig / lspconfig
    {
        "williamboman/mason.nvim",
        dependencies = {
            "williamboman/mason-lspconfig.nvim",
            "neovim/nvim-lspconfig",
            "jay-babu/mason-null-ls.nvim",
            -- "jose-elias-alvarez/null-ls.nvim",
            "nvimtools/none-ls.nvim",
        },
        config = function()
            require("mason").setup()
            require("mason-lspconfig").setup({
                -- lsp_servers table Install
                ensure_installed = lsp_servers,
            })

            local lsp_config = require("lspconfig")
            -- lsp_servers table setup
            for _, lsp_server in ipairs(lsp_servers) do
                lsp_config[lsp_server].setup({
                    root_dir = function(fname)
                        return lsp_config.util.find_git_ancestor(fname) or vim.fn.getcwd()
                    end,
                })
            end
        end,
        cmd = "Mason",
    },

15行目のensure_installedに先程定義したlsp_serversテーブルを指定しています。これによりlsp_serversテーブルのLSPが自動でインストールされます。

20行目から26行目までのfor文でlsp_serversテーブルのLSPをセットアップしています。

cmd = "Mason"について

williamboman/mason.nvimは、cmd = "Mason":Masonコマンドを入力したときにプラグインが読み込まれる設定にしています。

mason-null-ls.nvimの設定

続いて、mason-null-lsの設定です。先程定義したformattersテーブルとdiagnosticsテーブルのツールを自動インストールします。

~/.config/nvim/lua/plugins/lsp_cfg.lua


    -- mason-null-ls
    {
        "jay-babu/mason-null-ls.nvim",
        dependencies = {
            "williamboman/mason.nvim",
            -- "jose-elias-alvarez/null-ls.nvim",
            "nvimtools/none-ls.nvim",
        },
        config = function()
            require("mason-null-ls").setup({
                automatic_setup = true,
                -- formatters table and diagnostics table Install
                ensure_installed = vim.tbl_flatten({ formatters, diagnostics }),
                handlers = {},
            })
        end,
        cmd = "Mason",
    },

上の13行目のensure_installedに、先程定義したformattersテーブルとdiagnosticsテーブルを指定しています。これによりformattersテーブルとdiagnosticsテーブルのツールが自動でインストールされます。

cmd = "Mason"について

遅延設定は、cmd = "Mason":Masonコマンドを入力したときにプラグインが読み込まれる設定にしています。

none-lsの設定

続いて、none-lsの設定です。定義したformattersテーブルとdiagnosticsテーブルのツールをセットアップします。

~/.config/nvim/lua/plugins/lsp_cfg.lua


    -- none-ls
    {
        -- "jose-elias-alvarez/null-ls.nvim",
        "nvimtools/none-ls.nvim",
        requires = "nvim-lua/plenary.nvim",
        config = function()
            local null_ls = require("null-ls")

            -- formatters table
            local formatting_sources = {}
            for _, tool in ipairs(formatters) do
                table.insert(formatting_sources, null_ls.builtins.formatting[tool])
            end

            -- diagnostics table
            local diagnostics_sources = {}
            for _, tool in ipairs(diagnostics) do
                table.insert(diagnostics_sources, null_ls.builtins.diagnostics[tool])
            end

            -- none-ls setup
            null_ls.setup({
                diagnostics_format = "[#{m}] #{s} (#{c})",
                sources = vim.tbl_flatten({ formatting_sources, diagnostics_sources }),
            })
        end,
        event = { "BufReadPre", "BufNewFile" },
    },

lspsagaの設定

LSPの情報を視覚的に見やすく表示してくれるnvimdev/lspsaga.nvimをインストールします。LSPホバーが見やすくなり、LSPのエラーメッセージをポップアップで見やすく表示してくれます。また、IDEのようなwinbarを表示することもできます。(他にも多くの機能があります)

以下のlspsagaの設定は、winbarのセパレーターのみ変更しています。

~/.config/nvim/lua/plugins/lsp_cfg.lua


    -- lspsaga
    {
        "nvimdev/lspsaga.nvim",
        config = function()
            require("lspsaga").setup({
                symbol_in_winbar = {
                    separator = "  ",
                },
            })
        end,
        dependencies = {
            "nvim-treesitter/nvim-treesitter",
            "nvim-tree/nvim-web-devicons",
        },
        event = { "BufRead", "BufNewFile" },
    },

mason-nvim-dapの設定

pythonのデバッグアダプター(DAP:Debug Adapter Protocol)であるdebugpyも自動でインストールしたいので、mason-nvim-dapを以下のように設定します。

~/.config/nvim/lua/plugins/lsp_cfg.lua


    -- mason-nvim-dap
    {
        "jay-babu/mason-nvim-dap.nvim",
        dependencies = {
            "williamboman/mason.nvim",
            "mfussenegger/nvim-dap",
        },
        opts = {
            ensure_installed = {
                "python",
            },
            handlers = {},
        },
    },

上の10行目のensure_installedに、"python"を指定すると、debugpyを自動でインストールすることができます。

利用可能なデバッグアダプターとensure_installedで指定するワードとデバッグアダプターの対応表は以下となります。

LSP関連の設定:全体

これまで紹介した各項目ですが、まとめるとこのようになります。

~/.config/nvim/lua/plugins/lsp_cfg.lua


local lsp_servers = {
    "pyright",
    "ruff",
    "bashls",
    "lua_ls",
    "yamlls",
    "jsonls",
    "taplo",
    "rust_analyzer",
    "ts_ls",
    "html",
    "cssls",
}

local formatters = {
    "djlint",
    "stylua",
    "shfmt",
    "prettier",
}
local diagnostics = {
    "yamllint",
    "selene",
}

return {
    -- lsp icons like vscode
    {
        "onsails/lspkind.nvim",
        -- nvim-cmp.lua
        event = "InsertEnter",
    },

    -- mason / mason-lspconfig / lspconfig
    {
        "williamboman/mason.nvim",
        dependencies = {
            "williamboman/mason-lspconfig.nvim",
            "neovim/nvim-lspconfig",
            "jay-babu/mason-null-ls.nvim",
            -- "jose-elias-alvarez/null-ls.nvim",
            "nvimtools/none-ls.nvim",
        },
        config = function()
            require("mason").setup()
            require("mason-lspconfig").setup({
                -- lsp_servers table Install
                ensure_installed = lsp_servers,
            })

            local lsp_config = require("lspconfig")
            -- lsp_servers table setup
            for _, lsp_server in ipairs(lsp_servers) do
                lsp_config[lsp_server].setup({
                    root_dir = function(fname)
                        return lsp_config.util.find_git_ancestor(fname) or vim.fn.getcwd()
                    end,
                })
            end
        end,
        cmd = "Mason",
    },

    -- mason-null-ls
    {
        "jay-babu/mason-null-ls.nvim",
        -- event = { "BufReadPre", "BufNewFile" },
        dependencies = {
            "williamboman/mason.nvim",
            -- "jose-elias-alvarez/null-ls.nvim",
            "nvimtools/none-ls.nvim",
        },
        config = function()
            require("mason-null-ls").setup({
                automatic_setup = true,
                -- formatters table and diagnostics table Install
                ensure_installed = vim.tbl_flatten({ formatters, diagnostics }),
                handlers = {},
            })
        end,
        cmd = "Mason",
    },

    -- none-ls
    {
        -- "jose-elias-alvarez/null-ls.nvim",
        "nvimtools/none-ls.nvim",
        requires = "nvim-lua/plenary.nvim",
        config = function()
            local null_ls = require("null-ls")

            -- formatters table
            local formatting_sources = {}
            for _, tool in ipairs(formatters) do
                table.insert(formatting_sources, null_ls.builtins.formatting[tool])
            end

            -- diagnostics table
            local diagnostics_sources = {}
            for _, tool in ipairs(diagnostics) do
                table.insert(diagnostics_sources, null_ls.builtins.diagnostics[tool])
            end

            -- none-ls setup
            null_ls.setup({
                diagnostics_format = "[#{m}] #{s} (#{c})",
                sources = vim.tbl_flatten({ formatting_sources, diagnostics_sources }),
            })
        end,
        event = { "BufReadPre", "BufNewFile" },
    },

    -- lspsaga
    {
        "nvimdev/lspsaga.nvim",
        config = function()
            require("lspsaga").setup({
                symbol_in_winbar = {
                    separator = "  ",
                },
            })
        end,
        dependencies = {
            "nvim-treesitter/nvim-treesitter",
            "nvim-tree/nvim-web-devicons",
        },
        event = { "BufRead", "BufNewFile" },
    },

    -- mason-nvim-dap
    {
        "jay-babu/mason-nvim-dap.nvim",
        dependencies = {
            "williamboman/mason.nvim",
            "mfussenegger/nvim-dap",
        },
        opts = {
            ensure_installed = {
                "python",
            },
            handlers = {},
        },
    },
}

補完系プラグインの設定

最後にとても便利な補完をしてくれるプラグインを設定します。

補完関連のプラグインの役割

プラグイン役割
hrsh7th/cmp-nvim-lspLSPから提供される補完候補をnvim-cmpで利用するプラグイン。
hrsh7th/cmp-nvim-luaNeovimのLua API向けに特化した補完プラグイン。
hrsh7th/cmp-buffer現在開いているバッファ内の内容を元に補完を行うプラグイン。
hrsh7th/cmp-pathファイルパスの補完を提供するプラグイン。
hrsh7th/cmp-cmdlineNeovimのコマンドラインでの補完をサポートするプラグイン。
saadparwaiz1/cmp_luasnipLuaSnipスニペットエンジンとnvim-cmpを統合するプラグイン。
L3MON4D3/LuaSnip強力なスニペットエンジンで、スニペットの管理と展開を行う。
補完関連のプラグインの役割

この記事では補完系のプラグインはnvim_cmp_cfg.luaに設定していきます。

~/.config/nvim/lua/plugins/nvim_cmp_cfg.lua


local M = {
    "hrsh7th/nvim-cmp",
    dependencies = {
        "hrsh7th/cmp-nvim-lsp",
        "hrsh7th/cmp-nvim-lua",
        "hrsh7th/cmp-buffer",
        "hrsh7th/cmp-path",
        "hrsh7th/cmp-cmdline",
        "saadparwaiz1/cmp_luasnip",
        "L3MON4D3/LuaSnip",
    },
    event = { "InsertEnter", "CmdlineEnter" },
}

M.config = function()
    local cmp = require("cmp")
    local lspkind = require("lspkind")
    vim.opt.completeopt = { "menu", "menuone", "noselect" }

    cmp.setup({
        formatting = {
            format = lspkind.cmp_format({
                mode = "symbol",
                maxwidth = 50,
                ellipsis_char = "...",
                before = function(entry, vim_item)
                    return vim_item
                end,
            }),
        },
        snippet = {
            expand = function(args)
                require("luasnip").lsp_expand(args.body)
            end,
        },
        window = {
            completion = cmp.config.window.bordered(),
            documentation = cmp.config.window.bordered(),
        },
        mapping = cmp.mapping.preset.insert({
            ["<C-b>"] = cmp.mapping.scroll_docs(-4),
            ["<C-f>"] = cmp.mapping.scroll_docs(4),
            ["<C-Space>"] = cmp.mapping.complete(),
            ["<C-e>"] = cmp.mapping.abort(),
            ["<CR>"] = cmp.mapping.confirm({ select = true }),
        }),
        sources = cmp.config.sources({
            { name = "nvim_lsp" },
            { name = "nvim_lua" },
            { name = "luasnip" }, -- For luasnip users.
            -- { name = "orgmode" },
        }, {
            { name = "buffer" },
            { name = "path" },
        }),
    })

    cmp.setup.cmdline(":", {
        mapping = cmp.mapping.preset.cmdline(),
        sources = cmp.config.sources({
            { name = "path" },
        }, {
            { name = "cmdline" },
        }),
    })
end

return M

動作確認

neovimを起動し、:MasonコマンドでMasonを起動します。この記事で設定した各LSPやツールがインストールされます。

LSP関連のキーマップ

LSP関連の便利なキーマップを設定していきます。この記事のキーマップ設定ファイルは~/.config/nvim/lua/core/keymaps.luaです。

45行目以降がLSP関連のキーマップです。

LSP関連のキーマップは、LspAttachというイベント発生時に設定されるようにしています。LspAttachというイベントはLSPサーバーが特定のバッファにアタッチされた際にトリガーされるイベントです。

~/.config/nvim/lua/core/keymaps.lua


local vim = vim

local opts = { noremap = true, silent = true }
local keymap = vim.keymap.set

-- オプションテーブルに desc や buffer を追加する簡略化関数
local function ex_opts(desc, buffer)
    local final_opts = vim.tbl_extend("force", opts, {})
    if desc then
        final_opts.desc = desc
    end
    if buffer then
        final_opts.buffer = buffer
    end
    return final_opts
end

-- <Leader>の設定
vim.g.mapleader = " "

-- 標準的な操作
keymap("n", "<leader>w", ":w<cr>", ex_opts("Save"))
keymap("n", "<leader>q", ":q<cr>", ex_opts("Quit"))
keymap("n", "<leader>Q", ":qall<cr>", ex_opts("Quit all"))

-- ウィンドウ操作
keymap("n", "<leader>|", ":vsplit<cr>", ex_opts("Vertical Split"))
keymap("n", "<leader>-", ":split<cr>", ex_opts("Horizontal Split"))

-- Plugin Manager Lazy.nvim
keymap("n", "<leader>Ls", ":Lazy sync<cr>", ex_opts("Lazy sync"))
keymap("n", "<leader>Lp", ":Lazy profile<cr>", ex_opts("Lazy profile"))

-- バッファ移動
keymap("n", "<C-n>", ":bnext<cr>", ex_opts("Next Buffer"))
keymap("n", "<C-p>", ":bprevious<cr>", ex_opts("Previous Buffer"))

-- NeoTree
keymap("n", "<leader>nn", ":Neotree toggle<cr>", ex_opts("Neotree Toggle"))
keymap("n", "<leader>no", ":Neotree reveal<cr>:Neotree ~/dotfiles/nvim/<cr>", ex_opts("Neotree reveal"))

-- 検索ハイライト解除
keymap("n", "<ESC>", ":noh<cr>", ex_opts("Reset Highlight Search"))

-- LSP関連のキーマッピングと設定
vim.api.nvim_create_autocmd("LspAttach", {
    group = vim.api.nvim_create_augroup("UserLspConfig", {}),
    callback = function(ev)
        -- バッファローカルでのLSP設定
        vim.bo[ev.buf].omnifunc = "v:lua.vim.lsp.omnifunc"

        -- バッファローカルなキーマッピング
        keymap("n", "gD", vim.lsp.buf.declaration, ex_opts("Go to declaration", ev.buf))
        keymap("n", "gd", vim.lsp.buf.definition, ex_opts("Go to definition", ev.buf))
        keymap("n", "K", vim.lsp.buf.hover, ex_opts("Hover", ev.buf))
        keymap("n", "gi", vim.lsp.buf.implementation, ex_opts("Go to implementation", ev.buf))
        keymap("n", "<C-k>", vim.lsp.buf.signature_help, ex_opts("Signature help", ev.buf))
        keymap("n", "<leader>wa", vim.lsp.buf.add_workspace_folder, ex_opts("Add workspace folder", ev.buf))
        keymap("n", "<leader>wr", vim.lsp.buf.remove_workspace_folder, ex_opts("Remove workspace folder", ev.buf))
        keymap("n", "<leader>wl", function()
            print(vim.inspect(vim.lsp.buf.list_workspace_folders()))
        end, ex_opts("List workspace folders", ev.buf))
        keymap("n", "<leader>D", vim.lsp.buf.type_definition, ex_opts("Go to type definition", ev.buf))
        keymap("n", "<leader>rn", vim.lsp.buf.rename, ex_opts("Rename", ev.buf))
        keymap({ "n", "v" }, "<space>ca", vim.lsp.buf.code_action, ex_opts("Code action", ev.buf))
        keymap("n", "gr", vim.lsp.buf.references, ex_opts("References", ev.buf))
        keymap("n", "<leader><space>", function()
            vim.lsp.buf.format({ async = true })
        end, ex_opts("Format", ev.buf))

        -- Diagnostic mappings
        keymap("n", "<leader>e", vim.diagnostic.open_float, ex_opts("Open diagnostic float", ev.buf))
        keymap("n", "[d", vim.diagnostic.goto_prev, ex_opts("Go to previous diagnostic", ev.buf))
        keymap("n", "]d", vim.diagnostic.goto_next, ex_opts("Go to next diagnostic", ev.buf))
        keymap("n", "<leader>q", vim.diagnostic.setloclist, ex_opts("Set diagnostic loclist", ev.buf))

        -- Lspsaga キーマッピング
        keymap("n", "<leader>lf", "<cmd>Lspsaga finder<cr>", ex_opts("Lspsaga Finder show references", ev.buf))
        keymap("n", "<leader>lh", "<cmd>Lspsaga hover_doc<cr>", ex_opts("Lspsaga Hover Doc", ev.buf))
        keymap("n", "<leader>lo", "<cmd>Lspsaga outline<cr>", ex_opts("Lspsaga Outline", ev.buf))
        keymap("n", "<leader>lr", "<cmd>Lspsaga rename<cr>", ex_opts("Lspsaga Rename", ev.buf))
        keymap("n", "<leader>la", "<cmd>Lspsaga code_action<cr>", ex_opts("Lspsaga Code Action", ev.buf))
    end,
})
設定したLSP関連キーマップ内容
gDカーソル下のシンボルの宣言位置にジャンプ
gdカーソル下のシンボルの定義位置にジャンプ
Kカーソル下のシンボルに関するドキュメント情報をポップアップ表示
giカーソル下のシンボルの実装箇所にジャンプ
<C-k>関数やメソッドのシグネチャヘルプを表示
<leader>wa現在のディレクトリをLSPのワークスペースフォルダに追加
<leader>wr現在のディレクトリをLSPのワークスペースフォルダから削除
<leader>wl現在のLSPワークスペースフォルダのリストを表示
<leader>Dカーソル下のシンボルの型定義にジャンプ
<leader>rnカーソル下のシンボルをリネーム
<leader>caコードアクションをトリガー
grカーソル下のシンボルの参照箇所を検索してリスト表示
<leader><space>コードフォーマットを実行
<leader>eカーソル位置にある診断メッセージをポップアップ表示
[d前の診断メッセージ(エラーや警告)にジャンプ
]d次の診断メッセージ(エラーや警告)にジャンプ
<leader>qすべての診断メッセージをリストに表示
<leader>lfLspsagaのFinder機能を使ってシンボルの参照や定義を表示
<leader>lhLspsagaのホバードキュメント機能を使って、カーソル下のシンボルに関する詳細なドキュメント情報をポップアップ表示
<leader>loLspsagaのアウトライン機能を表示
<leader>lrLspsagaのリネーム機能を使って、カーソル下のシンボルの名前をリネーム
<leader>laLspsaga のコードアクション機能を起動
設定したLSP関連のキーマップ

neovim.ymlselene.tomlの設定

~/.config/nvim/neovim.ymlselene.tomlを設定しておきます。selene.tomlの設定例は緩い設定のため、適宜調整してください。

~/.config/nvim/neovim.yml


---
base: lua51

globals:
  vim:
    any: true

~/.config/nvim/selene.toml


std = "neovim"

[rules]
global_usage = "allow"
if_same_then_else = "allow"
incorrect_standard_library_use = "allow"
mixed_table = "allow"
multiple_statements = "allow"
undefined_variable = "allow"
unused_variable = "allow"

ファイル保存時に自動でフォーマットする

ファイル保存時に自動でフォーマットするように設定します。

~/.config/nvim/lua/core/autocmds.lua


-- ファイル保存時に自動フォーマット
vim.cmd([[autocmd BufWritePre * lua vim.lsp.buf.format()]])

最後に

最後まで読んでいただきありがとうございます。今回のLazy.nvimでPythonとLuaのLSP環境を構築する方法はいかがでしたでしょうか。

NeovimやVimは自分好みにとことんカスタマイズできる使いやすいテキストエディターです。最初は独特の操作を覚える必要がありますが、一度覚えると無くてはならない存在になり、魅力的なエディターになることは間違いないのでぜひ活用してみてください。

究極のコーディング体験:NeovimとHHKBで高める生産性

neovim関連記事

Neovimをかっこ良くクールに使う設定

カテゴリー:
関連記事