nixos-config/users/simon/modules/neovim/init.lua

291 lines
9.3 KiB
Lua

-- Aliases
local cmd = vim.cmd
local fn = vim.fn
local g = vim.g
local opt = vim.opt
local map = vim.api.nvim_set_keymap
-- Helpers
local function noremap(mode, lhs, rhs, opts)
local options = { noremap = true }
if opts then options = vim.tbl_extend('force', options, opts) end
vim.api.nvim_set_keymap(mode, lhs, rhs, options)
end
local function associate_filetype(glob, ft)
cmd('autocmd BufRead,BufNewFile ' .. glob .. ' set filetype=' .. ft)
end
local function setup_filetype(ft, tab, expandtab, opts)
local cmdline = 'autocmd Filetype ' .. ft .. ' setlocal'
if tab then cmdline = cmdline .. ' ts=' .. tab .. ' sw=' .. tab .. ' sts=' .. tab end
if opts then cmdline = cmdline .. ' ' .. opts end -- FIXME: opts should be a table
cmd(cmdline)
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
-- Display
opt.number = true -- line numbers
opt.colorcolumn = { '80' } -- line at 80 characters
opt.scrolloff = 5 -- context at top/bottom
opt.sidescrolloff = 8 -- context on the left/right side
opt.conceallevel = 1 -- conceal inactive lines
opt.termguicolors = true
cmd('colorscheme solarized')
-- Undo
opt.undofile = true
opt.undolevels = 4096
opt.undoreload = 16384
-- Behaviour
opt.hidden = true -- background buffers
opt.expandtab = true -- spaces instead of tabs by default
opt.smartindent = true -- automatic indentation
opt.tabstop = 2 -- tabs have width of 2 by default
opt.shiftwidth = 0 -- shift width = tab width
opt.joinspaces = false -- no double spaces when joining
opt.clipboard = 'unnamedplus' -- use system clipboard
opt.modeline = true
cmd([[
autocmd BufReadPost * if line("'\"") >= 1 && line("'\"") <= line("$") && &ft !~# 'commit' | exe "normal! g`\"" | endif
]]) -- see :h last-position-jump
-- Search
opt.ignorecase = true -- ignore case
opt.smartcase = true -- but only with all-lowercase searches
-- Highlight trailing spaces
cmd([[autocmd BufWinEnter * match errorMsg /\s\+$\| \+\ze\t/]])
-- Mappings
g.mapleader = ','
noremap('n', '<CR>', ':nohlsearch<CR>', { silent = true }) -- hide highlights on enter
noremap('v', '<Leader>s', ':sort<CR>') -- sort in visual mode
noremap('t', '<Esc><Esc>', [[<C-\><C-n>]])
-- Filetypes
associate_filetype('*.vpy', 'python') -- vapoursynth scripts
setup_filetype('bib', 1)
setup_filetype('c', 4)
setup_filetype('cpp', 4)
setup_filetype('dockerfile', 4)
setup_filetype('gitcommit', nil, 'colorcolumn=72')
setup_filetype('go', 4, 'noexpandtab')
setup_filetype('haskell', 4)
setup_filetype('lua', 4)
setup_filetype('python', 4)
setup_filetype('sh', 4, 'noexpandtab')
setup_filetype('tex', 1)
setup_filetype('zsh', 4)
-- Plugins
-- Status line
local custom_solarized_lualine = require('lualine.themes.solarized')
-- default colours are very hard to read
custom_solarized_lualine.normal.b = { fg = '#eee8d5', bg = '#586e75' }
require('lualine').setup {
options = {
theme = custom_solarized_lualine,
},
sections = {
lualine_c = {
'filename',
'lsp_progress',
},
},
}
-- Tagbar
noremap('n', '<F8>', ':TagbarToggle<CR>')
-- Keymap popup
require('which-key').setup {}
-- Icons
require('nvim-web-devicons').setup { default = true }
-- Git
require('plenary') -- otherwise neogit SIGABRTs
require('neogit').setup {
disable_commit_confirmation = true,
integrations = {
diffview = true,
},
}
cmd([[
hi NeogitNotificationInfo guifg=#268bd2
hi NeogitNotificationWarning guifg=#cb4b16
hi NeogitNotificationError guifg=#dc322f
]])
require('gitsigns').setup()
require('diffview').setup {}
-- Fuzzy finder/option picker
require('telescope').setup {}
-- Completion/Snippets
local cmp = require('cmp')
local lspkind = require('lspkind')
local luasnip = require('luasnip')
luasnip.config.set_config {
enable_autosnippets = true,
}
require('snippets')
cmp.setup {
snippet = {
expand = function(args) luasnip.lsp_expand(args.body) end,
},
mapping = {
['<C-d>'] = cmp.mapping(cmp.mapping.scroll_docs(-4), { 'i', 'c' }),
['<C-f>'] = cmp.mapping(cmp.mapping.scroll_docs(4), { 'i', 'c' }),
['<C-e>'] = cmp.mapping({ i = cmp.mapping.abort(), c = cmp.mapping.close() }),
['<CR>'] = cmp.mapping.confirm({ select = false }),
['<Tab>'] = cmp.mapping(function(fallback)
if luasnip.expand_or_jumpable() then
luasnip.expand_or_jump()
elseif cmp.visible() then
cmp.select_next_item()
elseif has_words_before() then
cmp.complete()
else
fallback()
end
end, { 'i', 's' }),
['<S-Tab>'] = cmp.mapping(function(fallback)
if luasnip.jumpable(-1) then
luasnip.jump(-1)
elseif cmp.visible() then
cmp.select_prev_item()
else
fallback()
end
end, { 'i', 's' }),
},
sources = cmp.config.sources({
{ name = 'nvim_lsp' },
{ name = 'luasnip' },
{ name = 'path' }
}, {
{
name = 'buffer',
opts = {
keyword_pattern = [[\k\+]], -- allow unicode multibyte characters
},
}
}),
formatting = {
format = lspkind.cmp_format({
with_text = false,
maxwidth = 50,
})
},
}
-- LSP
local lsp = require('lspconfig')
vim.lsp.handlers['textDocument/publishDiagnostics'] = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
update_in_insert = true, -- update suggestions in insert mode
})
for type, icon in pairs({ Error = '', Warning = '', Hint = '', Information = '' }) do
local hl = 'LspDiagnosticsSign' .. type
fn.sign_define(hl, { text = icon, texthl = hl, numhl = hl })
end
local on_attach = function(client, bufnr)
local function buf_set_keymap(...) vim.api.nvim_buf_set_keymap(bufnr, ...) end
local function buf_set_option(...) vim.api.nvim_buf_set_option(bufnr, ...) end
buf_set_option('omnifunc', 'v:lua.vim.lsp.omnifunc')
local opts = { noremap = true, silent = true }
buf_set_keymap('n', 'gD', '<cmd>lua vim.lsp.buf.declaration()<CR>', opts)
buf_set_keymap('n', 'gd', '<cmd>lua require("telescope.builtin").lsp_definitions()<CR>', opts)
buf_set_keymap('n', 'K', '<cmd>lua vim.lsp.buf.hover()<CR>', opts)
buf_set_keymap('n', 'gi', '<cmd>lua require("telescope.builtin").lsp_implementations()<CR>', opts)
buf_set_keymap('n', '<C-k>', '<cmd>lua vim.lsp.buf.signature_help()<CR>', opts)
buf_set_keymap('n', '<Leader>wa', '<cmd>lua vim.lsp.buf.add_workspace_folder()<CR>', opts)
buf_set_keymap('n', '<Leader>wr', '<cmd>lua vim.lsp.buf.remove_workspace_folder()<CR>', opts)
buf_set_keymap('n', '<Leader>wl', '<cmd>lua print(vim.inspect(vim.lsp.buf.list_workspace_folders()))<CR>', opts)
buf_set_keymap('n', '<Leader>D', '<cmd>lua require("telescope.builtin").lsp_type_definitions()<CR>', opts)
buf_set_keymap('n', '<Leader>rn', '<cmd>lua vim.lsp.buf.rename()<CR>', opts)
buf_set_keymap('n', '<Leader>ca', '<cmd>lua require("telescope.builtin").lsp_code_actions()<CR>', opts)
buf_set_keymap('n', 'gr', '<cmd>lua vim.lsp.buf.references()<CR>', opts)
buf_set_keymap('n', '<Leader>d', '<cmd>lua vim.lsp.diagnostic.show_line_diagnostics()<CR>', opts)
buf_set_keymap('n', '[d', '<cmd>lua vim.lsp.diagnostic.goto_prev()<CR>', opts)
buf_set_keymap('n', ']d', '<cmd>lua vim.lsp.diagnostic.goto_next()<CR>', opts)
buf_set_keymap('n', '<Leader>q', '<cmd>lua vim.lsp.diagnostic.set_loclist()<CR>', opts)
buf_set_keymap('n', '<Leader>f', '<cmd>lua vim.lsp.buf.formatting()<CR>', opts)
end
lsp.gopls.setup {
on_attach = on_attach,
}
lsp.hls.setup {
on_attach = on_attach,
root_dir = lsp.util.root_pattern('*.cabal', 'stack.yaml', 'cabal.project', 'package.yaml', 'hie.yaml', '.git'),
}
lsp.pylsp.setup {
on_attach = on_attach,
}
lsp.rnix.setup {
on_attach = on_attach,
}
lsp.rust_analyzer.setup {
on_attach = on_attach,
settings = {
['rust-analyzer'] = {
checkOnSave = {
command = 'clippy',
},
},
},
}
require('trouble').setup {}
-- VimTeX
g.tex_flavor = 'latex'
g.vimtex_view_method = 'zathura'
g.tex_conceal = 'abdmg'
-- this disables some helful warnings that often have a reason why I ignore them
g.vimtex_quickfix_ignore_filters = {
[[Underfull \\hbox (badness [0-9]*) in ]],
[[Overfull \\hbox ([0-9]*.[0-9]*pt too wide) in ]],
[[Overfull \\vbox ([0-9]*.[0-9]*pt too high) detected ]],
[[Package hyperref Warning: Token not allowed in a PDF string]],
[[Package typearea Warning: Bad type area settings!]],
}
-- When using math environments vim does not know if if it currently is in one or outside of one
-- unless it parses the file from the start.
-- Parsing the file from the start each time fixes this
-- but leads to a performance drop (depending on the number of lines).
-- Also, somehow using FileType tex does not work, so this will enable slow syntax highlighting
-- everywhere once a *.tex file is opened.
cmd([[autocmd BufEnter *.tex syntax sync fromstart]])
-- rust.vim
g.rustfmt_autosave_if_config_present = 1
g.rust_fold = 1
noremap('n', '<Leader>rt', ':RustTest<CR>')
-- Markdown
g.vim_markdown_folding_disabled = 1