fix: retain alternate screen across executable restart

This commit is contained in:
2026-10-12 23:26:38 +02:00
parent d85998e1cb
commit c35abe0f03
6 changed files with 273 additions and 103 deletions
+39 -15
View File
@@ -1,7 +1,10 @@
use std::{env, path::PathBuf};
use std::{env, io, path::PathBuf};
use vamp::{session::EditorSession, tui};
// Only the first argument can be this process-to-process terminal handoff marker.
const INHERITED_SCREEN: &str = "--vamp-inherit-alternate-screen";
const HELP: &str = "vamp — modal editor with isolated Ruby plugins
Usage: vamp [--config PATH | --no-config] [FILE]
@@ -86,8 +89,8 @@ struct Options {
config: Option<PathBuf>,
}
fn options() -> Result<Option<Options>, String> {
let mut args = env::args_os().skip(1);
fn options(inherited_screen: bool) -> Result<Option<Options>, String> {
let mut args = env::args_os().skip(1 + usize::from(inherited_screen));
let mut file = None;
let mut config = None;
let mut config_selected = false;
@@ -129,7 +132,25 @@ fn options() -> Result<Option<Options>, String> {
}
fn run() -> Result<(), String> {
let Some(options) = options()? else {
let inherited_screen = env::args_os()
.nth(1)
.is_some_and(|arg| arg == INHERITED_SCREEN);
if inherited_screen {
return tui::TerminalSession::run(true, || {
run_editor(options(true).map_err(io::Error::other)?, true)
})
.map_err(|error| error.to_string());
}
let options = options(false)?;
if options.is_none() {
return Ok(());
}
tui::TerminalSession::run(false, || run_editor(options, false))
.map_err(|error| error.to_string())
}
fn run_editor(options: Option<Options>, inherited_screen: bool) -> io::Result<()> {
let Some(options) = options else {
return Ok(());
};
let mut session = EditorSession::open(
@@ -137,34 +158,37 @@ fn run() -> Result<(), String> {
tui::CAPABILITIES.iter().map(|s| (*s).to_owned()).collect(),
options.config.as_deref(),
)
.map_err(|error| format!("cannot open file: {error}"))?;
tui::run(&mut session).map_err(|error| format!("terminal error: {error}"))?;
.map_err(|error| io::Error::other(format!("cannot open file: {error}")))?;
tui::run(&mut session, inherited_screen)?;
let restart = session.editor().should_restart();
drop(session);
if restart {
restart_editor()?;
tui::TerminalSession::prepare_restart()?;
restart_editor(inherited_screen)
.map_err(|error| io::Error::other(format!("Restart failed: {error}")))?;
}
Ok(())
}
fn restart_editor() -> Result<(), String> {
let executable = env::current_exe().map_err(|error| format!("Restart failed: {error}"))?;
fn restart_editor(inherited_screen: bool) -> io::Result<()> {
let executable = env::current_exe()?;
let mut command = std::process::Command::new(executable);
command.args(env::args_os().skip(1));
command.arg(INHERITED_SCREEN);
command.args(env::args_os().skip(1 + usize::from(inherited_screen)));
#[cfg(unix)]
{
use std::os::unix::process::CommandExt;
Err(format!("Restart failed: {}", command.exec()))
Err(command.exec())
}
#[cfg(not(unix))]
{
let status = command
.status()
.map_err(|error| format!("Restart failed: {error}"))?;
let status = command.status()?;
if status.success() {
Ok(())
} else {
Err(format!("Restarted editor exited with {status}"))
Err(io::Error::other(format!(
"Restarted editor exited with {status}"
)))
}
}
}