inputs: { config, lib, pkgs, ... }: let inherit (inputs.nixvim.legacyPackages.x86_64-linux) makeNixvim; in { options.programs.nixvim = lib.mkOption { type = lib.types.submodule { freeformType = lib.types.anything; config.finalPackage = makeNixvim (builtins.removeAttrs config.programs.nixvim [ "finalPackage" ]); }; }; config.programs.nixvim = { # enable = true; luaLoader.enable = true; globals = { mapleader = ";"; maplocalleader = ","; }; opts = { backup = true; # Use `//` at the end to store the absolute file name backupdir.__raw = "vim.fn.stdpath('data') .. '/backup//'"; colorcolumn = "80"; completeopt = [ "menu" "menuone" "noinsert" "noselect" ]; cursorline = true; diffopt = [ "internal" "filler" "closeoff" "linematch:60" ]; grepprg = "${lib.getExe pkgs.ripgrep} --vimgrep --smart-case"; ignorecase = true; inccommand = "split"; list = true; listchars = { extends = ">"; nbsp = "+"; precedes = "<"; tab = " "; trail = "-"; }; scrolloff = 3; shiftwidth = 4; shortmess = "ncAxoTOtfFli"; showmode = false; sidescrolloff = 5; smartcase = true; smartindent = true; tabstop = 4; title = true; undofile = true; updatetime = 1000; wildmode = [ "longest:full" "full" ]; }; colorschemes.gruvbox = { enable = true; settings = { # bold = true; # italics = true; # underline = true; # undercurl = true; italic.strings = false; overrides = { GitSignsAdd.link = "GruvboxGreenSign"; GitSignsChange.link = "GruvboxOrangeSign"; GitSignsDelete.link = "GruvboxRedSign"; IblScope.link = "GruvboxAqua"; }; }; }; highlight = { TSDefinition.link = "GruvboxBlueSign"; TSDefinitionUsage.link = "GruvboxAquaSign"; }; keymaps = let toggle = key: option: { mode = "n"; key = "yo${key}"; action = "setlocal ${option}! ${option}?"; options.desc = "Toggle ${option}"; }; in [ { key = "fu"; action.__raw = "require('telescope').extensions.undo.undo"; options = { silent = true; desc = "Telescope undo"; }; } { key = "-"; action.__raw = "require('oil').open"; options.desc = "Open parent directory"; } # Git { key = "gg"; action = "Neogit"; options.desc = "Open Neogit"; } { key = "gd"; action = "DiffviewOpen"; options.desc = "Open Diffview"; } # TODO: noremap? buffer local? silent? { key = "gs"; action.__raw = "require('gitsigns').stage_hunk"; options.desc = "Stage hunk"; } { key = "gr"; action.__raw = "require('gitsigns').reset_hunk"; options.desc = "Reset hunk"; } # TODO: visual stage/reset { key = "gS"; action.__raw = "require('gitsigns').stage_buffer"; options.desc = "Stage buffer"; } { key = "gR"; action.__raw = "require('gitsigns').reset_buffer"; options.desc = "Stage buffer"; } { key = "gu"; action.__raw = "require('gitsigns').undo_stage_hunk"; options.desc = "Undo stage hunk"; } { key = "gp"; action.__raw = "require('gitsigns').preview_hunk_inline"; options.desc = "Preview hunk"; } { key = "gb"; action.__raw = "function() require('gitsigns').blame_line { full = true } end"; options.desc = "Blame line"; } { key = "]g"; action.__raw = '' function() if vim.wo.diff then return ']c' end vim.schedule(function() package.loaded.gitsigns.next_hunk() end) return '' end ''; options = { expr = true; desc = "Next hunk"; }; } { key = "[g"; action.__raw = '' function() if vim.wo.diff then return '[c' end vim.schedule(function() package.loaded.gitsigns.prev_hunk() end) return '' end ''; options = { expr = true; desc = "Next hunk"; }; } # Toggle options (toggle "c" "cursorline") (toggle "C" "cursorcolumn") (toggle "h" "hlsearch") (toggle "i" "ignorecase") (toggle "l" "list") (toggle "n" "number") (toggle "r" "relativenumber") (toggle "s" "spell") (toggle "w" "wrap") { mode = "n"; key = "yod"; action.__raw = '' function() if vim.wo.diff then vim.cmd.diffoff() print('diffoff') else vim.cmd.diffthis() print('diffthis') end end ''; options.desc = "Toggle diff"; } ]; # TODO: # extraPlugins = with pkgs.unstable.vimPlugins; [ extraPlugins = with inputs.nixpkgs-unstable.legacyPackages.x86_64-linux.vimPlugins; [ highlight-undo-nvim vim-abolish # TODO: make that modular playground vim-rhubarb fugitive-gitlab-vim vim-polyglot ]; plugins = { cmp = { enable = true; settings = { mapping.__raw = '' cmp.mapping.preset.insert { [''] = cmp.mapping.confirm({ select = false }), [""] = cmp.mapping(function(fallback) local luasnip = require("luasnip") if luasnip.locally_jumpable(1) then luasnip.jump(1) else fallback() end end, { "i", "s" }), [""] = cmp.mapping(function(fallback) local luasnip = require("luasnip") if luasnip.locally_jumpable(-1) then luasnip.jump(-1) else fallback() end end, { "i", "s" }), } ''; snippet.expand = '' function(args) require('luasnip').lsp_expand(args.body) end ''; sources = [ { name = "nvim_lsp"; } { name = "nvim_lsp_signature_help"; } { name = "cmp_pandoc"; } # TODO: make this modular { name = "crates"; } { name = "luasnip"; } { name = "calc"; } { name = "path"; } { name = "treesitter"; } { name = "git"; } { name = "tmux"; } { name = "spell"; } # Use \k for iskeyword because of UTF-8 { name = "buffer"; option.keyword_pattern = ''\k\+''; } ]; }; }; # cmp-buffer.enable = true; # cmp-calc.enable = true; # cmp-cmdline.enable = true; # cmp-git.enable = true; diffview.enable = true; dressing.enable = true; fidget = { enable = true; notification.overrideVimNotify = true; }; fugitive.enable = true; gitignore.enable = true; gitsigns.enable = true; indent-blankline = { enable = true; settings.indent = { char = "│"; tab_char = "│"; }; }; lastplace.enable = true; lualine = { enable = true; iconsEnabled = false; componentSeparators.left = ""; componentSeparators.right = ""; sectionSeparators.left = ""; sectionSeparators.right = ""; }; luasnip.enable = true; mini = { enable = true; modules = { ai.custom_textobjects = { f.__raw = "require('mini.ai').gen_spec.treesitter({ a = '@function.outer', i = '@function.inner' })"; F.__raw = "require('mini.ai').gen_spec.treesitter({ a = '@call.outer', i = '@call.inner' })"; c.__raw = "require('mini.ai').gen_spec.treesitter({ a = '@comment.outer', i = '@comment.inner' })"; b.__raw = "require('mini.ai').gen_spec.treesitter({ a = '@block.outer', i = '@block.inner' })"; a.__raw = "require('mini.ai').gen_spec.treesitter({ a = '@parameter.outer', i = '@parameter.inner' })"; o.__raw = '' require('mini.ai').gen_spec.treesitter({ a = { '@conditional.outer', '@loop.outer' }, i = { '@conditional.inner', '@loop.inner' }, }) ''; }; align = { }; bracketed = { }; clue = { triggers = [ { mode = "n"; keys = "yo"; } { mode = "n"; keys = "["; } { mode = "n"; keys = "]"; } { mode = "n"; keys = ""; } ]; }; surround = { }; trailspace = { }; }; }; neogit = { enable = true; settings = { graph_style = "unicode"; integrations = { diffview = true; telescope = true; }; }; }; none-ls = { enable = true; sources = { code_actions = { gitrebase.enable = true; gitsigns.enable = true; # TODO: maybe? #refactoring.enable = true; statix.enable = true; }; diagnostics = { deadnix.enable = true; statix.enable = true; vale = { enable = true; withArgs = '' { filetypes = { "markdown", "pandoc", "rst", "tex", "asciidoc" }, } ''; }; }; formatting.shfmt.enable = true; }; }; nvim-osc52 = { enable = true; keymaps.enable = true; }; oil.enable = true; # TODO: maybe #refactoring.enable = true; spider = { enable = true; keymaps.motions = { b = "b"; e = "e"; ge = "ge"; w = "w"; }; }; telescope = { enable = true; settings = { }; extensions.undo.enable = true; keymaps = { "fb" = { action = "buffers"; options.desc = "Telescope buffers"; }; "ff" = { action = "find_files"; options.desc = "Telescope find files"; }; "fg" = { action = "live_grep"; options.desc = "Telescope live grep"; }; "fh" = { action = "help_tags"; options.desc = "Telescope help tags"; }; "fo" = { action = "oldfiles"; options.desc = "Telescope old files"; }; "fs" = { action = "spell_suggest"; options.desc = "Telescope spell suggest"; }; "ft" = { action = "treesitter"; options.desc = "Telescope treesitter"; }; "fw" = { action = "git_status"; options.desc = "Telescope git status"; }; }; }; treesitter = { enable = true; indent = true; incrementalSelection.enable = true; nixvimInjections = true; }; treesitter-context = { enable = true; settings = { max_lines = 5; min_window_height = 20; }; }; treesitter-refactor = { enable = true; highlightDefinitions.enable = true; }; treesitter-textobjects = { enable = true; lspInterop = { enable = true; peekDefinitionCode = { "df" = { query = "@function.outer"; desc = "Peek outer function"; }; "dF" = { query = "@class.outer"; desc = "Peek outer class"; }; }; }; }; vim-matchup = { enable = true; treesitterIntegration.enable = true; }; }; extraConfigLuaPost = '' vim.api.nvim_create_autocmd("TextYankPost", { desc = "Highlight yanked text", callback = function() vim.highlight.on_yank() end, }) require('highlight-undo').setup() -- For fugitive's :GBrowse vim.api.nvim_create_user_command("Browse", function(opts) vim.ui.open(opts.args) end, { nargs = 1 }) ''; }; config.environment.systemPackages = [ config.programs.nixvim.finalPackage ]; }