history : reexecution (issues #27 #28) - expansion !! !N !prefix ^old^new dans le REPL + am history --rerun N avec confirmation (shell ou commande am)
This commit is contained in:
@@ -3,6 +3,44 @@
|
||||
use super::*;
|
||||
use crate::history::{self, HistoryEntry};
|
||||
use crate::output::print_json;
|
||||
use anyhow::{anyhow, Result};
|
||||
use clap::Parser;
|
||||
|
||||
/// Re-run the Nth most recent entry: shell commands go through the
|
||||
/// active shell, am commands are parsed and dispatched like the REPL does.
|
||||
fn rerun_entry(app: &App, n: usize) -> Result<i32> {
|
||||
if n == 0 {
|
||||
return Err(anyhow!("invalid entry number 0 — am history numbers start at 1"));
|
||||
}
|
||||
let entries = history::read_all(app, n);
|
||||
let entry = entries.get(n - 1).cloned().ok_or_else(|| {
|
||||
anyhow!("history entry {n} not found — 'am history' lists them")
|
||||
})?;
|
||||
let question = format!("re-run: {} [y/N]", entry.cmd);
|
||||
if !app.confirm(&question)? {
|
||||
app.log.info("cancelled");
|
||||
return Ok(0);
|
||||
}
|
||||
let cmd = entry.cmd.strip_prefix('!').unwrap_or(&entry.cmd);
|
||||
if entry.kind == "shell" {
|
||||
let session = crate::shell::ShellSession::start(&app.config);
|
||||
return Ok(session.run(cmd)?);
|
||||
}
|
||||
let tokens = shell_words::split(cmd)
|
||||
.map_err(|e| anyhow!("cannot parse '{cmd}': {e}"))?;
|
||||
if tokens.is_empty() {
|
||||
return Ok(0);
|
||||
}
|
||||
let cli = crate::cli::Cli::try_parse_from(std::iter::once("am".to_string()).chain(tokens))
|
||||
.map_err(|e| anyhow!("cannot parse '{cmd}': {e}"))?;
|
||||
match &cli.command {
|
||||
Some(cmd) => execute_command(app, cmd),
|
||||
None => {
|
||||
app.log.info("nothing to re-run (no subcommand)");
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Filter history entries; returns them most recent first.
|
||||
pub fn filter(
|
||||
@@ -57,8 +95,12 @@ pub fn run(
|
||||
failed: bool,
|
||||
session: Option<&str>,
|
||||
limit: usize,
|
||||
rerun: Option<usize>,
|
||||
) -> Result<i32> {
|
||||
history::migrate(app)?;
|
||||
if let Some(n) = rerun {
|
||||
return rerun_entry(app, n);
|
||||
}
|
||||
let rows = filter(app, kind, cwd, search, failed, session, limit);
|
||||
if app.json() {
|
||||
let payload: Vec<serde_json::Value> = rows
|
||||
|
||||
@@ -102,6 +102,7 @@ pub fn execute_command(app: &App, cmd: &Command) -> Result<i32> {
|
||||
failed,
|
||||
session,
|
||||
limit,
|
||||
rerun,
|
||||
} => history_cmd::run(
|
||||
app,
|
||||
kind.as_deref(),
|
||||
@@ -110,6 +111,7 @@ pub fn execute_command(app: &App, cmd: &Command) -> Result<i32> {
|
||||
*failed,
|
||||
session.as_deref(),
|
||||
*limit,
|
||||
*rerun,
|
||||
),
|
||||
Command::Info { agent } => info_cmd::run(app, agent),
|
||||
Command::Init { force } => init_cmd::run(app, *force),
|
||||
|
||||
Reference in New Issue
Block a user