authorgravatar for git@paperclover.netclover caruso <git@paperclover.net> 2025-08-21 01:57:32-07:00
committergravatar for git@paperclover.netclover caruso <git@paperclover.net> 2025-08-21 01:57:32-07:00
logb34edc3a519a0efebb9f39e24b0998d98309c99c
tree55e78e2f38ff331eb94991423d51dcd58e92d6df
parent1052a1ccc3d91a32648090733bef9d1ae6819c55

feat(vim): Smart quit popup

space q will close the application if all buffers are saved, otherwise a dialog box shows up with the buffers that are not saved.

7 files changed, 157 insertions(+), 43 deletions(-)

modules/neovim/commands/FullscreenTerm.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 = "*" })
modules/neovim/commands/SmartQuit.lua created+96
......@@ -0,0 +1,96 @@
1vim.api.nvim_create_user_command("SmartQuit", function(opts)
2 -- scan all buffers for unsaved buffers
3 local unsaved = {}
4 local saved = {}
5 for _, buf in ipairs(vim.api.nvim_list_bufs()) do
6 if vim.api.nvim_buf_is_loaded(buf) and vim.api.nvim_buf_get_option(buf, "buflisted") then
7 if vim.api.nvim_buf_get_option(buf, "modified") then
8 table.insert(unsaved, buf)
9 else
10 table.insert(saved, buf)
11 end
12 end
13 end
14
15 if #unsaved == 0 then
16 vim.cmd("qa")
17 return
18 end
19
20 -- gui for resolving unsaved files
21 local lines = {}
22 for _, buf in ipairs(unsaved) do
23 local full_path = vim.api.nvim_buf_get_name(buf)
24 local name = full_path == "" and ("[No Name] #" .. buf) or vim.fn.fnamemodify(full_path, ":~:.")
25 table.insert(lines, " • " .. name)
26 end
27 table.insert(lines, "")
28 table.insert(lines, " s - Save all and quit")
29 table.insert(lines, " c - Close saved; leave unsaved open")
30 table.insert(lines, " d - DISCARD ALL")
31
32 local buf = vim.api.nvim_create_buf(false, true)
33 vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines)
34 vim.api.nvim_buf_set_option(buf, "readonly", true)
35 local width = math.max(unpack(vim.tbl_map(function(l) return #l end, lines)))
36 local height = #lines
37 local win = vim.api.nvim_open_win(buf, true, {
38 relative = "editor",
39 width = width + 1,
40 height = height,
41 row = (vim.o.lines - height) / 2 - 1,
42 col = (vim.o.columns - width) / 2,
43 style = "minimal",
44 border = "rounded",
45 title = {
46 { #unsaved .. " Unsaved Buffer" .. (#unsaved != 1 and "s" or "") .. "!", "ErrorMsg" },
47 },
48 title_pos = "center",
49 })
50
51 vim.wo[win].winhighlight = "Normal:Normal,FloatBorder:ErrorMsg"
52 vim.api.nvim_win_set_option(win, "cursorline", false)
53
54 local hl = vim.api.nvim_get_hl_by_name('Cursor', true)
55 hl.blend = 100
56 vim.api.nvim_set_hl(0, 'Cursor', hl)
57 vim.opt.guicursor:append('a:Cursor/lCursor')
58
59 function close()
60 local hl = vim.api.nvim_get_hl_by_name('Cursor', true)
61 hl.blend = 0
62 vim.api.nvim_set_hl(0, 'Cursor', hl)
63 vim.opt.guicursor:remove('a:Cursor/lCursor')
64 vim.api.nvim_win_close(win, true)
65 end
66
67 -- keyboard event handlers
68 vim.keymap.set("n", "s", function()
69 for _, buf in ipairs(unsaved) do
70 vim.api.nvim_buf_call(buf, function()
71 vim.cmd("write")
72 end)
73 end
74 close()
75 vim.cmd("qa")
76 end, { buffer = buf })
77 vim.keymap.set("n", "c", function()
78 for _, buf in ipairs(saved) do
79 vim.api.nvim_buf_delete(buf, {})
80 end
81 close()
82 end, { buffer = buf })
83 vim.keymap.set("n", "d", function()
84 vim.cmd("qa!")
85 end, { buffer = buf })
86 vim.keymap.set("n", "<esc>", function()
87 close()
88 end, { buffer = buf })
89
90 vim.api.nvim_create_autocmd({ 'WinLeave' }, {
91 buffer = buf,
92 callback = close,
93 })
94end, { nargs = 0 })
95
96vim.api.nvim_set_hl(0, "QuitPopUpBorder", { fg = "red" })
modules/neovim/default.nix+16-2
......@@ -20,7 +20,8 @@
2020 # which allows user configurations to disable/override anything here.
2121 config.vim = lib.mkOverride 999 {
2222 extraLuaFiles = [
23 ./lib.lua
23 ./commands/FullscreenTerm.lua
24 ./commands/SmartQuit.lua
2425 ];
2526
2627 theme = {
......@@ -57,7 +58,7 @@
5758 lspkind.enable = config.vim.autocomplete.blink-cmp.enable;
5859 # Enables inlay hints (types info in rust and shit)
5960 inlayHints.enable = true;
60 #Nice mappings that i use :3
61 # Nice mappings that I use :3
6162 mappings = {
6263 codeAction = "<leader>ca";
6364 goToDeclaration = "gD";
......@@ -114,6 +115,19 @@
114115 setupOpts = {
115116 enable_cursor_hijack = true;
116117 git_status_async = true;
118 close_if_last_window = true;
119 filesystem.filtered_items = {
120 # dotfiles are often used for project configuration
121 hide_dotfiles = false;
122 never_show = [
123 ".DS_Store" # macOS
124 "thumbs.db" # Windows
125 ];
126 never_show_by_pattern = [
127 ".*.swp"
128 "._*" # macOS
129 ];
130 };
117131 };
118132 };
119133 fzf-lua = {
modules/neovim/keybind.nix+1
......@@ -21,6 +21,7 @@ in
2121 toggle-explorer = keyCmd "n" "<leader>e" "Neotree toggle";
2222 reveal-active-file = keyCmd "n" "<leader>E" "Neotree reveal<CR>:Neotree focus";
2323 lazygit = keyCmd "n" "<leader>gg" "FullscreenTerm ${pkgs.lazygit}/bin/lazygit";
24 smart-quit = keyCmd "n" "<leader>q" "SmartQuit";
2425
2526 # pickers
2627 pick-file = keyCmd "n" "<leader><leader>" "FzfLua files";
modules/neovim/lib.lua deleted-27
......@@ -1,27 +0,0 @@
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 = "*" })
users/clover/vim.nix+16-14
......@@ -1,20 +1,22 @@
11_: {
22 vim = {
3 options = {
4 linebreak = true;
5 };
6 git = {
7 gitsigns.setupOpts = {
8 current_line_blame = false;
9 current_line_blame_opts = {
10 virt_text = true;
11 virt_text_pos = "right_align";
12 delay = 25;
13 ignore_whitespace = true;
14 virt_text_priority = 100;
15 use_focus = true;
16 };
3 languages.lua.enable = false; # broken
4 options.linebreak = true;
5 git.gitsigns.setupOpts = {
6 current_line_blame = false;
7 current_line_blame_opts = {
8 virt_text = true;
9 virt_text_pos = "right_align";
10 delay = 25;
11 ignore_whitespace = true;
12 virt_text_priority = 100;
13 use_focus = true;
1714 };
1815 };
16 # filetree.neo-tree.setupOpts.default_component_configs.indent = {
17 # padding = 0;
18 # indent_marker = "|";
19 # last_indent_marker = "+";
20 # };
1921 };
2022}
users/natalie/vim/languages.nix+1
......@@ -11,6 +11,7 @@
1111 python312Packages.pylatexenc
1212 ];
1313 languages = {
14 lua.lsp.enable = true;
1415 lua.lsp.lazydev.enable = true;
1516 python = {
1617 format.type = "ruff";