From a5f2808c5d16e99b5624821b07f8c332bf9339cb Mon Sep 17 00:00:00 2001 From: psychhim Date: Sun, 2 Nov 2025 20:23:29 +0530 Subject: [PATCH] Fix: Save as fix. --- lua/keymaps.lua | 128 ++++++++++++++++++++++++-------- lua/plugins/custom/undotree.lua | 1 + 2 files changed, 96 insertions(+), 33 deletions(-) diff --git a/lua/keymaps.lua b/lua/keymaps.lua index e2bfad9..e88b621 100644 --- a/lua/keymaps.lua +++ b/lua/keymaps.lua @@ -136,6 +136,28 @@ end, { desc = 'New buffer in vertical split (right)' }) -- [[ Save buffer ]] local sudo_password_cache = nil -- store sudo password for session +-- Helper to write file with sudo permissions +local function write_with_sudo(filename, content) + -- Prompt for password once per session + if not sudo_password_cache then + local pass = vim.fn.inputsecret 'sudo password: ' + if pass == '' or pass == nil then + vim.notify('Sudo password required, save cancelled', vim.log.levels.WARN) + return false + end + sudo_password_cache = pass + end + -- Write buffer content to sudo tee + local sudo_cmd = string.format('sudo -S tee %s > /dev/null', vim.fn.fnameescape(filename)) + local ok = vim.fn.system(sudo_cmd, sudo_password_cache .. '\n' .. content) + if vim.v.shell_error ~= 0 then + vim.notify('Failed to write with sudo: ' .. ok, vim.log.levels.ERROR) + -- clear cached password to allow retry next time + sudo_password_cache = nil + return false + end + return true +end local function smart_save(force_save_as) local current_path = vim.api.nvim_buf_get_name(0) -- Compute default input (prefill directory + filename) @@ -150,8 +172,8 @@ local function smart_save(force_save_as) local default_name = current_path ~= '' and vim.fn.fnamemodify(current_path, ':t') or '' local default_input = default_dir .. default_name -- Decide whether to ask for filename - local filename = current_path if current_path == '' or force_save_as then + local filename local overwrite = false while true do -- Ask user for filename @@ -175,42 +197,82 @@ local function smart_save(force_save_as) break -- file doesn't exist, safe to write end end - end - -- Read buffer content - local lines = vim.api.nvim_buf_get_lines(0, 0, -1, true) - local content = table.concat(lines, '\n') - -- Determine if the file is writable - local writable = vim.fn.filereadable(filename) == 1 and vim.fn.filewritable(filename) == 1 - if writable then - -- Normal writable file - if current_path == '' or force_save_as then - vim.cmd('write ' .. vim.fn.fnameescape(filename)) - else - vim.cmd 'write' - end - else - -- File requires sudo - -- Prompt for password once per session - if not sudo_password_cache then - local pass = vim.fn.inputsecret 'sudo password: ' - if pass == '' or pass == nil then - vim.notify('Sudo password required, save cancelled', vim.log.levels.WARN) - return + -- If Save As filename is same as current file, just write and return + if filename == current_path then + local write_cmd = overwrite and 'write!' or 'write' + local ok = pcall(function() + vim.cmd(write_cmd) + end) + if not ok then + local lines = vim.api.nvim_buf_get_lines(0, 0, -1, true) + local content = table.concat(lines, '\n') + if not write_with_sudo(filename, content) then + return + end end - sudo_password_cache = pass - end - -- Write buffer content to sudo tee - local sudo_cmd = string.format('sudo -S tee %s > /dev/null', vim.fn.fnameescape(filename)) - local ok = vim.fn.system(sudo_cmd, sudo_password_cache .. '\n' .. content) - if vim.v.shell_error ~= 0 then - vim.notify('Failed to write with sudo: ' .. ok, vim.log.levels.ERROR) - -- clear cached password to allow retry next time - sudo_password_cache = nil + print('Saved ' .. filename) return end + -- For no-name buffers or Save As, write and set buffer name + if current_path == '' then + -- No-name buffer: set name first + vim.api.nvim_buf_set_name(0, filename) + -- Force overwrite if file exists + local write_cmd = 'write!' + local ok = pcall(function() + vim.cmd(write_cmd) + end) + if not ok then + local lines = vim.api.nvim_buf_get_lines(0, 0, -1, true) + local content = table.concat(lines, '\n') + if not write_with_sudo(filename, content) then + return + end + end + -- Clear modified flag so future saves work correctly + vim.api.nvim_buf_set_option(0, 'modified', false) + else + -- Named buffer: normal Save As logic + local write_cmd = overwrite and 'write!' or 'write' + local ok = pcall(function() + vim.cmd(write_cmd .. ' ' .. vim.fn.fnameescape(filename)) + end) + if not ok then + local lines = vim.api.nvim_buf_get_lines(0, 0, -1, true) + local content = table.concat(lines, '\n') + if not write_with_sudo(filename, content) then + return + end + end + -- Preserve cursor position and undo history + local old_buf = vim.api.nvim_get_current_buf() + local cursor_pos = vim.api.nvim_win_get_cursor(0) + local undo_history = vim.fn.getbufinfo(old_buf)[1].changedtick + -- Open the new file in a fresh buffer + vim.cmd('edit ' .. vim.fn.fnameescape(filename)) + -- Restore cursor + vim.api.nvim_win_set_cursor(0, cursor_pos) + -- Restore undo history + vim.cmd 'undojoin' + -- Delete the old buffer without saving + vim.api.nvim_buf_delete(old_buf, { force = true }) + end + print('Saved as ' .. filename) + else + -- Buffer already has a name, just save it + local ok = pcall(function() + vim.cmd 'w' + end) + if not ok then + local lines = vim.api.nvim_buf_get_lines(0, 0, -1, true) + local content = table.concat(lines, '\n') + if not write_with_sudo(current_path, content) then + return + end + end + vim.api.nvim_buf_set_option(0, 'modified', false) + print('Saved ' .. current_path) end - vim.api.nvim_buf_set_option(0, 'modified', false) - print('Saved ' .. filename) end -- Save current buffer vim.keymap.set('n', 'w', function() diff --git a/lua/plugins/custom/undotree.lua b/lua/plugins/custom/undotree.lua index 6ece1ff..e367ec4 100644 --- a/lua/plugins/custom/undotree.lua +++ b/lua/plugins/custom/undotree.lua @@ -1,5 +1,6 @@ return { 'mbbill/undotree', + lazy = false, keys = { { 'u', vim.cmd.UndotreeToggle, desc = 'Toggle UndoTree' }, },