こんにちは。ナミレリです。この記事では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の起動画面

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

この記事はこんな人にオススメ
- NeovimでLSP環境を構築したいが難しそう
- Pythonでプログラミングすることが好きな方
- Neovimの設定をLuaでカスタマイズすることが好きな方
- Neovimを使い始めたばかりの方
- Neovimを使い始めたが、より深く活用したいと考えている方
- M3 MacBook Air 15インチ
- macOS Sonoma 14.6.1
- NVIM v0.10.1
- Parallels Desktop 20 for Mac バージョン 20.0.1
 もありますので、ぜひダウンロードして試してみてください。M1/M2/M3のMac上で快適にMacやUbuntu、Windowsが動作します。
もありますので、ぜひダウンロードして試してみてください。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関連のプラグインの役割
| プラグイン | 役割 | 
|---|---|
| mason.nvim | LSPやフォーマッター、リンターなどのツールを インストール・管理するプラグイン。 | 
| mason-lspconfig.nvim | mason.nvimでインストールされたLSPを nvim-lspconfigと自動的に連携させるプラグイン。 | 
| nvim-lspconfig | LSPをNeovimで使用するための設定を 簡素化するプラグイン。 | 
| mason-null-ls.nvim | mason.nvimでインストールされた フォーマッターやリンター等を none-ls.nvimで使用できるように連携するプラグイン。 | 
| none-ls.nvim | LSP以外のフォーマッターやリンターを LSPクライアントとして使用するためのプラグイン。 | 
mason.nvim
LSPやフォーマッター、リンターなどのツールをインストール・管理するプラグイン。

- 役割: masonは、LSP、Lintツール、フォーマッターなどの開発ツールを簡単にインストールし、管理するためのNeovimプラグインです。コマンド一つで必要なツールをインストールし、NeovimのLSPエコシステムと連携させます。公式リポジトリからLSPを自動的にインストールし、バージョン管理や依存関係の解決も行ってくれます。
- 関係性: masonはlspconfigと連携して、ユーザーが必要とする言語サーバーやツールのインストールを担当します。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は、masonとnull-lsを連携させるプラグインです。masonでインストール可能なLintツールやフォーマッターを自動的にnone-ls(null-ls)に統合し、設定を簡単にします。
- 関係性: このプラグインはmasonとnone-ls(null-ls)の橋渡しをする役割です。
none-ls.nvim
LSP以外のフォーマッターやリンターをLSPクライアントとして使用するためのプラグイン。

- 役割: null-lsは、LSPプロトコルをサポートしていないツール(フォーマッター、リンターなど)をLSPクライアントとして使えるようにするプラグインです。
null-lsは2023年8月11日以降、アーカイブされ更新されないとのことです。
https://github.com/jose-elias-alvarez/null-ls.nvim/issues/1621
none-lsは、プラグインマネージャでjose-elias-alvarez/null-ls.nvimをnvimtools/none-ls.nvimに置き換えるだけで、null-lsの設定はそのままで使うことができます。
null-ls.nvimとnone-lsについて、以下のサイトを参考にさせていただきました。
より詳しくは
以下の2つのサイトにはより詳しいLSP系の各プラグインの説明がされていて参考にさせていただきました。
作ってわかる[入門]Streamlit Pythonによる実践Webサービス開発
補完系プラグインとアイコン
以下は、補完系の便利で素晴らしいプラグインです。LSPの補完候補を表示するhrsh7th/cmp-nvim-lspをはじめ、この記事では下記のプラグインもインストールしていきます。
| 補完系プラグイン | 説明 | 
|---|---|
| hrsh7th/cmp-nvim-lsp | LSPから提供される補完候補を nvim-cmpで利用するプラグイン | 
| hrsh7th/cmp-buffer | 現在のバッファにある単語を 補完するプラグイン | 
| hrsh7th/cmp-path | ファイルシステムの パス補完するプラグイン | 
| hrsh7th/cmp-cmdline | コマンドラインモードでの 補完機能を提供するプラグイン | 
| hrsh7th/nvim-cmp | メインの補完プラグインで、 入力補完のためのエンジン | 
| onsails/lspkind.nvim | vscodeのようなアイコンを追加 するプラグイン | 
Neovimのディレクトリ構成
ディレクトリ構成はこだわりや好みで自由に構成することができます。
| ディレクトリ・ファイル | 説明 | 
|---|---|
| ~/.config/nvim/init.lua | Lazy.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.luaLazy.nvimの導入や初期設定については下の記事を参考にしてください。
事前の設定
それでは早速、~/.config/nvim/lua/plugins/lsp_cfg.luaにLSPの設定をしていきます。
言語サーバはpyrightを使い、フォーマッターとリンターにはruffを使います。
言語サーバはlua_lsを使い、フォーマッターにはstyluaを使います。
リンターにはluacheckを使いたいですが、luacheckはnone-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
| 言語サーバ | 言語 | フォーマッター | リンター | 
|---|---|---|---|
| pyright | python | ruff | ruff | 
| bashls | sh | shfmt | bashlsに含む | 
| lua_ls | lua | stylua | selene | 
| yamlls | yaml | prettier | yamllint | 
| jsonls | json | jsonlsに含む | jsonlsに含む | 
| taplo | toml | taploに含む | taploに含む | 
| rust_analyzser | rust | rust_analyzerに含む | |
| ts_ls | javascript | prettier | |
| html | html | htmlに含む | htmlに含む | 
| cssls | css | prettier | csslsに含む | 
実現したいこと
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",
    },
