Make web document navigation survive live-updating pages

Recreated-node caret recovery, tolerant caret validation, per-root retained document trees and cursors across tab switches, document warm-up, coalesced structural moves, and hung-provider fast-fail with an 'Application is not responding' announcement.
This commit is contained in:
hjozwiak committed 2026-11-03 10:34:55 -05:00
1 parent 8ce5e5cdad
commit 7eef6e8be6
30 files changed
+1484 -174

No files matched your search

+37
View File
@@ -110,6 +110,43 @@ func TestNavigationDocumentValidatesOnlyTraversedBranches(t *testing.T) {
}
}
// Caret moves read text and line bounds live from the provider, so text,
// geometry, or child-order staleness along the traversed range must not
// force a recapture first: on ticking pages some counter between caret and
// target is always mid-update, and strict validation traps the caret no
// matter how often it recaptures. Identity and semantics stay strict, and
// the strict range validation used by structural navigation is unchanged.
func TestValidateDocumentCaretRangeToleratesTextAndGeometryStaleness(t *testing.T) {
for _, test := range []struct {
name string
invalidate func(*AccessibleTree)
want error
wantStrict error
}{
{"text", func(tree *AccessibleTree) { tree.InvalidateText(testID("/link")) }, nil, ErrStaleText},
{"geometry", func(tree *AccessibleTree) { tree.InvalidateGeometry(testID("/inner")) }, nil, ErrStaleGeometry},
{"semantics", func(tree *AccessibleTree) { tree.InvalidateSnapshot(testID("/link")) }, ErrStaleSnapshot, ErrStaleSnapshot},
{"children", func(tree *AccessibleTree) { tree.MarkChildrenChanged(testID("/inner")) }, nil, ErrIncompleteTree},
} {
t.Run(test.name, func(t *testing.T) {
tree, _ := NewAccessibleTree(testID("/root"), documentTestNodes())
ref, _ := tree.Reference(testID("/heading"))
view, err := tree.NavigationDocument(context.Background(), ref)
if err != nil {
t.Fatal(err)
}
test.invalidate(tree)
heading, _ := view.Index(ref.ID())
if err := tree.ValidateDocumentCaretRange(context.Background(), view, heading, len(view.Nodes)-1); !errors.Is(err, test.want) {
t.Fatalf("caret validation: %v, want %v", err, test.want)
}
if err := tree.ValidateDocumentRange(context.Background(), view, heading, len(view.Nodes)-1); !errors.Is(err, test.wantStrict) {
t.Fatalf("strict validation changed: %v, want %v", err, test.wantStrict)
}
})
}
}
func TestNavigationDocumentRejectsRetiredViewsAndCanceledMoves(t *testing.T) {
tree, _ := NewAccessibleTree(testID("/root"), documentTestNodes())
ref, _ := tree.Reference(testID("/heading"))