Reject stale navigation envelopes before shared boundaries

This commit is contained in:
2026-09-12 19:49:27 -07:00
parent a17ca5d066
commit 659b7a655a
11 changed files with 422 additions and 51 deletions
+19 -17
View File
@@ -1249,6 +1249,21 @@ impl App {
])
}
pub fn update(&mut self, message: Message) -> Task<Message> {
// These handlers reject old owners/tokens without changing state. Apply
// the same admission before shared camera and allocation boundaries.
if !self.source_input_envelope(&message)
|| matches!(&message, Message::DiagramUsage(event) if !self.diagram_usage_envelope(event))
|| matches!(&message, Message::WorkDrag(event) if !self.allocation_event_envelope(event))
{
return Task::none();
}
if let Message::WorkDrag(allocation_drag::Event::Press(press)) = &message
&& !self.allocation_press_owns_current_view(press)
{
// Keep the existing stale-press explanation, without treating the
// rejected press as a new navigation or allocation boundary.
return self.allocation_event(allocation_drag::Event::Press(press.clone()));
}
// A queued toolbar from a previous input owner cannot retire a newer
// navigation destination or allocation capability before dispatch.
if let Message::BehaviorControl(intent) = &message
@@ -1381,29 +1396,16 @@ impl App {
)
}
fn update_inner(&mut self, message: Message) -> Task<Message> {
if !self.source_input_envelope(&message) {
return Task::none();
}
let message = match message {
Message::SourceFindClose(context, instance) => {
if context != self.source_symbol_context()
|| instance != self.source_find_instance
|| !self.source_navigation.open
|| !self.source_navigation_available()
{
return Task::none();
}
Message::SourceFindClose(..) => {
// Only the checked envelope may enter the legacy Close handler.
Message::SourceNavigation(crate::source_navigation::Event::Close)
}
Message::SourceNavigation(crate::source_navigation::Event::Close) => {
return Task::none();
}
message => message,
};
if let Message::SourceSymbols(context, _) = &message
&& (context.session != self.source_workspace.session()
|| context.path != self.source_workspace.active)
{
return Task::none();
}
// Internal results and geometry do not constitute a new user intent.
// Process query completion even behind a modal to release its worker slot;
// its handler independently refuses navigation outside the live editor.