feat(:restart)!: ":restart" (no bang) saves/restores session #40321

Problem:
`:restart` does not preserve window layout, etc.

Solution:
- Change `:restart` to save/restore a session automatically.
- Introduce "bang" variant `:restart!` to restart *without* session
  save/restore.
- Introduce `v:startreason`.
- `ZR` maps to `:restart!`.
This commit is contained in:
Nathan Zeng
2026-06-29 07:55:23 -07:00
committed by GitHub
parent 39e9c1754a
commit 845b66dd4a
14 changed files with 231 additions and 63 deletions

View File

@@ -1,3 +1,5 @@
local fs = vim.fs
local uv = vim.uv
-- For "--listen" and related functionality.
local M = {}
@@ -154,4 +156,63 @@ function M.rebind_after_restart(canonical_addr, expected_uis)
end)
end
-- Called by ex_restart(). Saves the current session and calls back to
-- ex_restart() with the necessary arguments to restore the session.
-- TODO: https://github.com/neovim/neovim/issues/34204
--- @param eap vim._core.ExCmdArgs
--- @param extra { quit_cmd: string }
function M.ex_session_restart(eap, extra)
-- Commands to run after restart
local after_cmd = eap.args
assert(not after_cmd:find(']==]'))
-- Use custom quit command if provided
local quit_cmd = 'qall'
if extra.quit_cmd ~= '' then
quit_cmd = extra.quit_cmd
end
-- Preserve the value of v:this_session
local this_session = vim.v.this_session
assert(not this_session:find(']==]'))
-- Get temp file to write session to
local temp_dir = fs.abspath(fs.dirname(fs.dirname(vim.fn.tempname())))
assert(not temp_dir:find(']==]'))
local fd, session = uv.fs_mkstemp(fs.joinpath(temp_dir, 'restart_session_XXXXXX'))
if not fd then
error('Failed to get temporary filename for restart session')
end
uv.fs_close(fd)
-- Write session
local session_arg = vim.fn.fnameescape(session)
vim.cmd('%argdelete')
vim.cmd.mksession { session_arg, bang = true }
-- Lua commands to restore the session and remove the session file
local after_list = {}
table.insert(after_list, ('vim.cmd("source %s")'):format(session_arg))
table.insert(after_list, ('pcall(vim.fs.rm, [==[%s]==])'):format(session))
table.insert(after_list, ('vim.v.this_session = [==[%s]==]'):format(this_session))
-- User provided command
if after_cmd ~= '' then
table.insert(after_list, ('vim.cmd([==[%s]==])'):format(after_cmd))
end
-- Concatenate everything together
local after = 'lua ' .. table.concat(after_list, ';')
-- Restart Neovim and run our Lua commands
local success, msg = pcall(function()
-- "+:::" special argument tells the C handler that this is actually a non-bang restart
-- That way, v:startreason can be set correctly
vim.cmd.restart { '+:::', quit_cmd, after, bang = true }
end)
if not success then
fs.rm(session, { force = true })
error(msg)
end
end
return M

View File

@@ -669,7 +669,8 @@ vim.v.stacktrace = ...
--- The reason Nvim started. Possible values:
--- - "normal" normal startup.
--- - "restart" started by `:restart` or `ZR`.
--- - "restart" started by `:restart`.
--- - "restart!" started by `:restart!` or `ZR`.
---
--- Read-only.
--- @type string