2025年2月 Neovimセットアップ

Table of Contents

Introduction

Neovimに入門したいと思い早n年だったが、vim-jpの皆さんのおかげでようやくミニマムの設定が完了したのでブログにまとめておきます。

VimとNeovimの使い分けと最小構成 の通りVimは最小構成にしているので、Neovimはヘビーカスタマイズしていく方針です。

Neovimの設定はこちら。

https://github.com/takeokunn/nixos-configuration/tree/main/home-manager/programs/neovim

Setup

Neovim本体

Nix経由でインストールしています。

https://github.com/takeokunn/nixos-configuration/blob/main/home-manager/programs/neovim/default.nix

withNodeJswithRuby などはイマドキ使わない設定まらしいので false にしました。

{ pkgs, sources }:
{
  programs.neovim = {
    enable = true;
    withNodeJs = false;
    withRuby = false;
    withPython3 = false;
    plugins = import ./plugins { inherit pkgs sources; };
    extraLuaConfig = builtins.readFile ./init.lua;
  };
}

Plugin Manager

VimのPlugin Managerは乱立しているようで、デファクトスタンダードはないらしいです。 私はNixユーザーなのでNixで管理することにしました。

また、各Pluginごとの設定もNix内に記述する方針にしました。

# 実際の例
{ pkgs }:
with pkgs.vimPlugins;
[
  {
    type = "lua";
    plugin = dracula-nvim;
    config = ''
      vim.cmd[[colorscheme dracula]]
    '';
  }
]

Terminal Emulator

「Terminal Emulatorにこだわらない」というこだわりを持っていたが、Mac標準のTerminal.appだとうまく描画してくれない問題があった。

一応以下が候補だったが、NixOS環境でも安定的に動いてくれる、かつ友人のnatsukiumが使っているKittyを採用しました。

現状Kittyで特に困っていないしTerminal Emulatorに情熱がないのでこのまま続投するつもりです。

Config

Neovimの設定はVim scriptではなくLuaを使うのがイマドキであり、多くのNeovim PluginはLuaで書かれているらしい。 それにならって自分もLuaで設定していくことにしました。

init.lua

基本的な設定は以下。 行番号はそもそも表示不要というのが最近の結論なので消しました。

vim.opt.number = false
vim.opt.relativenumber = false
vim.opt.encoding = "utf-8"
vim.opt.fileencodings = "utf-8,euc-jp,cp932"
vim.opt.clipboard:append("unnamed")
vim.opt.backspace = "indent,eol,start"
vim.opt.tabstop = 2
vim.opt.shiftwidth = 2
vim.opt.laststatus = 3
vim.opt.statusline = "%y"
vim.opt.showmatch = true
vim.opt.wrapscan = true
vim.opt.hlsearch = true
vim.opt.showcmd = true
vim.opt.title = true
vim.opt.foldenable = false
vim.opt.swapfile = false
vim.opt.expandtab = true
vim.opt.splitbelow = true
vim.opt.splitright = true
vim.opt.incsearch = true
vim.opt.ignorecase = true
vim.opt.smartcase = true
vim.opt.termguicolors = true

簡単なkeymapは以下。 mapleader をスペースに割り当てている人が多数派みたいですが、個人的には , が昔から好きです。

vim.g.mapleader = ","

vim.keymap.set("n", "/", "/\\v", { remap = false })
vim.keymap.set("n", "U", "<C-r>", { remap = false })
vim.keymap.set("n", "<Leader><Leader>", "V", { remap = false })
vim.keymap.set("n", "<Esc><Esc>", "<Cmd>nohlsearch<CR><Esc>", { remap = false })
vim.keymap.set("i", "<C-j>", "<CR>")

windowやbufferの切り替えは簡単な設定をしています。

-- window keymap

vim.keymap.set("n", "sj", "<C-w>j", { noremap = true, silent = true })
vim.keymap.set("n", "sk", "<C-w>k", { noremap = true, silent = true })
vim.keymap.set("n", "sl", "<C-w>l", { noremap = true, silent = true })
vim.keymap.set("n", "sh", "<C-w>h", { noremap = true, silent = true })
vim.keymap.set("n", "sJ", "<C-w>J", { noremap = true, silent = true })
vim.keymap.set("n", "sK", "<C-w>K", { noremap = true, silent = true })
vim.keymap.set("n", "sL", "<C-w>L", { noremap = true, silent = true })
vim.keymap.set("n", "sH", "<C-w>H", { noremap = true, silent = true })
vim.keymap.set("n", "sw", "<C-w>w", { noremap = true, silent = true })

-- buffer keymap

vim.keymap.set("n", "sp", ":<C-u>bp<CR>", { noremap = true, silent = true })
vim.keymap.set("n", "sn", ":<C-u>bn<CR>", { noremap = true, silent = true })

package

項目分けは雑なのでもう少しpluginが増えたら考え直します。

basic

ざっくりこのあたりを入れています。

Git

