Making My Tiny Neovim Config
Its that time of year where i revist some of my configs, though this time its because im trying out NixOS again, and happened to forget to save my neovim scripts. Luckily, i already wanted to make a "guide" to how i made my config, because i specifically put a lot of thought into making it as small as possible. And on the note of NixOS, its important to clarify that, first, i wont be using any fancy nix features, and second, this is on nightly. On NixOS im just using neovim in the unstable channel, but you can use whatever AUR package or build from source. All that matters is that im on 0.12.2, because nightly neovim has been working on a very special new feature...
A Native Plugin Manager!
Neovim's been cooking up a module called vim.pack, and while its still experimental, its already quite stable and nice to use (although it doesnt have features like lazy loading that people care about apparently). Part of the reason for this post is to just show off this PM and hopefully get some more eyes on it to get it further developed.
To kick this off, lets set up our only file init.lua with the most important thing any config needs: a colorscheme (and some other defaults).
vim.g.mapleader = " "
vim.opt.nu = true
vim.opt.relativenumber = true
vim.opt.tabstop = 4
vim.opt.softtabstop = 4
vim.opt.shiftwidth = 4
vim.opt.scrolloff = 4
vim.pack.add({
'https://github.com/nvim-lua/plenary.nvim',
'https://github.com/nvim-tree/nvim-web-devicons',
'https://github.com/catppuccin/nvim',
})
vim.cmd.colorscheme "catppuccin-mocha"
vim.pack uses git under the hood, so it'll work with any properly organized git repo without fuss. Lets move on to the actual most important part of a config (in my opinion).
LSP
In my experience the builtin lsp has matured well beyond the need of anything like lspzero. All you really need is to make sure the langauge server is installed and to just feed it to neovim.
vim.diagnostic.config({
virtual_text = true,
signs = false,
})
local function def_lsp (name, cmd)
vim.lsp.config[name] = {
cmd = { cmd },
filetypes = { name },
}
vim.lsp.enable(name)
end
def_lsp('nix', 'nixd')
def_lsp('lua', 'lua-language-server')
That vim.diagnostic.config controls how neovim shows lsp outputs; virtual text shows errors and warnings.
Completions
I currently use cmp because of its wide list of sourcing plugins. Right now I just use cmp-lsp and cmp-async-path but check out its list of sources for others.
local cmp = require('cmp')
cmp.setup({
mapping = cmp.mapping.preset.insert({
['<C-y>'] = cmp.mapping.confirm(),
}),
sources = cmp.config.sources({
{ name = 'nvim_lsp' },
{ name = 'async_path' },
},
{ name = 'buffer' })
})
Code Actions
Depending on your LSP, code actions can be really really helpful. actions-preview can use telescope as a backend, so its what I use.
require('actions-preview').setup {
backend = { 'telescope' },
}
bind({ "v", "n" }, "<leader>a", require("actions-preview").code_actions)
Tree-sitter
Finally, neovim supports better and more language-specific syntax highlighting and text objects using tree-sitter, a really awesome parsing library that compiles language parser object files. nvim-treesitter is a recently abandoned but still very functional plugin to automate fetching and compiling languages on demand.
require('nvim-treesitter').install { 'rust', 'odin', 'c', 'markdown' }
vim.api.nvim_create_autocmd('FileType', {
pattern = { 'rust,odin,c,markdown' },
callback = function() vim.treesitter.start() end,
})
Navigation
A lot of my config is really just focused on file navigation, since thats where I tend to have the most hangups and pauses.
Telescope
Telescope is a no-brainer. The amount of functionality it adds by being so generic is awesome. Heres some bindings I use:
local bind = vim.keymap.set
local ts = require('telescope.builtin')
bind('n', 'tb', ts.buffers) -- buffer list
bind('n', 'tg', ts.live_grep) -- grep
bind('n', 'td', ts.diagnostics) -- searchable lsp diagnostics
bind('n', 'ts', ts.lsp_document_symbols) -- functions and types in buffer
bind('n', 'tm', ts.marks) -- marks
bind('n', 'gd', ts.lsp_type_definitions) -- jump-to-def with previews on conflict
File Explorer
Netrw is great. If you haven't tried not using an explorer plugin I reccomend just seeing how far you can get with whats built in. However, after my little stint with emacs a thing I thought was really cool and missed was how it treats everything like an editable text buffer. Oil is the plugin I use to bring this functionality to neovim. Check out its demo and see if its something youd like.
Harpoon
Harpoon is an honorable mention, but right now im seeing if I actually need it or if marks + telescope serves the same purpose. Very nice plugin though!
Misc. Settings and Binds
I personally prefer turning off swap and backups, and instead using persistent undos:
vim.opt.swapfile = false
vim.opt.backup = false
vim.opt.undodir = vim.fn.stdpath('data') .. ".undodir"
vim.opt.undofile = true
Yank and paste from system clipboard:
bind('n', 'Y', '\"+y')
bind('n', 'P', '\"+p')
And this ones really cool. Holding shift on a selection lets you move it around in the buffer, and auto-indents.
bind('v', 'J', ':m \'>+1<CR>gv=gv')
bind('v', 'K', ':m \'<-2<CR>gv=gv')