masonのLSP関連の設定(mason, mason-lspconfig, lspconfig)
ここからLSP関連の本題です。mason、mason-lspconfig、lspconfigの設定は以下の通りです。
~/.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をセットアップしています。
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テーブルのツールが自動でインストールされます。
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 = {},
        },
        event = { "BufRead", "BufNewFile" },
    },
上の10行目のensure_installedに、"python"を指定すると、debugpyを自動でインストールすることができます。
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 = {},
        },
        event = { "BufRead", "BufNewFile" },
    },
}
補完系プラグインの設定(nvim-cmp)
最後にとても便利な補完をしてくれるプラグインを設定します。
補完関連のプラグインの役割
| プラグイン | 役割 | 
|---|---|
| hrsh7th/cmp-nvim-lsp | LSPから提供される補完候補を nvim-cmpで利用するプラグイン。 | 
| hrsh7th/cmp-nvim-lua | NeovimのLua API向けに特化した補完プラグイン。 | 
| hrsh7th/cmp-buffer | 現在開いているバッファ内の内容を元に補完を行うプラグイン。 | 
| hrsh7th/cmp-path | ファイルパスの補完を提供するプラグイン。 | 
| hrsh7th/cmp-cmdline | Neovimのコマンドラインでの補完をサポートするプラグイン。 | 
| saadparwaiz1/cmp_luasnip | LuaSnipスニペットエンジンと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 = { "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 = false }),
        }),
        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 = {
            { name = "buffer" },
        },
    })
    cmp.setup.cmdline(":", {
        mapping = cmp.mapping.preset.cmdline({
            ["<Tab>"] = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Insert }),
        }),
        sources = cmp.config.sources({
            { name = "path" },
        }, {
            { name = "cmdline" },
        }),
    })
end
return M
動作確認
neovimを起動し、:MasonコマンドでMasonを起動します。この記事で設定した各LSPやツールがインストールされます。

下の画像は、この段階でのロード時間(30個のプラグイン中、17個のロード)

下の画像は、この段階での起動時間(30.69ms)

