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" })