local api = vim.api local N_ = vim.fn.gettext local M = {} --- Renders a swap file as a multi-line block: --- ``` --- %home%foo%bar%README.md.swl --- dated: Thu Apr 23 17:25:52 2026 --- file name: ~foo/bar/README.md --- modified: no --- user name: justin host name: minime --- process ID: 10521 (STILL RUNNING) --- ``` --- @param path string --- @return string local function format_swap(path) local info = vim.fn.swapinfo(path) local mtime = info.mtime and vim.fn.strftime('%a %b %d %H:%M:%S %Y', info.mtime) or '?' local lines = { vim.fs.basename(path), (' dated: %s'):format(mtime), } if info.error then lines[#lines + 1] = (' [%s]'):format(info.error) else lines[#lines + 1] = (' file name: %s'):format( info.fname == '' and '[No Name]' or info.fname ) lines[#lines + 1] = (' modified: %s'):format(info.dirty == 1 and 'YES' or 'no') if info.user ~= '' or info.host ~= '' then local parts = {} ---@type string[] if info.user ~= '' then parts[#parts + 1] = ('user name: %s'):format(info.user) end if info.host ~= '' then parts[#parts + 1] = ('host name: %s'):format(info.host) end lines[#lines + 1] = (' %s'):format(table.concat(parts, ' ')) end if info.pid > 0 then lines[#lines + 1] = (' process ID: %d (STILL RUNNING)'):format(info.pid) end end return table.concat(lines, '\n') end --- Implements `:recover` (when there are multiple swap files): let the user pick via vim.ui.select(). --- --- async: returns immediately, then schedules `:recover {path}` on the chosen swapfile. --- --- @param items string[] List of swapfile paths. function M.select_swap(items) vim.ui.select(items, { prompt = N_('Select a swapfile:'), kind = 'swap', format_item = format_swap, }, function(_, idx) if not idx then return end -- Queue ":recover! " as user input, so the recursive recovery runs via the normal -- input-dispatch loop. Using vim.schedule + vim.cmd can hang bc of "Press ENTER". vim.fn.feedkeys( vim.keycode(('recover! %s'):format(vim.fn.fnameescape(assert(items[idx])))), 'in' ) end) end --- Implements `nvim -r` (no arg): list every swapfile found in 'directory'. --- --- @param items string[] List of swapfile paths. function M.list_swaps(items) local lines = { { N_('Swap files found:') .. '\n' } } ---@type [string][] if #items == 0 then lines[#lines + 1] = { ' ' .. N_('-- none --') } else for i, path in ipairs(items) do lines[#lines + 1] = { ('%d. %s\n'):format(i, format_swap(path)) } end end api.nvim_echo(lines, false) end return M