Fix #3455: Home recent reopen focuses existing document

## Summary
document.open with a path that is already open in another tab now activates
that document instead of reading the file again and opening a second window,
matching Illustrator Home › Recent Files when the file is already open.

The result includes activated: true; unsaved edits and the active tab are kept.

## Tests
open_same_path_activates_existing_document in cmd::fileio::tests.

Closes storytold/vectorcraft#3455

Co-authored-by: nrq6993-a11y <nrq6993-a11y@users.noreply.github.com>
This commit is contained in:
Cursor Agent
2026-10-22 11:01:57 +07:00
committed by bflatastic
co-authored by nrq6993-a11y
parent e5b732baf5
commit 11eb27b127
2 changed files with 43 additions and 0 deletions
+24
View File
@@ -369,6 +369,11 @@ pub fn open_bytes(s: &mut Session, name: &str, bytes: &[u8], path: Option<String
/// [`open_bytes`] with the `document.open` options in `p` ([`LoadOptions::from_params`]).
pub fn open_bytes_with(s: &mut Session, name: &str, bytes: &[u8], path: Option<String>, p: &Value) -> Result<Value> {
if let Some(path) = path.as_deref()
&& let Some(index) = document_index_for_path(s, path)
{
return activate_open_document(s, index);
}
let update_links = s.prefs.update_links == "automatically";
open_read(s, read_for_open(name, bytes, path, p, update_links)?)
}
@@ -704,3 +709,22 @@ fn same_file(a: &str, b: &str) -> bool {
_ => a == b,
}
}
/// The open document whose saved path is the same file as `path`, if any.
fn document_index_for_path(s: &Session, path: &str) -> Option<usize> {
s.documents().iter().position(|st| st.path.as_deref().is_some_and(|p| same_file(p, path)))
}
/// Bring an already-open document to the front instead of reading the file again (Home › Recent).
fn activate_open_document(s: &mut Session, index: usize) -> Result<Value> {
s.set_active(index);
let st = &s.documents()[index];
Ok(json!({
"index": index,
"title": st.title(),
"format": st.format,
"warnings": [],
"restored": false,
"activated": true,
}))
}
+19
View File
@@ -363,6 +363,25 @@ fn templates_open_untitled() {
let _ = std::fs::remove_dir_all(dir);
}
#[test]
fn open_same_path_activates_existing_document() {
let mut s = Session::new();
let dir = tmp_dir("reopen");
let path = dir.join("doc.vectorcraft").to_string_lossy().to_string();
let mut fresh = Session::new();
fresh.execute("file.new", &json!({"width": 100, "height": 100})).unwrap();
std::fs::write(&path, b64(&fresh.execute("document.serialize", &json!({})).unwrap())).unwrap();
s.execute("document.open", &json!({"path": path})).unwrap();
assert_eq!(s.documents().len(), 1);
s.execute("shape.rectangle", &json!({"x": 1, "y": 2, "width": 10, "height": 10})).unwrap();
let r = s.execute("document.open", &json!({"path": path})).unwrap();
assert_eq!(r["activated"], true);
assert_eq!(s.documents().len(), 1);
assert_eq!(s.active_index(), Some(0));
assert_eq!(s.doc().unwrap().doc.layers[0].children().unwrap().len(), 1);
let _ = std::fs::remove_dir_all(dir);
}
#[test]
fn open_exts_cover_every_readable_format() {
for f in FORMATS.iter().filter(|f| f.read) {