そこまで使っていないです。 Git操作はTerminalでも良いのかなという気持ちになってます。

language

基本的にTree-sitterがhighlightしてくれるので特別入れる必要がなかったです。

lsp

ざっくりとした設定は以下。最低限満足するUIになってくれました。

nvim-cmp:

local cmp = require("cmp")

cmp.setup({
      snippet = {
         expand = function(args)
            vim.fn["vsnip#anonymous"](args.body)
         end,
      },
      sources = {
         { name = "nvim_lsp" },
         { name = "path" },
      },
      mapping = cmp.mapping.preset.insert({
            ["<C-p>"] = cmp.mapping.select_prev_item(),
            ["<C-n>"] = cmp.mapping.select_next_item(),
            ['<C-l>'] = cmp.mapping.complete(),
            ['<C-e>'] = cmp.mapping.abort(),
            ["<CR>"] = cmp.mapping.confirm { select = true },
      }),
      experimental = {
         ghost_text = true,
      },
})

nvim-lspconfig:

local lspconfig = require('lspconfig')

vim.keymap.set('n', 'gd', '<cmd>lua vim.lsp.buf.definition()<CR>', { silent = true, buffer = buffer })

if vim.fn.executable('nil') == 1 then
   lspconfig.nil_ls.setup {
      settings = {
         ['nil'] = {
            formatting = {
               command = { 'nixfmt' }
            }
         }
      }
   }
end

if vim.fn.executable('typescript-language-server') == 1 then
   lspconfig.ts_ls.setup { }
end

if vim.fn.executable('intelephense') == 1 then
   lspconfig.intelephense.setup { }
end

lspsaga-nvim:

require('lspsaga').setup({
    code_action = {
        extend_gitsigns = true,
    },
    finder = {
        max_height = 0.7,
        left_width = 0.3,
        right_width = 0.6,
        keys = {
            shuttle = "<Space>w",
            toggle_or_open = "<CR>"
        }
    },
    lightbulb = {
        enable = false,
    }
})

vim.keymap.set('n', 'K', '<cmd>Lspsaga hover_doc<CR>')
vim.keymap.set({ 'n', 'i' }, '<S-M-r>', "<cmd>Lspsaga rename<CR>", opts)
vim.keymap.set('n', '<M-d>', "<cmd>Lspsaga finder def+ref<CR>", opts)
vim.keymap.set('n', '<M-r>', "<cmd>Lspsaga peek_definition<CR>", opts)
vim.keymap.set('n', '<M-j>', "<cmd>Lspsaga diagnostic_jump_next<CR>", opts)
vim.keymap.set('n', '<M-k>', "<cmd>Lspsaga diagnostic_jump_prev<CR>", opts)

skk

簡易的な設定とskkservへの接続、AZIKの有効化をしました。

skkeleton#register_kanatable で独自のかなテーブルを定義できるらしいです。

skkeleton:

vim.fn['skkeleton#config']({
    eggLikeNewline = true,
    keepState = true,
    sources = { "skk_server" }
})

vim.keymap.set({ 'i', 'c' }, '<C-j>', '<Plug>(skkeleton-toggle)', { silent = true })

skkeleton-azik-kanatable:

vim.fn['skkeleton#azik#add_table']('us')
vim.fn['skkeleton#config']({
    kanaTable = 'azik'
})

vim.call("skkeleton#register_kanatable", "azik", {
    ss = { "せい" },
})

telescope

telescopeは簡単に導入できるということで導入しました。

Emacsで言う所の、というのは説明が難しいですね。 tomoyaさんの Emacsの次世代ミニバッファ補完UI あたりが参考になりそうです。

<leader> はデフォルトでマッピングされてないのでこれで問題ないようです。

require('telescope').setup {
    extensions = {
        fzf = {
            fuzzy = true,
            override_generic_sorter = true,
            override_file_sorter = true,
            case_mode = "smart_case",
        }
    }
}
local builtin = require('telescope.builtin')
vim.keymap.set('n', '<leader>f', builtin.git_files, { desc = 'Telescope find git files' })
vim.keymap.set('n', '<leader>o', builtin.current_buffer_fuzzy_find, { desc = 'Telescope buffer fuzzy find' })
vim.keymap.set('n', '<leader>g', builtin.live_grep, { desc = 'Telescope live grep' })
vim.keymap.set('n', '<leader>b', builtin.buffers, { desc = 'Telescope buffers' })
vim.keymap.set('n', '<leader>h', builtin.help_tags, { desc = 'Telescope help tags' })

themes

すべてのカラーテーマをdraculaに寄せているので導入しました。 また、modelineはlualine-nvimがイマドキらしいです。

終わりに

vim-jpの皆さん(特にkuuさん、Kento Ogataさん、Shougoさん、こまもかくん、おもちあいす)のおかげで無事日常生活できるくらいの設定になりました。 もう少しVimに慣れたらDark Poweredなpackageを試していくつもりです。