Keep failed scripts and selected panels out of recent script history

This commit is contained in:
dotCooCoo
2026-10-27 11:06:19 -07:00
parent 2c2c51ca0c
commit 8ee9bc144b
2 changed files with 48 additions and 9 deletions
+9 -8
View File
@@ -450,9 +450,6 @@ fn run_script(s: &mut Session, p: &Value) -> Result<Value> {
&& p.get("steps").is_none()
{
let name = name.to_string();
if super::scripts::scripts(s).iter().any(|e| e.name == name && !e.panel) {
remember_script(s, crate::prefs::RecentScript::Name(name.clone()));
}
return super::scripts::run_named(s, &name);
}
if let Some(path) = str_p(p, "path")
@@ -464,18 +461,19 @@ fn run_script(s: &mut Session, p: &Value) -> Result<Value> {
}
let bytes = s.services.read_file(path).map_err(|e| EngineError::Other(format!("cannot read {path}: {e}")))?;
let full = s.services.full_path(path);
remember_script(s, crate::prefs::RecentScript::Path(full));
let code = String::from_utf8_lossy(&bytes).to_string();
let name = std::path::Path::new(path).file_name().map(|n| n.to_string_lossy().to_string()).unwrap_or_else(|| path.to_string());
let out = run_js(s, &code, path, false)?;
return report_js(s, &name, out);
let result = report_js(s, &name, out)?;
remember_script(s, crate::prefs::RecentScript::Path(full));
return Ok(result);
}
let mut script_path = None;
let steps: Vec<Value> = match (p.get("steps"), str_p(p, "path")) {
(Some(Value::Array(a)), _) => a.clone(),
(_, Some(path)) => {
let bytes = s.services.read_file(path).map_err(|e| EngineError::Other(format!("cannot read {path}: {e}")))?;
let full = s.services.full_path(path);
remember_script(s, crate::prefs::RecentScript::Path(full));
script_path = Some(s.services.full_path(path));
let text = String::from_utf8_lossy(&bytes).to_string();
match serde_json::from_str::<Value>(&text) {
Ok(Value::Array(a)) => a,
@@ -508,11 +506,14 @@ fn run_script(s: &mut Session, p: &Value) -> Result<Value> {
let r = r.map_err(|e| EngineError::Other(format!("step {} ({id}): {e}", i + 1)))?;
results.push(r);
}
if let Some(path) = script_path {
remember_script(s, crate::prefs::RecentScript::Path(path));
}
Ok(json!({"steps": results.len(), "results": results}))
}
/// Remember a script that runs for File ▸ Scripts ▸ Recent Script Files.
fn remember_script(s: &mut Session, script: crate::prefs::RecentScript) {
pub(super) fn remember_script(s: &mut Session, script: crate::prefs::RecentScript) {
s.prefs.push_recent_script(script);
s.save_prefs();
s.prefs_revision += 1;
+39 -1
View File
@@ -241,7 +241,9 @@ pub(crate) fn run_named(s: &mut Session, name: &str) -> Result<Value> {
if panel {
return open_panel(s, &json!({"name": name}));
}
super::file_more::run_js_named(s, &code, name)
let result = super::file_more::run_js_named(s, &code, name)?;
super::file_more::remember_script(s, crate::prefs::RecentScript::Name(name.to_string()));
Ok(result)
}
/// The code a ScriptUI panel runs with: `this` is a dockable Panel titled after the script.
@@ -603,6 +605,42 @@ mod tests {
let _ = std::fs::remove_dir_all(&root);
}
#[test]
fn recent_script_history_uses_the_selected_script() {
let (mut s, root) = session_in_tmp("recent-panel-collision");
let name = "Rename Layers.jsx";
std::fs::write(root.join("settings").join(PANELS_DIR).join(name), "panel").unwrap();
assert!(super::scripts(&s).iter().any(|entry| entry.name == name && !entry.panel));
assert!(script_code(&s, name, None).unwrap().0);
s.execute("file.runScript", json!({"name": name})).unwrap();
assert!(s.prefs.recent_scripts.is_empty(), "the selected panel must not enter recent script history");
let _ = std::fs::remove_dir_all(root);
}
#[test]
fn recent_script_history_keeps_successful_entries_when_scripts_fail() {
fn fail_or_echo(_: &mut Session, request: &ScriptRequest) -> Value {
if request.code == "fail" { json!({"error": {"message": "script failed"}}) } else { json!({"ran": request.code}) }
}
let (mut s, root) = session_in_tmp("recent-failed");
s.script = Some(fail_or_echo);
let good = root.join("good.jsonl");
std::fs::write(&good, "[]").unwrap();
s.execute("file.runScript", json!({"path": good})).unwrap();
let remembered = s.prefs.recent_scripts.clone();
for (name, code) in [("parse.jsonl", "{"), ("step.jsonl", r#"{"command":"does.not.exist"}"#), ("missing-command.jsonl", "{}"), ("runtime.jsx", "fail")]
{
let path = root.join(name);
std::fs::write(&path, code).unwrap();
assert!(s.execute("file.runScript", json!({"path": path})).is_err(), "{name}");
assert_eq!(s.prefs.recent_scripts, remembered, "{name}");
}
std::fs::write(root.join("settings").join(SCRIPTS_DIR).join("Failed.jsx"), "fail").unwrap();
assert!(s.execute("file.runScript", json!({"name": "Failed.jsx"})).is_err());
assert_eq!(s.prefs.recent_scripts, remembered);
let _ = std::fs::remove_dir_all(root);
}
/// Reads relative paths from a working directory that a test can change.
struct InFolder(std::sync::Mutex<PathBuf>);