From b34edc3a519a0efebb9f39e24b0998d98309c99c Mon Sep 17 00:00:00 2001 From: chloe caruso Date: Thu, 21 Aug 2025 01:57:32 -0700 Subject: [PATCH] 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. --- .../{lib.lua => commands/FullscreenTerm.lua} | 0 modules/neovim/commands/SmartQuit.lua | 96 +++++++++++++++++++ modules/neovim/default.nix | 18 +++- modules/neovim/keybind.nix | 1 + users/clover/vim.nix | 30 +++--- users/natalie/vim/languages.nix | 1 + 6 files changed, 130 insertions(+), 16 deletions(-) rename modules/neovim/{lib.lua => commands/FullscreenTerm.lua} (100%) create mode 100644 modules/neovim/commands/SmartQuit.lua diff --git a/modules/neovim/lib.lua b/modules/neovim/commands/FullscreenTerm.lua similarity index 100% rename from modules/neovim/lib.lua rename to modules/neovim/commands/FullscreenTerm.lua diff --git a/modules/neovim/commands/SmartQuit.lua b/modules/neovim/commands/SmartQuit.lua new file mode 100644 index 0000000..f6647d5 --- /dev/null +++ b/modules/neovim/commands/SmartQuit.lua @@ -0,0 +1,96 @@ +vim.api.nvim_create_user_command("SmartQuit", function(opts) + -- scan all buffers for unsaved buffers + local unsaved = {} + local saved = {} + for _, buf in ipairs(vim.api.nvim_list_bufs()) do + if vim.api.nvim_buf_is_loaded(buf) and vim.api.nvim_buf_get_option(buf, "buflisted") then + if vim.api.nvim_buf_get_option(buf, "modified") then + table.insert(unsaved, buf) + else + table.insert(saved, buf) + end + end + end + + if #unsaved == 0 then + vim.cmd("qa") + return + end + + -- gui for resolving unsaved files + local lines = {} + for _, buf in ipairs(unsaved) do + local full_path = vim.api.nvim_buf_get_name(buf) + local name = full_path == "" and ("[No Name] #" .. buf) or vim.fn.fnamemodify(full_path, ":~:.") + table.insert(lines, " • " .. name) + end + table.insert(lines, "") + table.insert(lines, " s - Save all and quit") + table.insert(lines, " c - Close saved; leave unsaved open") + table.insert(lines, " d - DISCARD ALL") + + local buf = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines) + vim.api.nvim_buf_set_option(buf, "readonly", true) + local width = math.max(unpack(vim.tbl_map(function(l) return #l end, lines))) + local height = #lines + local win = vim.api.nvim_open_win(buf, true, { + relative = "editor", + width = width + 1, + height = height, + row = (vim.o.lines - height) / 2 - 1, + col = (vim.o.columns - width) / 2, + style = "minimal", + border = "rounded", + title = { + { #unsaved .. " Unsaved Buffer" .. (#unsaved != 1 and "s" or "") .. "!", "ErrorMsg" }, + }, + title_pos = "center", + }) + + vim.wo[win].winhighlight = "Normal:Normal,FloatBorder:ErrorMsg" + vim.api.nvim_win_set_option(win, "cursorline", false) + + local hl = vim.api.nvim_get_hl_by_name('Cursor', true) + hl.blend = 100 + vim.api.nvim_set_hl(0, 'Cursor', hl) + vim.opt.guicursor:append('a:Cursor/lCursor') + + function close() + local hl = vim.api.nvim_get_hl_by_name('Cursor', true) + hl.blend = 0 + vim.api.nvim_set_hl(0, 'Cursor', hl) + vim.opt.guicursor:remove('a:Cursor/lCursor') + vim.api.nvim_win_close(win, true) + end + + -- keyboard event handlers + vim.keymap.set("n", "s", function() + for _, buf in ipairs(unsaved) do + vim.api.nvim_buf_call(buf, function() + vim.cmd("write") + end) + end + close() + vim.cmd("qa") + end, { buffer = buf }) + vim.keymap.set("n", "c", function() + for _, buf in ipairs(saved) do + vim.api.nvim_buf_delete(buf, {}) + end + close() + end, { buffer = buf }) + vim.keymap.set("n", "d", function() + vim.cmd("qa!") + end, { buffer = buf }) + vim.keymap.set("n", "", function() + close() + end, { buffer = buf }) + + vim.api.nvim_create_autocmd({ 'WinLeave' }, { + buffer = buf, + callback = close, + }) +end, { nargs = 0 }) + +vim.api.nvim_set_hl(0, "QuitPopUpBorder", { fg = "red" }) diff --git a/modules/neovim/default.nix b/modules/neovim/default.nix index 446fe23..c436602 100644 --- a/modules/neovim/default.nix +++ b/modules/neovim/default.nix @@ -20,7 +20,8 @@ # which allows user configurations to disable/override anything here. config.vim = lib.mkOverride 999 { extraLuaFiles = [ - ./lib.lua + ./commands/FullscreenTerm.lua + ./commands/SmartQuit.lua ]; theme = { @@ -57,7 +58,7 @@ lspkind.enable = config.vim.autocomplete.blink-cmp.enable; # Enables inlay hints (types info in rust and shit) inlayHints.enable = true; - #Nice mappings that i use :3 + # Nice mappings that I use :3 mappings = { codeAction = "ca"; goToDeclaration = "gD"; @@ -114,6 +115,19 @@ setupOpts = { enable_cursor_hijack = true; git_status_async = true; + close_if_last_window = true; + filesystem.filtered_items = { + # dotfiles are often used for project configuration + hide_dotfiles = false; + never_show = [ + ".DS_Store" # macOS + "thumbs.db" # Windows + ]; + never_show_by_pattern = [ + ".*.swp" + "._*" # macOS + ]; + }; }; }; fzf-lua = { diff --git a/modules/neovim/keybind.nix b/modules/neovim/keybind.nix index 42732a6..2b4a4d2 100644 --- a/modules/neovim/keybind.nix +++ b/modules/neovim/keybind.nix @@ -21,6 +21,7 @@ in toggle-explorer = keyCmd "n" "e" "Neotree toggle"; reveal-active-file = keyCmd "n" "E" "Neotree reveal:Neotree focus"; lazygit = keyCmd "n" "gg" "FullscreenTerm ${pkgs.lazygit}/bin/lazygit"; + smart-quit = keyCmd "n" "q" "SmartQuit"; # pickers pick-file = keyCmd "n" "" "FzfLua files"; diff --git a/users/clover/vim.nix b/users/clover/vim.nix index 84bac23..9ada4b1 100644 --- a/users/clover/vim.nix +++ b/users/clover/vim.nix @@ -1,20 +1,22 @@ _: { vim = { - options = { - linebreak = true; - }; - git = { - gitsigns.setupOpts = { - current_line_blame = false; - current_line_blame_opts = { - virt_text = true; - virt_text_pos = "right_align"; - delay = 25; - ignore_whitespace = true; - virt_text_priority = 100; - use_focus = true; - }; + languages.lua.enable = false; # broken + options.linebreak = true; + git.gitsigns.setupOpts = { + current_line_blame = false; + current_line_blame_opts = { + virt_text = true; + virt_text_pos = "right_align"; + delay = 25; + ignore_whitespace = true; + virt_text_priority = 100; + use_focus = true; }; }; + # filetree.neo-tree.setupOpts.default_component_configs.indent = { + # padding = 0; + # indent_marker = "|"; + # last_indent_marker = "+"; + # }; }; } diff --git a/users/natalie/vim/languages.nix b/users/natalie/vim/languages.nix index 9c447ed..6c37085 100644 --- a/users/natalie/vim/languages.nix +++ b/users/natalie/vim/languages.nix @@ -11,6 +11,7 @@ python312Packages.pylatexenc ]; languages = { + lua.lsp.enable = true; lua.lsp.lazydev.enable = true; python = { format.type = "ruff";