やっとNeovimの設定ファイルをinit.luaに移行した
はじめに
hisasann/neovim: hisasann's neovim settings
Vim 時代は .vimrc
一本、 Neovim に変えてからは Init.vim
と dein.toml
で設定やプラグインを管理していました。
neovim/vim at master · hisasann/neovim
toml ファイルにプラグインの細かい設定を書く場合は、以下のように改行コード込みの文字列として記述します。
[[plugins]]
hook_add = """
lua << EOF
-- ここに lua のコードを書くことができる
EOF
"""
ぼくはこの場合に -- のようなコメントの行があると、うまくプラグインが動かないなどの挙動がありました。
なので、基本コメントは書かないようにしていました。
このように一工夫する必要があったり、うまく動かない機能などもありました。
たとえば、ファイルの保存時に何かするみたいなのが動きませんでした。
lspconfig の以下のようなコードです。
-- formatting
if client.server_capabilities.documentFormattingProvider then
vim.api.nvim_create_autocmd("BufWritePre", {
group = vim.api.nvim_create_augroup("Format", { clear = true }),
buffer = bufnr,
callback = function() vim.lsp.buf.formatting_seq_sync() end
})
end
というのもあり、このあたりがモチベーションになりました。
何をしたかを忘れたいので、メモ程度ですが、残しておきます。
また、一応 Neovim をインストールするところからメモしておきますので、今から Neovim を lua で使ってみたい系の方でも読めるかと思います。
どんな設定なのか
lua 移植時に、いったんは必須ではないプラグインなどは入れないようにしました。
なので、以下に列挙したぐらいのことしかできません。
ただ、これはぼくにとって最高の状態なので、同じような設定を実現したい方には参考になるかもしれません。
- ファイル操作を迅速にしたい
- TypeScript を書きたい
- cmp でいい感じのインテリセンスを実現したい
- prettier で保存時にフォーマットしたい
- tree-sitter でシンタックスハイライトはより良い感じにしたい
- powerline 的なものは lua 製のものにしたい
Neovimをインストールする
brew で入れるのが主流でしょう。
$ brew install neovim
$ which nvim
/opt/homebrew/bin/nvim
$ nvim -v
NVIM v0.8.0-dev+547-ge837f29ce
lua が動くことを一応確認しておきます。
$ nvim
:lua print('hello lua')
init.luaを作成する
すでに init.vim
がある場合は、
$ mv init.vim _init.vim
のようにリネームして、 Neovim が勝手に読み込まないようにしておきましょう。
$ cd .config
$ mkdir nvim && cd nvim
$ touch init.lua
$ nvim init.lua
以下を記述します。
print('init.lua')
ここまできて、コマンド表示の部分に init.lua
が出れば読み込めています。
今回のぼくの作った init.lua
の中身の最終形態は以下のようになります。
require("base")
require("autocmds")
require("options")
require("keymaps")
require("colorscheme")
require("plugins")
そこまで細かくはファイル分割はしませんでした。
必要最低限という程度です。
luaディレクトリを作成する
$ mkdir lua && cd lua
この lua というディレクトリは特殊で、 require('ファイルのパス')
のように指定することで、 lua ディレクトリのファイルを読み込むことができます。
base設定をする
$ touch base.lua
vim.cmd("autocmd!")
vim.scriptencoding = "utf-8"
vim.wo.number = true
-- Open hoge file
vim.api.nvim_create_user_command("Hoge", function(opts)
vim.cmd("e " .. "~/_/hoge/hoge.markdown")
end, {})
ぼくは :Hoge
というコマンドをメモ帳起動用に割り当てています。
もっといい名前にしたかったのですが、もう手に馴染んでしまっているので、いいんです。
autocmds設定をする
$ touch autocmds.lua
local augroup = vim.api.nvim_create_augroup -- Create/get autocommand group
local autocmd = vim.api.nvim_create_autocmd -- Create autocommand
-- Remove whitespace on save
autocmd("BufWritePre", {
pattern = "*",
command = ":%s/\\s\\+$//e",
})
-- Don't auto commenting new lines
autocmd("BufEnter", {
pattern = "*",
command = "set fo-=c fo-=r fo-=o",
})
-- Restore cursor location when file is opened
autocmd({ "BufReadPost" }, {
pattern = { "*" },
callback = function()
vim.api.nvim_exec('silent! normal! g`"zv', false)
end,
})
option設定をする
$ touch options.lua
local options = {
encoding = "utf-8",
fileencoding = "utf-8",
title = true,
backup = false,
clipboard = "unnamedplus",
cmdheight = 2,
completeopt = { "menuone", "noselect" },
conceallevel = 0,
hlsearch = true,
ignorecase = true,
mouse = "a",
pumheight = 10,
showmode = false,
showtabline = 2,
smartcase = true,
smartindent = true,
swapfile = false,
termguicolors = true,
timeoutlen = 300,
undofile = true,
updatetime = 300,
writebackup = false,
shell = "fish",
backupskip = { "/tmp/*", "/private/tmp/*" },
expandtab = true,
shiftwidth = 2,
tabstop = 2,
cursorline = true,
number = true,
relativenumber = false,
numberwidth = 4,
signcolumn = "yes",
wrap = false,
winblend = 0,
wildoptions = "pum",
pumblend = 5,
background = "dark",
scrolloff = 8,
sidescrolloff = 8,
guifont = "monospace:h17",
splitbelow = false, -- オンのとき、ウィンドウを横分割すると新しいウィンドウはカレントウィンドウの下に開かれる
splitright = false, -- オンのとき、ウィンドウを縦分割すると新しいウィンドウはカレントウィンドウの右に開かれる
}
vim.opt.shortmess:append("c")
for k, v in pairs(options) do
vim.opt[k] = v
end
vim.cmd("set whichwrap+=<,>,[,],h,l")
vim.cmd([[set iskeyword+=-]])
vim.cmd([[set formatoptions-=cro]]) -- TODO: this doesn't seem to work
設定が反映されているかを確認します。
:set backupskip
backupskip=/tmp/*,/private/tmp/*
今回、キーの入力待機時間の設定が割と重要でした。
updatetime
がそれなんですが、はじめ 100ms にしてみたのですが、相当速いキー入力じゃないと連続したキーとして扱ってくれなかったので、 300ms にしたら安定しました。
ここは個人差がありそうですね。
また、結構ハマってしまったのですが、 splitbelow
splitright
を true にしてしまっていたのですが、これのせいで :vsplit したときに次のウィンドウに移動する keymap が動かなくてなんでなのかをデバッグしました。
keymaps設定をする
$ touch keymaps.lua
local opts = { noremap = true, silent = true }
local term_opts = { silent = true }
--local keymap = vim.keymap
local keymap = vim.api.nvim_set_keymap
--Remap space as leader key
keymap("", "<Space>", "<Nop>", opts)
vim.g.mapleader = " "
vim.g.maplocalleader = " "
-- Modes
-- normal_mode = 'n',
-- insert_mode = 'i',
-- visual_mode = 'v',
-- visual_block_mode = 'x',
-- term_mode = 't',
-- command_mode = 'c',
-- Normal --
-- Better window navigation
keymap("n", "<C-h>", "<C-w>h", opts)
keymap("n", "<C-j>", "<C-w>j", opts)
keymap("n", "<C-k>", "<C-w>k", opts)
keymap("n", "<C-l>", "<C-w>l", opts)
-- New tab
keymap("n", "te", ":tabedit", opts)
-- 新しいタブを一番右に作る
keymap("n", "gn", ":tabnew<Return>", opts)
-- move tab
keymap("n", "gh", "gT", opts)
keymap("n", "gl", "gt", opts)
-- Split window
keymap("n", "ss", ":split<Return><C-w>w", opts)
keymap("n", "sv", ":vsplit<Return><C-w>w", opts)
-- Select all
keymap("n", "<C-a>", "gg<S-v>G", opts)
-- Do not yank with x
keymap("n", "x", '"_x', opts)
-- Delete a word backwards
keymap("n", "dw", 'vb"_d', opts)
-- 行の端に行く
keymap("n", "<Space>h", "^", opts)
keymap("n", "<Space>l", "$", opts)
-- ;でコマンド入力( ;と:を入れ替)
keymap("n", ";", ":", opts)
-- 行末までのヤンクにする
keymap("n", "Y", "y$", opts)
-- <Space>q で強制終了
keymap("n", "<Space>q", ":<C-u>q!<Return>", opts)
-- ESC*2 でハイライトやめる
keymap("n", "<Esc><Esc>", ":<C-u>set nohlsearch<Return>", opts)
-- Insert --
-- Press jk fast to exit insert mode
keymap("i", "jk", "<ESC>", opts)
-- コンマの後に自動的にスペースを挿入
keymap("i", ",", ",<Space>", opts)
-- Visual --
-- Stay in indent mode
keymap("v", "<", "<gv", opts)
keymap("v", ">", ">gv", opts)
-- ビジュアルモード時vで行末まで選択
keymap("v", "v", "$h", opts)
-- 0番レジスタを使いやすくした
keymap("v", "<C-p>", '"0p', opts)
colorscheme設定をする
$ touch colorscheme.lua
もともとは Slack も iTerm2 も全部 dracula
にしていたのですが、
最近は dracula
ではなく nightfox
をよく使っています。
vim.cmd [[
try
colorscheme nightfox
catch /^Vim\%((\a\+)\)\=:E185/
colorscheme default
set background=dark
endtry
]]
plugins設定をする
$ touch plugins.lua
local fn = vim.fn
-- Automatically install packer
local install_path = fn.stdpath("data") .. "/site/pack/packer/start/packer.nvim"
if fn.empty(fn.glob(install_path)) > 0 then
PACKER_BOOTSTRAP = fn.system({
"git",
"clone",
"--depth",
"1",
"https://github.com/wbthomason/packer.nvim",
install_path,
})
print("Installing packer close and reopen Neovim...")
vim.cmd([[packadd packer.nvim]])
end
-- Autocommand that reloads neovim whenever you save the plugins.lua file
vim.cmd([[
augroup packer_user_config
autocmd!
autocmd BufWritePost plugins.lua source <afile> | PackerSync
augroup end
]])
-- Use a protected call so we don't error out on first use
local status_ok, packer = pcall(require, "packer")
if not status_ok then
return
end
-- Have packer use a popup window
packer.init({
display = {
open_fn = function()
return require("packer.util").float({ border = "rounded" })
end,
},
})
-- Install your plugins here
return packer.startup(function(use)
-- My plugins here
use({ "wbthomason/packer.nvim" })
use({ "nvim-lua/plenary.nvim" }) -- Common utilities
-- Colorschemes
use({ "EdenEast/nightfox.nvim" }) -- Color scheme
use({ "nvim-lualine/lualine.nvim" }) -- Statusline
use({ "windwp/nvim-autopairs" }) -- Autopairs, integrates with both cmp and treesitter
use({ "kyazdani42/nvim-web-devicons" }) -- File icons
use({ "akinsho/bufferline.nvim" })
-- cmp plugins
use({ "hrsh7th/nvim-cmp" }) -- The completion plugin
use({ "hrsh7th/cmp-buffer" }) -- buffer completions
use({ "hrsh7th/cmp-path" }) -- path completions
use({ "hrsh7th/cmp-cmdline" }) -- cmdline completions
use({ "saadparwaiz1/cmp_luasnip" }) -- snippet completions
use({ "hrsh7th/cmp-nvim-lsp" })
use({ "hrsh7th/cmp-nvim-lua" })
use({ "onsails/lspkind-nvim" })
-- snippets
use({ "L3MON4D3/LuaSnip" }) --snippet engine
-- LSP
use({ "neovim/nvim-lspconfig" }) -- enable LSP
use({ "williamboman/nvim-lsp-installer" }) -- simple to use language server installer
use({ "jose-elias-alvarez/null-ls.nvim" }) -- for formatters and linters
use({ "glepnir/lspsaga.nvim" }) -- LSP UIs
-- Formatter
use({ "MunifTanjim/prettier.nvim" })
-- Telescope
use({ "nvim-telescope/telescope.nvim" })
-- Treesitter
use({ "nvim-treesitter/nvim-treesitter", { run = ":TSUpdate" } })
use({ "nvim-telescope/telescope-file-browser.nvim" })
use({ "windwp/nvim-ts-autotag" })
-- Automatically set up your configuration after cloning packer.nvim
-- Put this at the end after all plugins
if PACKER_BOOTSTRAP then
require("packer").sync()
end
end)
それぞれのプラグインの設定の部分は以下のリンクからご覧ください。
neovim/plugin at master · hisasann/neovim
packer.nvimでプラグインを管理する
packer.nvimをインストールする
一応ここに packer.nvim のインストール方法を貼ってはいますが、上記 plugins.lua の最初のほうで packer.nvim がない場合は自動的にインストールするようにしているので、不要ではあります。
git clone --depth 1 https://github.com/wbthomason/packer.nvim\
~/.local/share/nvim/site/pack/packer/start/packer.nvim
packer.nvimの使い方
packer.nvim のメインとなる部分は、以下のように use でインストールしたいプラグインを指定するだけです。
use({ "neovim/nvim-lspconfig" })
さらに git の commit を指定することで、特定のバージョンもインストールできるようです。
use({ "neovim/nvim-lspconfig", commit = "148c99bd09b44cf3605151a06869f6b4d4c24455" })
さいごに
hisasann/neovim: hisasann's neovim settings
なんだかんだで10時間ほどいろいろいじっていましたが、ベーシックな部分は5時間ほどでマイグレーションができました。
さらに深夜に作業をしていたので、とにかく楽しかったです。
lofi hiphop を聴きながら無限に Neovim の設定ファイルをいじるのは最高です。
とくに今回の収穫は、 telescope-file-browser.nvim
との出会いでした。
nvim-telescope/telescope-file-browser.nvim: File Browser extension for telescope.nvim
すごく使いやすいファイラーでもあり、爆速です。
今まではダークパワーの Shougo/defx.nvim: The dark powered file explorer implementation for neovim/Vim8 を使っていました。
こちらは数年お世話になったファイラーで、ほんと好きなファイラーです。
参考記事
Set up Neovim on a new M2 MacBook Air for coding React, TypeScript, Tailwind CSS, etc. - YouTube
brainfucksec/neovim-lua: Neovim KISS configuration with Lua
LunarVim/Neovim-from-scratch: A Neovim config designed from scratch to be understandable
Discussion