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:
@@ -124,6 +124,40 @@ pub fn migrate(app: &App) -> Result<usize> {
|
||||
Ok(count)
|
||||
}
|
||||
|
||||
/// Expand a history reference against the most recent entries
|
||||
/// (most recent first): !! (last), !N (the Nth most recent), !prefix (the
|
||||
/// most recent command starting with prefix) and ^old^new (substitution in
|
||||
/// the last command). Returns None when the line is not a reference.
|
||||
pub fn expand(entries: &[HistoryEntry], line: &str) -> Option<String> {
|
||||
let trimmed = line.trim();
|
||||
if trimmed == "!!" {
|
||||
return entries.first().map(|e| e.cmd.clone());
|
||||
}
|
||||
if let Some(rest) = trimmed.strip_prefix('!') {
|
||||
if !rest.is_empty() {
|
||||
if let Ok(n) = rest.parse::<usize>() {
|
||||
if n >= 1 {
|
||||
return entries.get(n - 1).map(|e| e.cmd.clone());
|
||||
}
|
||||
return None;
|
||||
}
|
||||
return entries
|
||||
.iter()
|
||||
.find(|e| e.cmd.starts_with(rest))
|
||||
.map(|e| e.cmd.clone());
|
||||
}
|
||||
}
|
||||
if let Some(body) = trimmed.strip_prefix('^') {
|
||||
if let Some((old, new)) = body.split_once('^') {
|
||||
if !old.is_empty() {
|
||||
let last = entries.first()?;
|
||||
return Some(last.cmd.replacen(old, new, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// History files of a directory, oldest first.
|
||||
pub fn files(dir: &Path) -> Vec<PathBuf> {
|
||||
let mut out: Vec<PathBuf> = std::fs::read_dir(dir)
|
||||
@@ -277,4 +311,22 @@ start group:dev
|
||||
Some("20260815_143926".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expand_history_references() {
|
||||
let entries = vec![
|
||||
HistoryEntry::now("install jcode"),
|
||||
HistoryEntry::now("start group:dev"),
|
||||
HistoryEntry::now("list --all"),
|
||||
];
|
||||
assert_eq!(expand(&entries, "!!").as_deref(), Some("install jcode"));
|
||||
assert_eq!(expand(&entries, "!2").as_deref(), Some("start group:dev"));
|
||||
assert_eq!(expand(&entries, "!9"), None, "out of range");
|
||||
assert_eq!(expand(&entries, "!li").as_deref(), Some("list --all"));
|
||||
assert_eq!(
|
||||
expand(&entries, "^jcode^aider").as_deref(),
|
||||
Some("install aider")
|
||||
);
|
||||
assert_eq!(expand(&entries, "plain line"), None);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user