Updated NeoVim Configuration -- explicit AND minimal? post
Can you have a configuration for NeoVim that is both explicit and minimal? I will let you be the judge.
Fans of the One True Editor know that it's flexibility in configuration and huge plugin ecosystem is both good and bad. Since I have some time on my hands I decided to go back and look at my current NeoVim setup and see what can be done.
Here is what I came up with as some ground rules:
- use as much "native NeoVim functionality" as I can
- keep the number of configuration files to the bare minimum (currently sitting at 1)
- really think about what I want my workflow to be.
I'll break down what I've done so far.
First a reminder to install a Lua language server to I can edit this configuration file too and get hints if I make mistakes.
-- Make sure to install lua-language-server locally
Next, cover some basics:
-- General configuration
vim.o.autocomplete = true -- We generally want autocomplete
vim.g.mapleader = " "
vim.g.maplocalleader = "\\"
vim.o.expandtab = true
vim.o.smartindent = true
vim.o.autoindent = true
vim.o.number = true
vim.o.relativenumber = true
vim.o.cursorline = true
vim.o.signcolumn = "yes"
vim.o.signcolumn = "yes"
vim.diagnostic.config({ virtual_text = true })
I am using NeoVim's built-in package management.
For those wondering, here is a highlight of the packages:
- Alabaster is a minimalist theme
- Mason makes it easier to install language servers as I need them
- the Debug Anything Protocol powers my XDebug configuration
- Treesitter and Telescope seem to be turning into requirements for a lot of other packages
- Snacks is for making some context-friendly key mappings
- which-key created pop-up summaries of what is available for key mappings while using them
- mini.nvim is a collection of very small plugins (I am only using the status bar one for now)
The PackChanged stuff is so any of the stuff Treesitter has installed gets updated whenever I open up NeoVim.
-- Package management
vim.api.nvim_create_autocmd("PackChanged", {
group = vim.api.nvim_create_augroup("treesitter_tsupdate", { clear = true }),
callback = function(ev)
local name, kind = ev.data.spec.name, ev.data.kind
if name ~= "nvim-treesitter" then return end
if kind ~= "install" and kind ~= "update" then return end
if not ev.data.active then
vim.cmd.packadd("nvim-treesitter")
end
vim.cmd("TSUpdate")
end,
})
vim.pack.add({
{ src = "https://git.sr.ht/~p00f/alabaster.nvim" },
{ src = "https://github.com/neovim/nvim-lspconfig" },
{ src = "https://github.com/mason-org/mason.nvim" },
{ src = "https://github.com/mason-org/mason-lspconfig.nvim" },
{ src = "https://github.com/nvim-treesitter/nvim-treesitter" },
{ src = "https://github.com/mfussenegger/nvim-dap" },
{ src = "https://github.com/rcarriga/nvim-dap-ui" },
{ src = "https://github.com/theHamsta/nvim-dap-virtual-text" },
{ src = "https://github.com/nvim-treesitter/nvim-treesitter" },
{ src = "https://github.com/nvim-telescope/telescope-dap.nvim" },
{ src = "https://github.com/nvim-telescope/telescope.nvim" },
{ src = "https://github.com/folke/snacks.nvim" },
{ src = "https://github.com/nvim-lua/plenary.nvim" },
{ src = "https://github.com/pdaether/pest.nvim" },
{ src = "https://github.com/folke/which-key.nvim" },
{ src = "https://github.com/nvim-mini/mini.nvim" },
})
Explicitly set up the packages I installed:
require('mason').setup()
require('mason-lspconfig').setup({
ensure_installed = { "intelephense", "lua_ls" }
})
require('nvim-treesitter').setup()
require('telescope').setup()
require('snacks').setup()
require('which-key').setup()
require('mini.statusline').setup()
DAP-specific stuff:
-- debugging set up
local dap = require('dap')
require('telescope').load_extension('dap')
dap.adapters.php = {
type = "executable",
command = "node",
args = { os.getenv("HOME") .. "/vscode-php-debug/out/phpDebug.js" }
}
dap.configurations.php = {
{
type = "php",
request = "launch",
name = "Listen for Xdebug",
port = 9003
},
{
type = "php",
request = "launch",
name = "Launch Pest (current file) with Xdebug",
program = function()
return vim.fn.getcwd() .. "/vendor/bin/pest"
end,
cwd = "${workspaceFolder}",
args = { "${file}" },
port = 9003,
env = {
XDEBUG_MODE = "debug",
XDEBUG_SESSION = "pest",
},
},
}
Don't forget the colour scheme:
-- Colorscheme setup
vim.cmd('colorscheme alabaster')
LSP-specific configuration:
-- LSP configuration
vim.keymap.set("n", "gl", vim.diagnostic.open_float)
vim.api.nvim_create_autocmd('LspAttach', {
group = vim.api.nvim_create_augroup('my.lsp', {}),
callback = function(ev)
local client = assert(vim.lsp.get_client_by_id(ev.data.client_id))
if client:supports_method('textDocument/completion') then
vim.lsp.completion.enable(true, client.id, ev.buf, {autotrigger = true})
end
end,
})
All lazy programmers love auto completion:
-- Autocompletion
vim.opt.complete:append('o')
vim.opt.completeopt = { 'menuone', 'noselect' }
vim.o.pumheight = 5
vim.o.pumborder = 'rounded'
Key mappings (I use which-key so I never have to really remember anything other than the first letter of the combo)
-- DAP keymaps via snacks.nvim
local map = require("snacks.keymap").set
map("n", "<F5>", function() require("dap").continue() end, { desc = "DAP Continue" })
map("n", "<F10>", function() require("dap").step_over() end, { desc = "DAP Step Over" })
map("n", "<F11>", function() require("dap").step_into() end, { desc = "DAP Step Into" })
map("n", "<F12>", function() require("dap").step_out() end, { desc = "DAP Step Out" })
map("n", "<Leader>b", function() require("dap").toggle_breakpoint() end, { desc = "DAP Toggle Breakpoint" })
map("n", "<Leader>B", function() require("dap").set_breakpoint() end, { desc = "DAP Set Breakpoint" })
map("n", "<Leader>lp", function()
require("dap").set_breakpoint(nil, nil, vim.fn.input("Log point message: "))
end, { desc = "DAP Log Point" })
map("n", "<Leader>dr", function() require("dap").repl.open() end, { desc = "DAP REPL Open" })
map("n", "<Leader>dl", function() require("dap").run_last() end, { desc = "DAP Run Last" })
map({ "n", "v" }, "<Leader>dh", function()
require("dap.ui.widgets").hover()
end, { desc = "DAP Hover Widgets" })
map({ "n", "v" }, "<Leader>dp", function()
require("dap.ui.widgets").preview()
end, { desc = "DAP Preview Widgets" })
map("n", "<Leader>df", function()
local widgets = require("dap.ui.widgets")
widgets.centered_float(widgets.frames)
end, { desc = "DAP Frames" })
map("n", "<Leader>ds", function()
local widgets = require("dap.ui.widgets")
widgets.centered_float(widgets.scopes)
end, { desc = "DAP Scopes" })
-- telescope keymaps
local builtin = require('telescope.builtin')
vim.keymap.set('n', '<leader>ff', builtin.find_files, { desc = 'Telescope find files' })
vim.keymap.set('n', '<leader>fg', builtin.live_grep, { desc = 'Telescope live grep' })
vim.keymap.set('n', '<leader>fb', builtin.buffers, { desc = 'Telescope buffers' })
vim.keymap.set('n', '<leader>fh', builtin.help_tags, { desc = 'Telescope help tags' })
Pest for PHP tests:
-- Settings for running Pest tests
require('pest-nvim').setup({
pest_cmd = 'vendor/bin/pest',
window_size = 25,
})
That's all that is in there for now.
I go through cycles of installing all sorts of plugins and then trimming them down. This time around I am going to start with what I think is a good base set and then carefully add in more stuff as I need it.
Here is the whole thing if you want to just copy-and-paste
-- Make sure to install lua-language-server locally
-- General configuration
vim.o.autocomplete = true -- We generally want autocomplete
vim.g.mapleader = " "
vim.g.maplocalleader = "\\"
vim.o.expandtab = true
vim.o.smartindent = true
vim.o.autoindent = true
vim.o.number = true
vim.o.relativenumber = true
vim.o.cursorline = true
vim.o.signcolumn = "yes"
vim.o.signcolumn = "yes"
vim.diagnostic.config({ virtual_text = true })
-- Package management
vim.api.nvim_create_autocmd("PackChanged", {
group = vim.api.nvim_create_augroup("treesitter_tsupdate", { clear = true }),
callback = function(ev)
local name, kind = ev.data.spec.name, ev.data.kind
if name ~= "nvim-treesitter" then return end
if kind ~= "install" and kind ~= "update" then return end
-- If TSUpdate relies on the plugin being loaded, ensure it is.
if not ev.data.active then
vim.cmd.packadd("nvim-treesitter")
end
vim.cmd("TSUpdate")
end,
})
vim.pack.add({
{ src = "https://git.sr.ht/~p00f/alabaster.nvim" },
{ src = "https://github.com/neovim/nvim-lspconfig" },
{ src = "https://github.com/mason-org/mason.nvim" },
{ src = "https://github.com/mason-org/mason-lspconfig.nvim" },
{ src = "https://github.com/nvim-treesitter/nvim-treesitter" },
{ src = "https://github.com/mfussenegger/nvim-dap" },
{ src = "https://github.com/rcarriga/nvim-dap-ui" },
{ src = "https://github.com/theHamsta/nvim-dap-virtual-text" },
{ src = "https://github.com/nvim-treesitter/nvim-treesitter" },
{ src = "https://github.com/nvim-telescope/telescope-dap.nvim" },
{ src = "https://github.com/nvim-telescope/telescope.nvim" },
{ src = "https://github.com/folke/snacks.nvim" },
{ src = "https://github.com/nvim-lua/plenary.nvim" },
{ src = "https://github.com/pdaether/pest.nvim" },
{ src = "https://github.com/folke/which-key.nvim" },
{ src = "https://github.com/nvim-mini/mini.nvim" },
})
require('mason').setup()
require('mason-lspconfig').setup({
ensure_installed = { "intelephense", "lua_ls" }
})
require('nvim-treesitter').setup()
require('telescope').setup()
require('snacks').setup()
require('which-key').setup()
require('mini.statusline').setup()
-- debugging set up
local dap = require('dap')
require('telescope').load_extension('dap')
dap.adapters.php = {
type = "executable",
command = "node",
args = { os.getenv("HOME") .. "/vscode-php-debug/out/phpDebug.js" }
}
dap.configurations.php = {
{
type = "php",
request = "launch",
name = "Listen for Xdebug",
port = 9003
},
{
type = "php",
request = "launch",
name = "Launch Pest (current file) with Xdebug",
program = function()
return vim.fn.getcwd() .. "/vendor/bin/pest"
end,
cwd = "${workspaceFolder}",
args = { "${file}" },
port = 9003,
env = {
XDEBUG_MODE = "debug",
XDEBUG_SESSION = "pest",
},
},
}
-- Colorscheme setup
vim.cmd('colorscheme alabaster')
-- LSP configuration
vim.keymap.set("n", "gl", vim.diagnostic.open_float)
vim.api.nvim_create_autocmd('LspAttach', {
group = vim.api.nvim_create_augroup('my.lsp', {}),
callback = function(ev)
local client = assert(vim.lsp.get_client_by_id(ev.data.client_id))
if client:supports_method('textDocument/completion') then
vim.lsp.completion.enable(true, client.id, ev.buf, {autotrigger = true})
end
end,
})
-- Autocompletion
vim.opt.complete:append('o')
vim.opt.completeopt = { 'menuone', 'noselect' }
vim.o.pumheight = 5
vim.o.pumborder = 'rounded'
-- DAP keymaps via snacks.nvim
local map = require("snacks.keymap").set
map("n", "<F5>", function() require("dap").continue() end, { desc = "DAP Continue" })
map("n", "<F10>", function() require("dap").step_over() end, { desc = "DAP Step Over" })
map("n", "<F11>", function() require("dap").step_into() end, { desc = "DAP Step Into" })
map("n", "<F12>", function() require("dap").step_out() end, { desc = "DAP Step Out" })
map("n", "<Leader>b", function() require("dap").toggle_breakpoint() end, { desc = "DAP Toggle Breakpoint" })
map("n", "<Leader>B", function() require("dap").set_breakpoint() end, { desc = "DAP Set Breakpoint" })
map("n", "<Leader>lp", function()
require("dap").set_breakpoint(nil, nil, vim.fn.input("Log point message: "))
end, { desc = "DAP Log Point" })
map("n", "<Leader>dr", function() require("dap").repl.open() end, { desc = "DAP REPL Open" })
map("n", "<Leader>dl", function() require("dap").run_last() end, { desc = "DAP Run Last" })
map({ "n", "v" }, "<Leader>dh", function()
require("dap.ui.widgets").hover()
end, { desc = "DAP Hover Widgets" })
map({ "n", "v" }, "<Leader>dp", function()
require("dap.ui.widgets").preview()
end, { desc = "DAP Preview Widgets" })
map("n", "<Leader>df", function()
local widgets = require("dap.ui.widgets")
widgets.centered_float(widgets.frames)
end, { desc = "DAP Frames" })
map("n", "<Leader>ds", function()
local widgets = require("dap.ui.widgets")
widgets.centered_float(widgets.scopes)
end, { desc = "DAP Scopes" })
-- Settings for running Pest tests
require('pest-nvim').setup({
pest_cmd = 'vendor/bin/pest',
window_size = 25,
})
-- telescope keymaps
local builtin = require('telescope.builtin')
vim.keymap.set('n', '<leader>ff', builtin.find_files, { desc = 'Telescope find files' })
vim.keymap.set('n', '<leader>fg', builtin.live_grep, { desc = 'Telescope live grep' })
vim.keymap.set('n', '<leader>fb', builtin.buffers, { desc = 'Telescope buffers' })
vim.keymap.set('n', '<leader>fh', builtin.help_tags, { desc = 'Telescope help tags' })
Categories: tools, NeoVim