Compose compact Text workspace with guarded root navigation

This commit is contained in:
2026-09-13 04:10:27 -07:00
parent feab2020d8
commit 74542ae2c1
20 changed files with 5482 additions and 738 deletions
@@ -359,7 +359,7 @@ fn document_reset_retains_all_three_worker_slots_until_their_exact_results_arriv
assert_eq!(app.diagram_lookup_in_flight, Some(diagram_job));
send(&mut app, Message::SourceSymbolsReady(source_ready));
assert!(app.source_symbols.in_flight.is_none());
assert!(!app.source_symbols.open);
assert!(app.text_workspace.drawer().is_none());
send(&mut app, Message::DiagramUsagesReady(old_diagram));
assert_eq!(app.diagram_lookup_in_flight, Some(new_token));
assert!(app.diagram_usages.as_ref().unwrap().loading);
@@ -164,3 +164,112 @@ fn captured_behavior_toolbar_cannot_retire_a_new_documents_navigation() {
assert!(Arc::ptr_eq(&accepted, &app.document.snapshot()));
first_measurement(&mut app, &found);
}
#[test]
fn stale_compact_drawer_controls_preserve_current_navigation_and_evidence() {
use crate::app::text_workspace::{DrawerTab, Event as TextEvent};
for changed in 0..3 {
let mut app = navigation_fixture();
app.text_workspace.show_drawer(Some(DrawerTab::Status));
let origin = app.text_drawer_context();
let captured = [
Message::TextWorkspace(TextEvent::ShowDrawer(origin, DrawerTab::Problems)),
Message::TextWorkspace(TextEvent::HideDrawer(origin)),
crate::views::captured_text_drawer_resize(&app),
];
match changed {
0 => app.canvas_document = Id::new_v4(),
1 => app.source_workspace.reset_navigation_session(),
_ => app.text_workspace.show_drawer(Some(DrawerTab::Status)),
}
let found = navigate(&mut app);
// Keep command availability true to isolate the stale owner check from
// the page guard, while a newer measured navigation is still pending.
app.page = Page::Text;
assert!(app.source_navigation_available());
let destination = navigation(&app);
let allocation = app.allocation_boundary();
let camera = app.camera_boundary();
let allocation_epoch = app.allocation_drag.epoch;
let interaction = app.source_symbols.interaction;
let drawer = app.text_workspace.drawer();
let height = app.text_workspace.drawer_height();
let visit = app.text_workspace.drawer_visit();
let accepted = app.document.snapshot();
let raw = app.source_workspace.bundle();
let status = app.status.clone();
for message in captured {
send(&mut app, message);
assert_eq!(navigation(&app), destination);
assert!(app.allocation_boundary() == allocation);
assert!(app.camera_boundary() == camera);
assert_eq!(app.allocation_drag.epoch, allocation_epoch);
assert_eq!(app.source_symbols.interaction, interaction);
assert_eq!(app.text_workspace.drawer(), drawer);
assert_eq!(app.text_workspace.drawer_height(), height);
assert_eq!(app.text_workspace.drawer_visit(), visit);
assert_eq!(app.status, status);
assert_eq!(app.source_workspace.bundle(), raw);
assert!(Arc::ptr_eq(&accepted, &app.document.snapshot()));
assert!(!app.document.can_undo() && !app.document.can_redo());
}
app.page = Page::Diagram;
first_measurement(&mut app, &found);
}
}
#[test]
fn current_compact_drawer_controls_and_mounted_resize_remain_live() {
use crate::app::text_workspace::{DrawerTab, Event as TextEvent};
let mut app = navigation_fixture();
let accepted = app.document.snapshot();
let raw = app.source_workspace.bundle();
let show = Message::TextWorkspace(TextEvent::ShowDrawer(
app.text_drawer_context(),
DrawerTab::Status,
));
send(&mut app, show);
assert_eq!(app.text_workspace.drawer(), Some(DrawerTab::Status));
let height = app.text_workspace.drawer_height();
let resize = crate::views::captured_text_drawer_resize(&app);
send(&mut app, resize);
assert_eq!(app.text_workspace.drawer_height(), height + 60.);
let hide = Message::TextWorkspace(TextEvent::HideDrawer(app.text_drawer_context()));
send(&mut app, hide);
assert!(app.text_workspace.drawer().is_none());
assert_eq!(app.source_workspace.bundle(), raw);
assert!(Arc::ptr_eq(&accepted, &app.document.snapshot()));
assert!(!app.document.can_undo() && !app.document.can_redo());
}
#[test]
fn compact_diagram_usages_command_uses_captured_query_and_existing_chooser() {
let mut app = navigation_fixture();
let accepted = app.document.snapshot();
let raw = app.source_workspace.bundle();
let command = app.text_command_message(crate::app::text_workspace::Command::ShowDiagramUsages);
send(&mut app, command);
let request = app
.source_symbols
.request
.clone()
.expect("actual source query started");
assert_eq!(app.source_diagram_job, Some(request.job));
let completion = source_completion(&app, request);
send(&mut app, Message::SourceSymbolsReady(completion));
let panel = app
.diagram_usages
.as_ref()
.expect("existing guarded chooser opened");
assert_eq!(panel.context.subject, model_id(2));
assert_eq!(panel.context.document, app.canvas_document);
assert_eq!(panel.context.revision, app.document.revision());
assert_eq!(app.diagram_lookup_in_flight, Some(panel.token));
assert!(!app.source_navigation_available());
let (_, found) = finish_lookup(&mut app);
assert_eq!(found.surface, usage::Surface::Saved(model_id(8)));
assert_eq!(app.source_workspace.bundle(), raw);
assert!(Arc::ptr_eq(&accepted, &app.document.snapshot()));
assert!(app.source_symbols.back.is_empty());
assert!(!app.document.can_undo() && !app.document.can_redo());
}
@@ -287,7 +287,7 @@ fn alias_editor_sync_fallback_restores_accepted_display_and_preserves_model_hist
assert_ne!(app.source_navigation.label(), "0 matches");
let mut invalid = original_source.clone();
invalid.files.insert(path.clone(), "?".into());
app.source_diagnostics = source_workspace::lint(&invalid);
app.publish_source_diagnostics(source_workspace::lint(&invalid));
assert!(!app.source_diagnostics.is_empty());
let version = app.source_version;
app.lint_requested = Some(version);
@@ -839,7 +839,8 @@ fn actual_captured_escape_closes_only_its_priority_owner_and_retains_worker() {
send(&mut app, Message::SourceRenameReady(ready.clone()));
}
app.source_navigation.open = true;
app.source_symbols.open = true;
app.text_workspace
.show_drawer(Some(crate::app::text_workspace::DrawerTab::References));
match other_modal {
1 => app.hosted.visible = true,
2 => {
@@ -866,7 +867,7 @@ fn actual_captured_escape_closes_only_its_priority_owner_and_retains_worker() {
}
assert!(!app.source_rename.open());
assert!(
app.source_symbols.open && app.source_navigation.open,
app.text_workspace.drawer().is_some() && app.source_navigation.open,
"rename Escape does not fall through"
);
if pending {
@@ -875,7 +876,7 @@ fn actual_captured_escape_closes_only_its_priority_owner_and_retains_worker() {
assert!(!app.source_rename.open());
}
assert_eq!(evidence(&app), before);
app.source_symbols.open = false;
app.text_workspace.show_drawer(None);
app.source_navigation.open = false;
assert!(captured_escape(&app).is_empty());
}