Session::opened identifies the open document

It changes when file.open, file.recover or file.sample replaces the session
and when geometry.open opens another design file or starts a new model; an
edit, a solve or reopening the same design keep it. The desktop app frames
the view on that change (#233).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
This commit is contained in:
jyvikoandClaude Opus 5.5 authored and Irakli Kourtis committed 2026-10-14 22:29:44 -04:00
1 parent a0f48c7207
commit 696b64c30f
3 files changed
+48

No files matched your search

+1
View File
@@ -232,6 +232,7 @@ impl Session {
opened.limits = self.limits;
opened.file_access = std::mem::take(&mut self.file_access);
opened.clear_history();
opened.mark_opened();
*self = opened;
}
}
+5
View File
@@ -90,6 +90,11 @@ fn open(s: &mut Session, p: &Value) -> Result<Value> {
"related": fit.related,
"stale": {"mesh_bodies": fit.mesh_bodies, "sets": fit.sets, "seeds": fit.seeds},
});
// Another design file (or a new model) is another document; the same file opened again after
// an edit is the same one.
if new_model || s.sources.design.as_ref().is_none_or(|d| d.path() != source.path()) {
s.mark_opened();
}
s.design = Some(Arc::new(design));
s.sources.design = Some(source);
Ok(out)
+42
View File
@@ -228,6 +228,9 @@ pub struct Session {
/// The folders commands may read and write files in (an automation client's roots,
/// docs/mcp.md); unconfined by default. A file replacing the session keeps them.
pub file_access: fieldcraft_io::roots::Roots,
/// Identifies the open document: it changes when another model, sample or design is opened
/// in place of the current one, never with an edit (see [`Session::opened`]).
opened: u64,
}
impl Session {
@@ -280,6 +283,19 @@ impl Session {
Ok(outputs)
}
/// Identifies the open document: it changes when `file.open`, `file.recover` or `file.sample`
/// replaces the session and when `geometry.open` opens another design file or starts a new
/// model with one; an edit, a solve, undo, redo or opening the same design again after an
/// edit keep it. A view frames the model again when it changes.
pub fn opened(&self) -> u64 {
self.opened
}
/// Make the session another document (see [`Session::opened`]).
pub(crate) fn mark_opened(&mut self) {
self.opened = next_revision();
}
/// Identifies the current state (see [`Session::is_dirty`]).
pub fn revision(&self) -> u64 {
self.revision
@@ -699,6 +715,32 @@ mod tests {
s
}
/// `opened` changes with another document (a sample, another design file, a new model) and
/// stays with an edit, a solve or the same design opened again: views frame on that change.
#[test]
fn the_open_document_changes_only_when_another_is_opened() {
let mut s = Session::default();
let start = s.opened();
s.execute("file.sample", &json!({"name": "cantilever"})).unwrap();
let cantilever = s.opened();
assert_ne!(cantilever, start);
s.execute("solve.run", &json!({})).unwrap();
s.execute("model.material.create", &json!({"name": "Al", "elastic": {"type": "isotropic", "young": 70000, "poisson": 0.33}})).unwrap();
assert_eq!(s.opened(), cantilever, "edits and solves keep the document");
s.execute("file.sample", &json!({"name": "cantilever"})).unwrap();
assert_ne!(s.opened(), cantilever, "a sample opened again is a fresh start");
let (_dir, path) = sample_design_file(&Plate::default());
let before = s.opened();
s.execute("geometry.open", &json!({"path": path})).unwrap();
let design = s.opened();
assert_ne!(design, before, "another design file");
s.execute("geometry.open", &json!({"path": path})).unwrap();
assert_eq!(s.opened(), design, "the same design opened again after an edit");
s.execute("geometry.open", &json!({"path": path, "model": "new"})).unwrap();
assert_ne!(s.opened(), design, "a new model");
}
#[test]
fn reopening_the_same_design_keeps_the_mesh_and_definitions() {
let (_dir, path) = sample_design_file(&Plate::default());