Merge pull request #3502 from nrq6993-a11y/stream/vc-feat1-3455-home-reopen-focus

Fix #3455: Home recent reopen focuses existing document
This commit is contained in:
BFlat
2026-10-22 11:08:42 +07:00
committed by GitHub
4 changed files with 68 additions and 2 deletions
+1 -1
View File
@@ -3094,7 +3094,7 @@ fn recent(app: &mut VectorcraftApp, ui: &mut Ui) {
for path in files {
if recent_row(ui, &path).clicked() {
// A failure is reported to the user there.
let _ = crate::io::open_reporting(app, &path);
let _ = crate::io::open_recent_reporting(app, &path);
}
}
}
+38
View File
@@ -214,6 +214,44 @@ pub fn open_reporting(app: &mut VectorcraftApp, path: &str) -> Result<Value, Str
r
}
/// Home › Recent Files and File › Open Recent: focus an already-open tab for that path instead of
/// calling `document.open` again (#3455).
pub fn open_recent_reporting(app: &mut VectorcraftApp, path: &str) -> Result<Value, String> {
if let Some(r) = try_activate_open_document(app, path)? {
return Ok(r);
}
open_reporting(app, path)
}
fn try_activate_open_document(app: &mut VectorcraftApp, path: &str) -> Result<Option<Value>, String> {
let Some(index) = document_index_for_path(app, path) else {
return Ok(None);
};
let st = &app.session.documents()[index];
let r = json!({
"index": index,
"title": st.title(),
"format": st.format,
"warnings": [],
"restored": false,
"activated": true,
});
app.run("document.activate", json!({ "index": index }))?;
opened(app, &r);
Ok(Some(r))
}
fn document_index_for_path(app: &VectorcraftApp, path: &str) -> Option<usize> {
app.session.documents().iter().position(|st| st.path.as_deref().is_some_and(|p| same_open_path(p, path)))
}
fn same_open_path(a: &str, b: &str) -> bool {
match (std::fs::canonicalize(a), std::fs::canonicalize(b)) {
(Ok(a), Ok(b)) => a == b,
_ => a == b,
}
}
fn read(app: &VectorcraftApp, path: &str) -> Result<Vec<u8>, String> {
app.services.read.as_ref().ok_or("no file reader")?(path)
}
+1 -1
View File
@@ -1266,7 +1266,7 @@ pub fn run_ui_command(app: &mut VectorcraftApp, id: &str, p: &Value) -> Option<R
"file.cancelExport" => Ok(io::cancel_exports(app)),
"file.exportInBackground" => Ok(io::hide_exports(app)),
id if id.starts_with("file.openRecent") => match recent_slot(app, id).cloned() {
Some(path) => io::open_reporting(app, &path),
Some(path) => io::open_recent_reporting(app, &path),
None => Err("no such recent file".into()),
},
"type.findFont" => {
+28
View File
@@ -297,3 +297,31 @@ fn home_scrolls_in_a_short_window() {
visible_home_texts(&mut app, &ctx, size, 4.1, vec![press(false)]);
assert_eq!(app.session.documents().len(), 1, "the card opened its preset");
}
/// Home › Recent Files and File › Open Recent focus an open tab instead of opening a second copy
/// (#3455); `document.open` is unchanged.
#[test]
fn home_recent_reopen_focuses_an_already_open_document() {
let services = crate::Services {
read: Some(Box::new(|p: &str| std::fs::read(p).map_err(|e| e.to_string()))),
write: Some(Box::new(|p: &str, b: &[u8]| std::fs::write(p, b).map_err(|e| e.to_string()))),
..Default::default()
};
let mut app = VectorcraftApp::new(vectorcraft_engine::Session::new(), services);
let d = std::env::temp_dir().join(format!("vc-home-reopen-{}", std::process::id()));
let _ = std::fs::remove_dir_all(&d);
std::fs::create_dir_all(&d).unwrap();
let path = d.join("doc.vectorcraft").to_string_lossy().to_string();
app.run("file.new", json!({"width": 100, "height": 100})).unwrap();
app.run("shape.rectangle", json!({"x": 1, "y": 2, "width": 10, "height": 10})).unwrap();
app.run("file.saveAs", json!({"path": path})).unwrap();
app.run("file.new", json!({})).unwrap();
assert_eq!(app.session.documents().len(), 2);
assert_eq!(app.session.active_index(), Some(1));
let r = crate::io::open_recent_reporting(&mut app, &path).unwrap();
assert_eq!(r["activated"], true);
assert_eq!(app.session.documents().len(), 2);
assert_eq!(app.session.active_index(), Some(0));
assert_eq!(app.session.doc().unwrap().doc.layers[0].children().unwrap().len(), 1);
let _ = std::fs::remove_dir_all(d);
}