Visuele stand: Overzicht-markering flipt per toetsaanslag — twee concurrerende caret-berekeningen #2141
Labels
No labels
accepted
bug
declined
docs
duplicate
enhancement
good first issue
in-progress
needs-info
privacy
release-blocker
security
triage
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
LibreKAT/Ocideck#2141
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Symptoom
In de visuele stand flipt de Overzicht-markering tijdens het typen heen en weer tussen de juiste kop en een andere kop, en de app voelt traag. Gemeld als "na een tabel bewerkt en verlaten", maar het tabelbezoek is niet de trigger — het flippen speelt zodra de twee caret→kop-berekeningen het structureel oneens zijn (zie hieronder).
Oorzaak — twee concurrerende berekeningen van dezelfde markering, elk met eigen frame
Per Quill-melding (
_onQuillChanged,markdown_editor.dart:557-580) loopt de outline-sync langs drie paden die elk hun eigen post-framesetStateplannen via_setActiveOutlineIndex(document_editor_screen.dart:275):onVisualCaret→_syncOutlineToVisualCaret(document_editor_layouts.dart:46-64) schrijft eerst_controller.selection— dat vuurt_onControllerChanged→_syncOutlineToMarkdownCaret→ index A viaactiveOutlineIndexForOffset(bron-offset)._syncOutlineToVisualCaretzelf index B viaactiveOutlineIndexInPlainText— een andere methode:indexOfop de koptitel in de platte tekst (markdown_outline.dart:78).widget.controller.value = …,markdown_editor.dart:578) vuurt opnieuw_onControllerChanged→ index C, weer via bron-offset.Quill/IME meldt documentwijzigingen en selectiewijzigingen als aparte notificaties in verschillende frames. De laatste schrijver per frame wint — en dat wisselt → zichtbaar flippen zodra A/C ≠ B.
Wanneer ze het oneens zijn (beide methoden falen elk op hun eigen manier):
activeOutlineIndexInPlainTextzoekt de letterlijke titelstring. Een kop met opmaak (## Paragraaf **vet**) staat in platte tekst alsParagraaf vet→indexOfmist hem → B rapporteert de kop dáárvoor.activeOutlineIndexForOffsetvertrouwt opMarkdownCaretMap.sourceOffsetOf, maar de kaart modelleert lang niet alle embeds die de codec kent. In Quill zijn dit elk één\uFFFC-teken; de kaart telt ze als volledige tekstregels:```mermaid-blokken: de kaart telt elke regel in de fence als zichtbare tekst (_fencePattern→_Row.text), Quill maakt er éénEmbeddableMermaid-embed van → per diagram tientallen tekens verschil.<!-- toc -->,<!-- timeline -->,<!-- pentest … -->-markers en voetnootdefinities[^1]: …→ embeds, kaart telt ze als tekst.[^label]-verwijzingen en inline-afbeeldingen → 1 teken in Quill, meerdere in de kaart (stripInlineMarkdownhoudt[^1]letterlijk,footnotes:false).Elke zo'n constructie boven de cursor laat
sourceOffsetOfsystematisch te vroeg landen → A/C wijzen de verkeerde kop aan, terwijl B wel goed zit — of andersom.Waarom traag: per toetsaanslag lopen
toPlainText,MarkdownCaretMap.of,toDelta,markdownFromDocument, tot 3×buildMarkdownOutline, een provider-edit én tot 3 losse post-framesetStates op de scherm-state — en_documentOutlineRailroept bij élke rebuild zelf weerbuildMarkdownOutline(source)aan (document_editor_toolbar.dart:819). Alles O(document), per aanslag, meerdere keren.Reproductie (widget-test, bewezen)
Zonder zo'n divergentie blijft de markering stabiel (
[Paragraaf, Paragraaf, …]) — de controle slaagt.Oplossingsrichting
_setActiveOutlineIndexaanroepen. De platte-tekstvariant (B) volgt de werkelijke Quill-caret zonder kwetsbare offset-vertaling — maar moet dan wel om koptitels met opmaak heen kunnen (zoek opstripInlineMarkdown(title), of werk met blok-indexen i.p.v.indexOfop de titelstring). De bron-offsetvariant (A/C) is betrouwbaar zodraMarkdownCaretMapalle embed-types als object markeert — dat is dan de andere helft van de klus. Beide tegelijk laten schrijven is hoe dan ook de bug.MarkdownCaretMapbijwerken voor de embed-types: mermaid-fences,<!-- toc/timeline/pentest -->-markers, voetnootdefinities en inline voetnoot/afbeelding-embeds als 1-teken objecten meetellen, zodat bron-offset↔visueel-offset weer klopt in documenten die ze bevatten.buildMarkdownOutlineniet 3–4× per aanslag draaien — één keer per bronwijziging cachen (of op deMarkdownSourceDocument/provider laten meerekenen) en de rail die versie laten gebruiken; en overwegen de outline-sync te dedupen per frame (max. één berekening per frame i.p.v. per notificatie).activeOutlineIndexniet alterneren — één stabiele kop per frame.