{ config, lib, pkgs, ... }: with lib; { options = { neovim = { tabWidth = mkOption { type = types.int; description = "Width of tabes in the editor."; default = 4; }; expandTab = mkOption { type = types.bool; description = "If tabs should be expanded to spaces."; default = false; }; keys = { leader = mkOption { type = types.str; description = "NeoVIM leader key"; default = " "; }; noh = mkOption { type = types.str; description = "Keybind to remove active hilighted content."; default = "<leader>h"; }; menus = { # file browser browser = mkOption { type = types.str; description = "Keybind to open file browser."; default = "<leader>e"; }; # active buffers buffers = mkOption { type = types.str; description = "Keybind to show active buffers."; default = "<leader>fb"; }; # error list error = mkOption { type = types.str; description = "Keybind to show LSP errors."; default = "<leader>t"; }; # find files find = mkOption { type = types.str; description = "Keybind to search files in working directory."; default = "<leader>ff"; }; # grep files grep = mkOption { type = types.str; description = "Keybind to grep files in working directory."; default = "<leader>fg"; }; # help menu help = mkOption { type = types.str; description = "Keybind to search help menus."; default = "<leader>fh"; }; # undo tree undo = mkOption { type = types.str; description = "Keybind to view undo tree."; default = "<leader>u"; }; }; # lsp actions lsp = { hover = mkOption { type = types.str; description = "Keybind to open LSP hover menu on a value."; default = "K"; }; action = mkOption { type = types.str; description = "Keybind to perform an LSP action on a value."; default = "<leader>la"; }; references = mkOption { type = types.str; description = "Keybind to view all references of a value."; default = "<leader>lr"; }; rename = mkOption { type = types.str; description = "Keybind to rename currrent and all references of a value."; default = "<leader>ln"; }; }; # completion cmp = { prev = mkOption { type = types.str; description = "Keybind to select previous value in completion engine."; default = "<C-p>"; }; next = mkOption { type = types.str; description = "Keybind to select next value in completion engine."; default = "<C-n>"; }; confirm = mkOption { type = types.str; description = "Keybind to confirm current value in completion engine."; default = "<CR>"; }; complete = mkOption { type = types.str; description = "Keybind to auto complete using completion engine."; default = "<C-space>"; }; }; }; # active lsp servers lsps = mkOption { type = with types; listOf str; description = "List of lsp servers to load"; default = ["clangd" "rust_analyzer"]; }; }; }; config = { environment.variables.EDITOR = "nvim"; home-manager.users.${config.user} = { programs.neovim = { enable = true; viAlias = true; vimAlias = true; extraLuaConfig = '' --[[ VIM ]]-- vim.opt.tabstop = ${toString config.neovim.tabWidth} vim.opt.softtabstop = ${toString config.neovim.tabWidth} vim.opt.shiftwidth = ${toString config.neovim.tabWidth} vim.opt.expandtab = ${boolToString config.neovim.expandTab} vim.opt.mouse = "a" vim.opt.clipboard = "unnamedplus" vim.opt.hlsearch = true vim.opt.autoindent = true vim.opt.ttyfast = true vim.opt.number = true vim.opt.relativenumber = true vim.opt.rnu = true vim.opt.swapfile = false --[[ BUF ]]-- -- remove trailing whitespace on save vim.api.nvim_create_autocmd({ "BufWritePre" }, { pattern = { "*" }, command = [[%s/\s\+$//e]], }) --[[ KEYBINDS ]]-- -- leader vim.g.mapleader = "${config.neovim.keys.leader}" vim.g.maplocalleader = "${config.neovim.keys.leader}" vim.keymap.set("", '<leader>', '<Nop>', { noremap = true, silent = true }) -- bind helper function local function bind(key, action, opts) opts = opts or {} vim.keymap.set('n', key, action, opts) end -- lsp bind("${config.neovim.keys.noh}", vim.cmd.noh) vim.api.nvim_create_autocmd('LspAttach', { desc = 'LSP actions', callback = function(event) local opts = {buffer = event.buf} bind("${config.neovim.keys.lsp.hover}", function() vim.lsp.buf.hover() end, opts) bind("${config.neovim.keys.lsp.action}", function() vim.lsp.buf.code_action() end, opts) bind("${config.neovim.keys.lsp.references}", function() vim.lsp.buf.references() end, opts) bind("${config.neovim.keys.lsp.rename}", function() vim.lsp.buf.rename() end, opts) end }) ''; plugins = with pkgs.vimPlugins; [ # Deoendencies vim-devicons nvim-web-devicons plenary-nvim # Colorscheme { plugin = base16-nvim; type = "lua"; config = '' vim.opt.termguicolors = true vim.g.base16_transparent_background = 1 local colorscheme = require('base16-colorscheme') colorscheme.setup({ base00 = '#${config.theme.colors.base00}', base01 = '#${config.theme.colors.base01}', base02 = '#${config.theme.colors.base02}', base03 = '#${config.theme.colors.base03}', base04 = '#${config.theme.colors.base04}', base05 = '#${config.theme.colors.base05}', base06 = '#${config.theme.colors.base06}', base07 = '#${config.theme.colors.base07}', base08 = '#${config.theme.colors.base08}', base09 = '#${config.theme.colors.base09}', base0A = '#${config.theme.colors.base0A}', base0B = '#${config.theme.colors.base0B}', base0C = '#${config.theme.colors.base0C}', base0D = '#${config.theme.colors.base0D}', base0E = '#${config.theme.colors.base0E}', base0F = '#${config.theme.colors.base0F}', }) -- make transparent background vim.api.nvim_set_hl(0, "Normal", { bg = "none" }) vim.api.nvim_set_hl(0, "NormalFloat", { bg = "none" }) vim.api.nvim_set_hl(0, 'EndOfBuffer', { bg = "none" }) -- identifiers should not be colored vim.api.nvim_set_hl(0, "Identifier", { fg = "#${config.theme.colors.base05}" }) vim.api.nvim_set_hl(0, "TSVariable", { fg = "#${config.theme.colors.base05}" }) -- macro should be colored as a keyword vim.api.nvim_set_hl(0, "TSFuncMacro", { fg = "#${config.theme.colors.base0E}" }) -- comments are too dark vim.api.nvim_set_hl(0, "Comment", { fg = "#${config.theme.colors.base07}" }) vim.api.nvim_set_hl(0, "@comment", { link = "Comment" }) ''; } # Mode line { plugin = lualine-nvim; type = "lua"; config = '' require('lualine').setup { options = { theme = 'base16', icons_enabled = true, globalstatus = true, }, }; ''; } # Buffer line { plugin = bufferline-nvim; type = "lua"; config = '' require('bufferline').setup {} ''; } # File browser { plugin = nvim-tree-lua; type = "lua"; config = '' vim.g.loaded_netrw = 1 vim.g.loaded_netrwPlugin = 1 require('nvim-tree').setup { sort = { sorter = "case_sensitive", }, view = { centralize_selection = true, signcolumn = "yes", float = { enable = true, quit_on_focus_loss = true, open_win_config = { relative = "editor", border = "rounded", width = 60, height = 20, row = 1, col = 1, }, }; }, renderer = { group_empty = true, }, actions = { use_system_clipboard = true, change_dir = { enable = true, global = false, restrict_above_cwd = false, }, expand_all = { max_folder_discovery = 300, exclude = {}, }, file_popup = { open_win_config = { col = 1, row = 1, relative = "cursor", border = "shadow", style = "minimal", }, }, open_file = { quit_on_open = true, window_picker = { enable = false, picker = "default", chars = "abcdefghijklmnopqrstuvwxyz1234567890", exclude = { filetype = { "notify", "lazy", "qf", "diff", "fugitive", "fugitiveblame" }, buftype = { "nofile", "terminal", "help" }, }, } }, remove_file = { close_window = true, }, }, filters = { dotfiles = false, }, tab = { sync = { open = false, close = false, ignore = {}, }, }, git = { enable = false, }, update_cwd = true, respect_buf_cwd = true, update_focused_file = { enable = true, update_cwd = true }, }; bind("${config.neovim.keys.menus.browser}", vim.cmd.NvimTreeToggle) ''; } # Undo tree { plugin = undotree; type = "lua"; config = '' bind("${config.neovim.keys.menus.undo}", vim.cmd.UndotreeToggle) ''; } # Trouble (error menu) { plugin = trouble-nvim; type = "lua"; config = '' bind("${config.neovim.keys.menus.error}", function() require('trouble').toggle() end) ''; } # Telescope (buffers/find/grep/help) { plugin = telescope-nvim; type = "lua"; config = '' local telescope = require('telescope.builtin') bind("${config.neovim.keys.menus.buffers}", telescope.buffers) bind("${config.neovim.keys.menus.find}", telescope.find_files) bind("${config.neovim.keys.menus.grep}", telescope.live_grep) bind("${config.neovim.keys.menus.help}", telescope.help_tags) vim.api.nvim_set_hl(0, 'TelescopeNormal', { bg = "none" }) vim.api.nvim_set_hl(0, 'TelescopeBorder', { bg = "none" }) vim.api.nvim_set_hl(0, 'TelescopeResultsTitle', { bg = "none" }) vim.api.nvim_set_hl(0, 'TelescopePromptTitle', { bg = "none" }) vim.api.nvim_set_hl(0, 'TelescopePreviewTitle', { bg = "none" }) vim.api.nvim_set_hl(0, 'TelescopePromptNormal', { bg = "none" }) vim.api.nvim_set_hl(0, 'TelescopePromptBorder', { bg = "none" }) ''; } # Snippets vim-vsnip vim-vsnip-integ friendly-snippets # Completion cmp-buffer cmp-nvim-lsp cmp-vsnip { plugin = nvim-cmp; type = "lua"; config = '' local cmp = require('cmp'); local cmp_select = {behavior = cmp.SelectBehavior.select} local cmp_mappings = cmp.mapping.preset.insert({ ["${config.neovim.keys.cmp.prev}"] = cmp.mapping.select_prev_item(cmp_select), ["${config.neovim.keys.cmp.next}"] = cmp.mapping.select_next_item(cmp_select), ["${config.neovim.keys.cmp.confirm}"] = cmp.mapping.confirm({ select = true }), ["${config.neovim.keys.cmp.complete}"] = cmp.mapping.complete(), }) cmp_mappings['<Tab>'] = nil cmp_mappings['<S-Tab>'] = nil cmp.setup { snippet = { expand = function(args) vim.fn["vsnip#anonymous"](args.body) end, }, sources = cmp.config.sources { { name = 'nvim_lsp' }, { name = 'vsnip' }, { name = 'buffer' }, }, mapping = cmp_mappings, } ''; } # Sourround delimiters { plugin = nvim-surround; type = "lua"; config = '' require('nvim-surround').setup {} ''; } # Comment functions nerdcommenter # Treesitter nvim-treesitter.withAllGrammars # Syntax hilighting { plugin = vim-illuminate; type = "lua"; config = '' require('illuminate').configure { providers = { 'lsp', 'treesitter', 'regex', }, } ''; } # Todo comments { plugin = todo-comments-nvim; type = "lua"; config = '' require('todo-comments').setup() ''; } # Lsp server { plugin = nvim-lspconfig; type = "lua"; config = let lspConfigs = map (server: '' lspconfig["${server}"].setup({ capabilities = capabilities }) '') config.neovim.lsps; in '' local lspconfig = require('lspconfig') local capabilities = require'cmp_nvim_lsp'.default_capabilities() ${lib.concatStrings lspConfigs} ''; } # Notifications { plugin = fidget-nvim; type = "lua"; config = '' require("fidget").setup { notification = { window = { winblend = 0, }, }, } ''; } # Auto indentation { plugin = indent-o-matic; type = "lua"; config = '' require('indent-o-matic').setup { max_lines = 2048, standard_widths = { 2, 4, 8 }, skip_multiline = true, }; ''; } # 80 column width { plugin = virt-column-nvim; type = "lua"; config = '' require('virt-column').setup { enabled = true, virtcolumn = "80" } ''; } ]; }; }; }; }