プログラミングする時の一番大事な道具はエディタ。僕は neovim を使っていて、その設定をまとめた。
mkdir -p ~/.config/nvim/lua mkdir -p ~/.config/nvim/plugin mkdir -p ~/.config/nvim/after/plugin
init.lua
mac だとディレクトリはこんな感じ。
Users/ ├─ yasushi/ │ ├─ .config/ │ │ ├─ nvim/ │ │ │ ├─ init.lua │ │ │ ├─ lua/ │ │ │ ├─ options.lua │ │ │ ├─ keymaps.lua │ │ │ ├─ packages.lua
これは、 ~/.config/nvim/init.lua
で、みての通り、他の設定をまとめているだけ。neovim は、lua 言語(でも)設定する。
require('options') require('keymaps') require('packages')
options.lua
vim.opt.tabstop = 4 vim.opt.shiftwidth = 4 vim.opt.softtabstop = 4 -- I don't know why this is not working with 'vim.opt' vim.cmd[[set noexpandtab]] vim.opt.encoding = 'utf-8' vim.scriptencoding = 'utf-8' -- vim.opt.ambiwidth= 'double' vim.opt.timeoutlen=300 vim.opt.updatetime=300 vim.opt.signcolumn="yes" vim.opt.splitright = true vim.opt.splitbelow = true vim.opt.mouse="a" vim.opt.undodir= vim.fn.getenv("HOME") .. "/.vimdid" vim.opt.undofile = true vim.opt.scrolloff = 999 vim.opt.laststatus = 2 vim.opt.ignorecase = true vim.opt.smartcase = true vim.opt.gdefault = true vim.opt.relativenumber = true vim.opt.number = true vim.ayucolor="dark" if vim.fn.has('macunix') then vim.opt.clipboard:append { 'unnamedplus' } end -- au TextYankPost * silent! lua vim.highlight.on_yank() vim.cmd('au TextYankPost * silent! lua.highlight.on_yank()') -- no line numbers when using the teminal vim.cmd('au TermOpen * setlocal nonumber norelativenumber') -- neomutt text-flowed option vim.cmd('au BufNewFile,BufRead neomutt-* setf mail') -- color scheme vim.g.tokyonight_style = "night" vim.cmd[[colorscheme tokyonight]]
ファイルタイプ個別対応
rust
vim.cmd('setl colorcolumn=100') vim.cmd('setl expandtab') vim.cmd('setl tabstop=4') vim.cmd('setl shiftwidth=4') vim.cmd('setl softtabstop=4') local tools = require"rust-tools"; require"which-key".register( { m = { name = 'Language specific tools (Rust)', e = {tools.expand_macro.expand_macro, 'expand macro'}, c = {tools.open_cargo_toml.open_cargo_toml, 'open Cargo.toml'}, h = {'<cmd>RustHoverActions<cr><cmd>RustHoverActions<cr>', 'hover actions'}, -- want to toggle.... d = {'<cmd>RustDisableInlayHints<cr>', 'disable inlay hints'}, i = {'<cmd>RustEnableInlayHints<cr>', 'enable inlay hints'}, } }, {prefix = "<leader>"} )
yaml
vim.cmd('setl colorcolumn=100') vim.cmd('setl expandtab') vim.cmd('setl tabstop=2') vim.cmd('setl shiftwidth=2') vim.cmd('setl softtabstop=2')
Mail の設定参照の事たまーに、一行 72 文字で書きましょうみたいなメーリスがおたく界隈ではあるので、それに対応している。でも、英語圏でしか通用しないんだけどね。
vim.cmd('setl tw=72') vim.cmd('setl fo=awq') vim.cmd('setl comments+=nb:>')
keymaps
プラグインの関数と結びつけていたり、特殊なものは whichkey
を使っているので、そっち参照
ウィンドウ操作が ’f’ でいいのかわからない。
local keymap = vim.api.nvim_set_keymap local opts = {noremap=true} local function nkeymap (key, target) keymap('n', key, target, opts) end vim.g.mapleader = " " keymap('i', 'jj', '<Esc>', opts) nkeymap('j','gj') nkeymap('k','gk') nkeymap(';',':') -- increment / decrement nkeymap('+', '<C-a>') nkeymap('-', '<C-x>') -- terminal keymap('t', 'jk', '<c-\\><c-n>', {})
packages.lua
packer
ってのが lua 製のパッケージマネージャらしいので使う。
最初に packer
自体を入れないといけないのはここに書いてあるけど、ようするに下記を実行する。
git clone --depth 1 https://github.com/wbthomason/packer.nvim\ ~/.local/share/nvim/site/pack/packer/start/packer.nvim
設定をなにか変えたら下記を実行で、同期してくれる。
nvim --headless -c 'autocmd User PackerComplete quitall' -c 'PackerSync'
:PackerInstall
をすれば、他のをインストールしてくれる。他のコマンドも用途に応じてどうぞ。
-- make sure packer is there local status, packer = pcall(require, "packer") if (not status) then print("Can't find Packer") return end vim.cmd[[packadd packer.nvim]] require('packer').startup(function() use 'wbthomason/packer.nvim' use 'kyazdani42/nvim-web-devicons' use 'jose-elias-alvarez/null-ls.nvim' use 'glepnir/lspsaga.nvim' -- better LSP UI use 'neovim/nvim-lspconfig' --- after 'plugins' -- auto pairs use 'windwp/nvim-autopairs' use 'windwp/nvim-ts-autotag' -- completion use 'hrsh7th/nvim-cmp' use 'L3MON4D3/LuaSnip' use "rafamadriz/friendly-snippets" use 'onsails/lspkind-nvim' use 'hrsh7th/cmp-nvim-lsp' use 'hrsh7th/cmp-path' use 'hrsh7th/cmp-buffer' -- git use { 'TimUntersberger/neogit', requires = {'nvim-lua/plenary.nvim' } } use { 'nvim-lualine/lualine.nvim', requires = { 'kyazdani42/nvim-web-devicons', opt = true } } use 'MunifTanjim/prettier.nvim' use { 'nvim-telescope/telescope.nvim', requires = {'nvim-lua/plenary.nvim'}, } use 'nvim-telescope/telescope-file-browser.nvim' use { 'nvim-treesitter/nvim-treesitter', run = ':TSUpdate' } use 'airblade/vim-rooter' use 'ggandor/lightspeed.nvim' -- use leap? use 'simrat39/rust-tools.nvim' use 'famiu/bufdelete.nvim' use 'folke/tokyonight.nvim' -- this comes last use {'folke/which-key.nvim', config = function() require("which-key").setup { spelling = { enabled = true }} end } use 'haya14busa/vim-migemo' end)
null-ls
local status, config = pcall(require, "null-ls") if (not status) then return end config.setup({ sources = { config.builtins.diagnostics.eslint_d.with({ diagnostics_format = '[eslint] #{m}\n(#{c})' }) } })
lspsaga
local status, saga = pcall(require, "lspsaga") if (not status) then return end saga.init_lsp_saga({ border_style = "rounded", finder_action_keys = { open = "<cr>", quit = "<esc>", }, code_action_keys = { quit = "<esc>" }, definition_action_keys = { quit = "<esc>" } }) -- saga.init_lsp_saga { -- server_filetype_map = { -- typescript = 'typescript' -- }, -- finder_action_keys = { -- open = "<CR>", -- quit = "<esc>" -- } -- }
lspconfig
--vim.lsp.set_log_level("debug") local status, nvim_lsp = pcall(require, "lspconfig") if (not status) then return end local protocol = require('vim.lsp.protocol') -- Use an on_attach function to only map the following keys -- after the language server attaches to the current buffer local on_attach = function(client, bufnr) local function buf_set_option(...) vim.api.nvim_buf_set_option(bufnr, ...) end --Enable completion triggered by <c-x><c-o> buf_set_option('omnifunc', 'v:lua.vim.lsp.omnifunc') -- Mappings. local opts = { noremap = true, silent = true } -- 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 end protocol.CompletionItemKind = { '', -- Text '', -- Method '', -- Function '', -- Constructor '', -- Field '', -- Variable '', -- Class 'ﰮ', -- Interface '', -- Module '', -- Property '', -- Unit '', -- Value '', -- Enum '', -- Keyword '', -- Snippet '', -- Color '', -- File '', -- Reference '', -- Folder '', -- EnumMember '', -- Constant '', -- Struct '', -- Event 'ﬦ', -- Operator '', -- TypeParameter } -- Set up completion using nvim_cmp with LSP source local capabilities = require('cmp_nvim_lsp').update_capabilities( vim.lsp.protocol.make_client_capabilities() ) nvim_lsp.tsserver.setup { on_attach = on_attach, filetypes = { "typescript", "typescriptreact", "typescript.tsx" }, cmd = { "typescript-language-server", "--stdio" }, capabilities = capabilities } nvim_lsp.sumneko_lua.setup { on_attach = on_attach, settings = { Lua = { diagnostics = { -- Get the language server to recognize the `vim` global globals = { 'vim' }, }, workspace = { -- Make the server aware of Neovim runtime files library = vim.api.nvim_get_runtime_file("", true), checkThirdParty = false }, }, }, } local util = require "lspconfig/util" nvim_lsp.gopls.setup { cmd = {"gopls", "serve"}, filetypes = {"go", "gomod"}, root_dir = util.root_pattern("go.work", "go.mod", ".git"), settings } require("rust-tools").setup({ server = { on_attach = on_attach, capabilities = capabilities }, }) nvim_lsp.tailwindcss.setup {} vim.lsp.handlers["textDocument/publishDiagnostics"] = vim.lsp.with( vim.lsp.diagnostic.on_publish_diagnostics, { underline = true, update_in_insert = false, virtual_text = { spacing = 4, prefix = "●" }, severity_sort = true, } ) -- Diagnostic symbols in the sign column (gutter) local signs = { Error = " ", Warn = " ", Hint = " ", Info = " " } for type, icon in pairs(signs) do local hl = "DiagnosticSign" .. type vim.fn.sign_define(hl, { text = icon, texthl = hl, numhl = "" }) end vim.diagnostic.config({ virtual_text = { prefix = '●' }, update_in_insert = true, float = { source = "always", -- Or "if_many" }, })
これいこうはそれぞれの Plugin の設定は、 ~/.config/nvim/after/plugin/XXX.rc.lua
の中にかいておくと、
autopairs
local status, config = pcall(require, "nvim-autopairs") if(not status) then return end config.setup({ disable_filetype = {"TelescopePrompt", "vim"} })
cmp
local status, cmp = pcall(require, "cmp") if(not status) then return end local has_words_before = function() local line, col = unpack(vim.api.nvim_win_get_cursor(0)) return col ~= 0 and vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match("%s") == nil end local lspkind = require 'lspkind' local luasnip = require 'luasnip' -- lazy load require("luasnip.loaders.from_vscode").lazy_load() cmp.setup({ snippet = { expand = function(args) luasnip.lsp_expand(args.body) end, }, mapping = cmp.mapping.preset.insert({ ['<C-d>'] = cmp.mapping.scroll_docs(-4), ['<C-f>'] = cmp.mapping.scroll_docs(-4), ['<C-Space>'] = cmp.mapping.complete(), ['<C-e>'] = cmp.mapping.close(), ['<CR>'] = cmp.mapping.confirm({ behaivior = cmp.ConfirmBehavior.Replace, select = true }), ["<Tab>"] = cmp.mapping(function(fallback) if cmp.visible() then cmp.select_next_item() elseif luasnip.expand_or_jumpable() then luasnip.expand_or_jump() elseif has_words_before() then cmp.complete() else fallback() end end, { "i", "s" }), ["<S-Tab>"] = cmp.mapping(function(fallback) if cmp.visible() then cmp.select_prev_item() elseif luasnip.jumpable(-1) then luasnip.jump(-1) else fallback() end end, { "i", "s" }) }), sources = cmp.config.sources({ {name = 'nvim_lsp'}, {name = 'buffer'}, {name = 'path'}, }), formatting = { format = lspkind.cmp_format({mode = 'symbol', maxwidth = 50}) } })
lspkind
local status, config = pcall(require, "lspkind") if (not status) then return end config.init({ mode='symbol', })
lualine
- this get’s upset when it’s not in a git repository..?
local status, config = pcall(require, "lualine") if (not status) then return end config.setup{ options = { theme = 'tokyonight' } }
prettier
local status, config = pcall(require, "prettier") if (not status) then return end config.setup { bin = 'prettierd', filetypes = { "css", "javascript", "javascriptreact", "typescript", "typescriptreact", "json", "scss", "less" } }
telescope
local status, config = pcall(require, "telescope") if (not status) then return end local actions = require('telescope.actions') config.setup { defaults = { mappings = { n = { ["q"] = actions.close }, }, }, extensions = { file_browser = { theme = "dropdown", -- disables netrw and use telescope-file-browser in its place hijack_netrw = true, }, }, } config.load_extension("file_browser")
treesitter
local status, config = pcall(require, "nvim-treesitter.configs") if (not status) then return end config.setup { autotag = { enable = true }, highlight = { enable = true, disable = {}, }, indent = { enable = true, disable = {}, }, ensure_installed = { "tsx", "toml", "php", "json", "yaml", "css", "html", "lua", "rust" }, autotag = { enable = true, }, } local parser_config = require "nvim-treesitter.parsers".get_parser_configs() parser_config.tsx.filetype_to_parsername = { "javascript", "typescript.tsx" }
whichkey
local status, config = pcall(require, "which-key") if(not status) then return end config.setup{ spelling = {enabled = true} } config.register( { f = {'<cmd>Telescope find_files<cr>', 'Find files'}, r = {'<cmd>Telescope live_grep<cr>', 'Grep'}, h = {'<cmd>Telescope help_tags<cr>', 'Help tags'}, j = {'<cmd>Migemo<cr>', 'search Japanese text'}, b = { name = 'buffer', b = {"<cmd>Telescope buffers<cr>", "Buffer list"}, p = {"<cmd>bp<cr>", "Prev Buffer"}, n = {"<cmd>bn<cr>", "Next Buffer"}, d = {"<cmd>Bdelete<cr>", "Delete buffer"} }, g = { name = 'LSP functions', g = {'<cmd>Lspsaga lsp_finder<cr>', 'LSP find file'}, f = {vim.lsp.buf.formatting_seq_sync(), 'LSP format'}, n = {'<cmd>Lspsaga diagnostic_jump_next<cr>', 'next diagnostic'}, p = {'<cmd>Lspsaga diagnostic_jump_prev<cr>', 'prev diagnostic'}, d = {'<cmd>Lspsaga preview_definition<cr>', 'preview definition'}, D = {vim.lsp.buf.definition(), 'jump to definition'}, a = {'<cmd>Lspsaga code_action<cr>', 'code action'}, k = {'<cmd>Lspsaga hover_doc<cr>', 'documentation'}, K = {'<cmd>Lspsaga signature_help<cr>', 'signature help'}, i = {vim.lsp.buf.implementation(), 'list implementation'}, r = {'<cmd>Lspsaga rename<cr>', 'rename'} }, s = {'<cmd>Neogit kind=split<cr>', 'Git'}, t = {'<cmd>terminal<cr>', 'Open Terminal'}, e = {'<cmd>e .<cr>', 'edit'} }, {prefix = "<leader>"} )
migemo
cmigemo
の辞書ファイルがみつからなくて :Migemo
コマンドから怒られる。
vim.g.migemodict='/opt/homebrew/Cellar/cmigemo/20110227/share/migemo/utf-8/migemo-dict'
vscode
neovim じゃないけど、vscode を Mac で使(わないといけない悲しい状況があり)う時に、 hjkl
がリピートしない。
defaults write com.microsoft.VSCode ApplePressAndHoldEnabled -bool false
上をやれって言われてるけど、ならない。謎