LSP関連のキーマップ
LSP関連の便利なキーマップを設定していきます。この記事のキーマップ設定ファイルは~/.config/nvim/lua/core/keymaps.luaです。
45行目以降がLSP関連のキーマップです。
~/.config/nvim/lua/core/keymaps.lua
local vim = vim
-- <leader>の設定
vim.g.mapleader = " "
-- 標準的な操作
vim.keymap.set("n", "<leader>w", ":w<cr>", { noremap = true, silent = true, desc = "Save" })
vim.keymap.set("n", "<leader>q", ":q<cr>", { noremap = true, silent = true, desc = "Quit" })
vim.keymap.set("n", "<leader>Q", ":qall<cr>", { noremap = true, silent = true, desc = "Quit all" })
-- ウィンドウ操作
vim.keymap.set("n", "<leader>|", ":vsplit<cr>", { noremap = true, silent = true, desc = "Vertical Split" })
vim.keymap.set("n", "<leader>-", ":split<cr>", { noremap = true, silent = true, desc = "Horizontal Split" })
-- Plugin Manager Lazy.nvim
vim.keymap.set("n", "<leader>Ls", ":Lazy sync<cr>", { noremap = true, silent = true, desc = "Lazy sync" })
vim.keymap.set("n", "<leader>Lp", ":Lazy profile<cr>", { noremap = true, silent = true, desc = "Lazy profile" })
-- バッファ移動
vim.keymap.set("n", "<C-n>", ":bnext<cr>", { noremap = true, silent = true, desc = "Next Buffer" })
vim.keymap.set("n", "<C-p>", ":bprevious<cr>", { noremap = true, silent = true, desc = "Previous Buffer" })
-- NeoTree
vim.keymap.set("n", "<leader>nn", ":Neotree toggle<cr>", { noremap = true, silent = true, desc = "Neotree Toggle" })
vim.keymap.set(
    "n",
    "<leader>no",
    ":Neotree reveal<cr>:Neotree ~/dotfiles/nvim/<cr>",
    { noremap = true, silent = true, desc = "Neotree reveal" }
)
-- 検索ハイライト解除
vim.keymap.set("n", "<ESC>", ":noh<cr>", { noremap = true, silent = true, desc = "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"
        -- バッファローカルなキーマッピング
        vim.keymap.set(
            "n",
            "<leader>gD",
            vim.lsp.buf.declaration,
            { noremap = true, silent = true, desc = "Go to declaration", buffer = ev.buf }
        )
        vim.keymap.set(
            "n",
            "<leader>gd",
            vim.lsp.buf.definition,
            { noremap = true, silent = true, desc = "Go to definition", buffer = ev.buf }
        )
        vim.keymap.set(
            "n",
            "<leader>K",
            vim.lsp.buf.hover,
            { noremap = true, silent = true, desc = "Hover", buffer = ev.buf }
        )
        vim.keymap.set(
            "n",
            "<leader>gi",
            vim.lsp.buf.implementation,
            { noremap = true, silent = true, desc = "Go to implementation", buffer = ev.buf }
        )
        vim.keymap.set(
            "n",
            "<leader><C-k>",
            vim.lsp.buf.signature_help,
            { noremap = true, silent = true, desc = "Signature help", buffer = ev.buf }
        )
        vim.keymap.set(
            "n",
            "<leader>wa",
            vim.lsp.buf.add_workspace_folder,
            { noremap = true, silent = true, desc = "Add workspace folder", buffer = ev.buf }
        )
        vim.keymap.set(
            "n",
            "<leader>wr",
            vim.lsp.buf.remove_workspace_folder,
            { noremap = true, silent = true, desc = "Remove workspace folder", buffer = ev.buf }
        )
        vim.keymap.set("n", "<leader>wl", function()
            print(vim.inspect(vim.lsp.buf.list_workspace_folders()))
        end, { noremap = true, silent = true, desc = "List workspace folders", buffer = ev.buf })
        vim.keymap.set(
            "n",
            "<leader>D",
            vim.lsp.buf.type_definition,
            { noremap = true, silent = true, desc = "Go to type definition", buffer = ev.buf }
        )
        vim.keymap.set(
            "n",
            "<leader>rn",
            vim.lsp.buf.rename,
            { noremap = true, silent = true, desc = "Rename", buffer = ev.buf }
        )
        vim.keymap.set(
            { "n", "v" },
            "<space>ca",
            vim.lsp.buf.code_action,
            { noremap = true, silent = true, desc = "Code action", buffer = ev.buf }
        )
        vim.keymap.set(
            "n",
            "<leader>gr",
            vim.lsp.buf.references,
            { noremap = true, silent = true, desc = "References", buffer = ev.buf }
        )
        vim.keymap.set("n", "<leader><space>", function()
            vim.lsp.buf.format({ async = true })
        end, { noremap = true, silent = true, desc = "Format", buffer = ev.buf })
        -- Diagnostic mappings
        vim.keymap.set(
            "n",
            "<leader>e",
            vim.diagnostic.open_float,
            { noremap = true, silent = true, desc = "Open diagnostic float", buffer = ev.buf }
        )
        vim.keymap.set(
            "n",
            "[d",
            vim.diagnostic.goto_prev,
            { noremap = true, silent = true, desc = "Go to previous diagnostic", buffer = ev.buf }
        )
        vim.keymap.set(
            "n",
            "]d",
            vim.diagnostic.goto_next,
            { noremap = true, silent = true, desc = "Go to next diagnostic", buffer = ev.buf }
        )
        vim.keymap.set(
            "n",
            "<leader>q",
            vim.diagnostic.setloclist,
            { noremap = true, silent = true, desc = "Set diagnostic loclist", buffer = ev.buf }
        )
        -- Lspsaga キーマッピング
        vim.keymap.set(
            "n",
            "<leader>lf",
            "<cmd>Lspsaga finder<cr>",
            { noremap = true, silent = true, desc = "Lspsaga Finder show references", buffer = ev.buf }
        )
        vim.keymap.set(
            "n",
            "<leader>lh",
            "<cmd>Lspsaga hover_doc<cr>",
            { noremap = true, silent = true, desc = "Lspsaga Hover Doc", buffer = ev.buf }
        )
        vim.keymap.set(
            "n",
            "<leader>lo",
            "<cmd>Lspsaga outline<cr>",
            { noremap = true, silent = true, desc = "Lspsaga Outline", buffer = ev.buf }
        )
        vim.keymap.set(
            "n",
            "<leader>lr",
            "<cmd>Lspsaga rename<cr>",
            { noremap = true, silent = true, desc = "Lspsaga Rename", buffer = ev.buf }
        )
        vim.keymap.set(
            "n",
            "<leader>la",
            "<cmd>Lspsaga code_action<cr>",
            { noremap = true, silent = true, desc = "Lspsaga Code Action", buffer = 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>lf | LspsagaのFinder機能を使ってシンボルの参照や定義を表示 | 
| <leader>lh | Lspsagaのホバードキュメント機能を使って、カーソル下のシンボルに関する詳細なドキュメント情報をポップアップ表示 | 
| <leader>lo | Lspsagaのアウトライン機能を表示 | 
| <leader>lr | Lspsagaのリネーム機能を使って、カーソル下のシンボルの名前をリネーム | 
| <leader>la | Lspsaga のコードアクション機能を起動 | 
neovim.ymlとselene.tomlの設定
~/.config/nvim/にneovim.ymlとselene.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をかっこ良くクールに使う設定

 
	



























