authorgravatar for git@paperclover.netclover caruso <git@paperclover.net> 2025-08-18 00:25:23-07:00
committergravatar for git@paperclover.netclover caruso <git@paperclover.net> 2025-08-18 00:25:32-07:00
log6cb28f1a2d717ec69b30a80d9504702e54721f59
tree152d4664b9a8c0e2f449f9dc8aca8583ee458614
parentce8580e840c9f822335915858ddc02f6da84909d

feat: nix keybind system, delete snacks, add lazygit/fzf

i've had issues with snacks' file tree, to the point where the delete operation would corrupt my editor state. the worst of which being a bug that caused my entire project to get deleted when pressing 'd' on a directory with corrupt state[1]. it's unacceptable, and i no longer trust any of the 'snacks.nvim' project. the neotree plugin is much nicer in my opinion, and what's great about it is there is a easy command list by pressing '?' on the file view. the big part of this commit is introducing 'vim.keybinds' (not to be confused with the existing 'keymaps' array). we now have a centralized system for defining keyboard shortcuts. in theory, user configs can override my default keymap, but i think the current users will appreciate these default settings. theres a handful of built-in keybinds for activating the newly added fzf-lua plugin (replaces telescope and snacks' pickers, losing no functionality). as one bonus treat, leader g g for integrated lazygit! [1]: https://paperclover.dev/clo/sitegen/commit/af60d1172fd981344cfb3c119a68d9b88b0a8dbd

3 files changed, 160 insertions(+), 90 deletions(-)

modules/neovim/default.nix+50-90
......@@ -6,8 +6,9 @@
66}:
77{
88 imports = [
9 ./options.nix
109 ./formatter.nix
10 ./keybind.nix
11 ./options.nix
1112 ];
1213 # based on default options from upstream:
1314 # https://github.com/NotAShelf/nvf/blob/main/configuration.nix
......@@ -18,6 +19,10 @@
1819 # override level 999 is used to not conflict with mkDefault as used by nvf.
1920 # which allows user configurations to disable/override anything here.
2021 config.vim = lib.mkOverride 999 {
22 extraLuaFiles = [
23 ./lib.lua
24 ];
25
2126 theme = {
2227 enable = true;
2328 };
......@@ -60,8 +65,8 @@
6065 listReferences = "gr";
6166 goToType = "gy";
6267 hover = "K";
63 nextDiagnostic = "<leader>d";
64 openDiagnosticFloat = "<leader>df";
68 nextDiagnostic = null; # ]d
69 openDiagnosticFloat = "<leader>d";
6570 renameSymbol = "rn";
6671 documentHighlight = null;
6772 listDocumentSymbols = null;
......@@ -78,11 +83,9 @@
7883 enable = true;
7984 addDefaultGrammars = true;
8085 };
81 debugger = {
82 nvim-dap = {
83 enable = true;
84 ui.enable = true;
85 };
86 debugger.nvim-dap = {
87 enable = true;
88 ui.enable = true;
8689 };
8790 languages = {
8891 enableFormat = true;
......@@ -96,36 +99,58 @@
9699 clang.enable = true;
97100 css.enable = true;
98101 html.enable = true;
102 lua.enable = true;
99103 markdown.enable = true;
104 nix.enable = true;
100105 python.enable = true;
101106 rust.crates.enable = true;
102107 rust.enable = true;
103108 ts.enable = true;
104109 zig.enable = true;
105 lua.enable = true;
106110 # sort-lines: off
107
108 nix = {
109 enable = true;
110 format.type = "nixfmt"; # looks so much nicer
111 };
112111 };
113 filetree = {
114 neo-tree = {
115 enable = false;
112 filetree.neo-tree = {
113 enable = true;
114 setupOpts = {
115 enable_cursor_hijack = true;
116 git_status_async = true;
116117 };
117118 };
118 tabline = {
119 nvimBufferline.enable = true;
119 fzf-lua = {
120 enable = true;
121 setupOpts = {
122 fzf_colors = true;
123 };
120124 };
121 autocomplete = {
122 blink-cmp = {
123 enable = true;
124 sourcePlugins = {
125 ripgrep.enable = true;
125 autocomplete.blink-cmp = {
126 enable = true;
127 mappings = {
128 close = null;
129 complete = null;
130 confirm = null;
131 next = null;
132 previous = null;
133 scrollDocsDown = null;
134 scrollDocsUp = null;
135 };
136 setupOpts = {
137 keymap = {
138 preset = "super-tab";
126139 };
127 friendly-snippets.enable = true;
140 completion = {
141 ghost_text.enabled = false;
142 list.selection.preselect = true;
143 trigger = {
144 show_in_snippet = true;
145 };
146 accept.auto_brackets.enabled = true;
147 };
148 signature.enabled = true;
128149 };
150 sourcePlugins = {
151 ripgrep.enable = true;
152 };
153 friendly-snippets.enable = true;
129154 };
130155 statusline = {
131156 lualine = {
......@@ -137,71 +162,6 @@
137162 };
138163 };
139164 };
140
141 utility = {
142 snacks-nvim = {
143 enable = true;
144 setupOpts = {
145 bigfile.enable = true;
146 dashboard = {
147 preset.keys = [
148 {
149 icon = " ";
150 key = "n";
151 desc = "New File";
152 action = ":ene | startinsert";
153 }
154 {
155 icon = " ";
156 key = "r";
157 desc = "Recent Files";
158 action = ":lua Snacks.dashboard.pick('oldfiles')";
159 }
160 ];
161 sections = [
162 { section = "header"; }
163 {
164 section = "keys";
165 indent = 2;
166 padding = 1;
167 }
168 {
169 icon = " ";
170 title = "Projects";
171 section = "projects";
172 indent = 2;
173 padding = 1;
174 }
175 {
176 icon = " ";
177 title = "Git";
178 section = "terminal";
179 enabled = lib.options.literalExpression ''
180 function()
181 return Snacks.git.get_root() ~= nil
182 end
183 '';
184 cmd = "git status --short --branch --renames";
185 height = 10;
186 padding = 1;
187 ttl = 5 * 60;
188 indent = 3;
189 }
190 ];
191 };
192 image = {
193 enable = true;
194 math.enabled = false;
195 };
196 notifier.timeout = 3000;
197 picker = {
198 enable = true;
199 sources = {
200 };
201 };
202 };
203 };
204 };
205165 binds = {
206166 whichKey.enable = true;
207167 cheatsheet.enable = true;
modules/neovim/keybind.nix created+83
......@@ -0,0 +1,83 @@
1# this file implements a keybind system, which is a higher level system
2# to configure vim.keymaps (note the different name bind vs map)
3{
4 pkgs,
5 lib,
6 config,
7 ...
8}:
9let
10 keyRemap = mode: key: action: { inherit mode key action; };
11 keyCmd =
12 mode: key: cmd:
13 keyRemap mode key ":${cmd}<Return>";
14in
15{
16 # default binds
17 config.vim.keybinds = {
18 search-commands = keyCmd "n" "<leader>?" "FzfLua keymaps";
19
20 # user interface
21 toggle-explorer = keyCmd "n" "<leader>e" "Neotree toggle";
22 reveal-active-file = keyCmd "n" "<leader>E" "Neotree reveal<CR>:Neotree focus";
23 lazygit = keyCmd "n" "<leader>gg" "FullscreenTerm ${pkgs.lazygit}/bin/lazygit";
24
25 # pickers
26 pick-file = keyCmd "n" "<leader><leader>" "FzfLua files";
27 pick-mark = keyCmd "n" "<leader>'" "FzfLua marks";
28 #pick-buffer = keyCmd "n" "<leader>b" "FzfLua buffers";
29 pick-grep = keyCmd "n" "<leader>ff" "FzfLua grep_project";
30 pick-recent-command = keyCmd "n" "<leader>fc" "FzfLua command_history";
31 pick-other = keyCmd "n" "<leader>f?" "FzfLua builtin"; # picker of Fzf pickers
32
33 # lsp
34 code-action =
35 keyCmd "n" "<leader>ca"
36 "FzfLua lsp_code_actions winopts.height=15 winopts.backdrop=100 winopts.title=false winopts.preview.title=false winopts.row=1";
37
38 # subtle nice features
39 visual-dedent = keyRemap "v" "<" "<gv"; # keep selection
40 visual-indent = keyRemap "v" ">" ">gv"; # keep selection
41 clear-search-highlights = keyRemap "n" "<esc" ":noh<Return><esc>";
42 };
43
44 # implementation
45 options.vim.keybinds = lib.mkOption {
46 type = lib.types.attrsOf (
47 lib.types.nullOr (
48 lib.types.submodule {
49 options = {
50 mode = lib.mkOption { type = lib.types.str; };
51 key = lib.mkOption { type = lib.types.str; };
52 action = lib.mkOption { type = lib.types.str; };
53 };
54 }
55 )
56 );
57 default = { };
58 };
59 config.vim.keymaps =
60 let
61 titleCase =
62 str:
63 lib.concatStringsSep " " (
64 map (
65 word:
66 lib.strings.toUpper (builtins.substring 0 1 word)
67 + builtins.substring 1 (builtins.stringLength word) word
68 ) (lib.splitString "-" str)
69 );
70 in
71 builtins.filter (f: f != null) (
72 lib.attrsets.mapAttrsToList (
73 desc: bind:
74 if bind != null then
75 {
76 desc = titleCase desc;
77 inherit (bind) mode key action;
78 }
79 else
80 null
81 ) config.vim.keybinds
82 );
83}
modules/neovim/lib.lua created+27
......@@ -0,0 +1,27 @@
1-- Ported from https://www.reddit.com/r/neovim/comments/vemydn
2vim.api.nvim_create_user_command("FullscreenTerm", function(opts)
3 vim.cmd("tab terminal " .. opts.args)
4 local laststatus = vim.o.laststatus
5 local showtabline = vim.o.showtabline
6 local cmdheight = vim.o.cmdheight
7 vim.o.laststatus = 0
8 vim.o.cmdheight = 0
9 vim.o.showtabline = 0
10 vim.wo.signcolumn = "no"
11 vim.wo.relativenumber = false
12 vim.wo.number = false
13 vim.cmd(
14 "autocmd! TermClose <buffer=abuf> "
15 .. "if !v:event.status"
16 .. " | exec 'bd! '..expand('<abuf>')"
17 .. " | endif"
18 .. " | checktime"
19 .. " | set laststatus="
20 .. laststatus
21 .. " | set cmdheight="
22 .. cmdheight
23 .. " | set showtabline="
24 .. showtabline
25 )
26 vim.cmd("startinsert")
27end, { nargs = "*" })