fix(editor): een dieper inspringniveau wordt niet meer stil afgeknipt #1563

Merged
brenno merged 2 commits from fix/inspringniveau-niet-stil-afknippen into main 2026-08-18 21:05:14 +00:00
Owner

Een inspringniveau dat dieper is dan de knop kan maken, werd stil afgeknipt zodra
je de dia in de visuele editor opende en er íets in typte.

Wat er misging, gemeten

Een dia met vier zichtbare niveaus, waarin ik één letter typ in het eerste
item:

VOOR : [0, 2, 4, 6]
NA   : [0, 2, 4, 4]

Het vierde item zakte een niveau. De gebruiker had die regel niet aangeraakt.

_levelOf klemde het niveau al bij het lezen op _maxLevel, en _emit
schreef dat geklemde niveau weer terug — dus de klem sloeg toe op alles wat de
editor in handen kreeg, niet alleen op wat je wijzigde. Terugdraaien met
ongedaan-maken in het bronvenster hielp niet: de dia was dan al herschreven.

Dat dit niveau 6 überhaupt bestaat, komt door een dubbeltelling: de parser
rekent twee spaties per niveau, terwijl markdown doorgaans met vier wordt
geschreven. Een geïmporteerde of geplakte lijst van vier zichtbare niveaus staat
intern dus op 0-2-4-6, en 6 lag boven het plafond van 4.

Waarom het plafond geen formaatgrens is

plek plafond
formaat / model (bulletLevel) geen
markdown-parser geen
dia-render (level * bulletSize * 1.05) geen, lineair
HTML-export (margin-left: level * 1.4em) geen
bullets_editor 4
bullets_image_editor 4
tree_editor 6

Nergens in de documentatie staat een maximum. Het getal is een grens van de
bediening die in drie editors was overgeschreven, met een derde waarde die
niemand ooit heeft besloten.

Wat er verandert

Lezen gebeurt ongeklemd. De eigen _levelOf van beide opsommingseditors kon
weg; ze gebruiken nu dezelfde bulletLevel als de rest van de codebase. Eén
lezer in plaats van drie.

Alleen de knop begrenst, via één gedeelde kMaxIndentButtonLevel naast
bulletLevel, met een doc-comment dat vastlegt dát het formaat geen maximum
kent — zodat de volgende lezer 4 niet voor een formaatgrens aanziet.

De boomeditor loopt mee op diezelfde constante, en had daar een eigen fout:
_indent klemde met clamp(0, _maxLevel), waardoor uitspringen vanaf niveau 6
met één klik naar 4 sprong in plaats van naar 5. Uitspringen gaat nu altijd één
stap; inspringen stopt bij het maximum.

De afweging die hieronder ligt

Drie routes lagen open. De dubbeltelling zélf wegnemen (parser op vier spaties)
ruimt de oorzaak op, maar laat elk bestaand deck met twee-spaties-inspringing —
precies wat OciDeck zelf schrijft en wat Tab in de broneditor produceert — zijn
niveaus verliezen. Dat is een formaatwijziging vermomd als een constante, en die
hoort niet zonder versieveld en migratiepad.

Het knopplafond verruimen naar vier zichtbare niveaus (acht tabs) lost het
gemelde gebrek ook op, maar laat de oorzaak staan en kost breedte in de render,
die zelf geen plafond kent.

Gekozen is de kleinste ingreep die de échte schade wegneemt: niet meer stil
herschrijven wat de gebruiker niet heeft aangeraakt. Hoe diep de knop mag komen
is daarmee een aparte vraag, die later los te beantwoorden is. De dubbeltelling
blijft staan en is vastgelegd in het commentaar bij de constante.

Toetsing

Beide reparaties zijn één keer teruggezet; precies hun eigen test viel, en niets
anders:

  • een niveau dieper dan de knop kan, blijft staan als je iets anders typt
    valt zodra het lezen weer klemt.
  • TreeEditor een dieper niveau blijft staan en springt met één stap uit
    valt zodra _indent weer met clamp(0, _maxLevel) werkt.

Bewaker

Bewust overgeslagen: raakt het bestandsformaat niet (tabs blijven de opslagvorm
en er verandert niets aan wat er weggeschreven wordt), geen opslag, geen
afhankelijkheid, geen uitgaand verkeer, geen publieke belofte. Wel raakte het
gebrek de inhoud van bestaande decks — die schade is nu juist wat verdwijnt.

Poorten

make check groen (exit 0, 9801 tests, dekking 87,0%, per-bestandsvloer 0),
make check-secrets groen (geen lekken), make sast groen (0 bevindingen).
DAST niet gedraaid — geen geserveerd oppervlak geraakt.

Closes #1558

Een inspringniveau dat dieper is dan de knop kan maken, werd stil afgeknipt zodra je de dia in de visuele editor opende en er íets in typte. ## Wat er misging, gemeten Een dia met vier zichtbare niveaus, waarin ik één letter typ in het **eerste** item: ``` VOOR : [0, 2, 4, 6] NA : [0, 2, 4, 4] ``` Het vierde item zakte een niveau. De gebruiker had die regel niet aangeraakt. `_levelOf` klemde het niveau al bij het **lezen** op `_maxLevel`, en `_emit` schreef dat geklemde niveau weer terug — dus de klem sloeg toe op alles wat de editor in handen kreeg, niet alleen op wat je wijzigde. Terugdraaien met ongedaan-maken in het bronvenster hielp niet: de dia was dan al herschreven. Dat dit niveau 6 überhaupt bestaat, komt door een dubbeltelling: de parser rekent **twee** spaties per niveau, terwijl markdown doorgaans met **vier** wordt geschreven. Een geïmporteerde of geplakte lijst van vier zichtbare niveaus staat intern dus op 0-2-4-6, en 6 lag boven het plafond van 4. ## Waarom het plafond geen formaatgrens is | plek | plafond | | --- | --- | | formaat / model (`bulletLevel`) | geen | | markdown-parser | geen | | dia-render (`level * bulletSize * 1.05`) | geen, lineair | | HTML-export (`margin-left: level * 1.4em`) | geen | | `bullets_editor` | 4 | | `bullets_image_editor` | 4 | | `tree_editor` | **6** | Nergens in de documentatie staat een maximum. Het getal is een grens van de *bediening* die in drie editors was overgeschreven, met een derde waarde die niemand ooit heeft besloten. ## Wat er verandert **Lezen gebeurt ongeklemd.** De eigen `_levelOf` van beide opsommingseditors kon weg; ze gebruiken nu dezelfde `bulletLevel` als de rest van de codebase. Eén lezer in plaats van drie. **Alleen de knop begrenst**, via één gedeelde `kMaxIndentButtonLevel` naast `bulletLevel`, met een doc-comment dat vastlegt dát het formaat geen maximum kent — zodat de volgende lezer 4 niet voor een formaatgrens aanziet. **De boomeditor loopt mee** op diezelfde constante, en had daar een eigen fout: `_indent` klemde met `clamp(0, _maxLevel)`, waardoor uitspringen vanaf niveau 6 met één klik naar 4 sprong in plaats van naar 5. Uitspringen gaat nu altijd één stap; inspringen stopt bij het maximum. ## De afweging die hieronder ligt Drie routes lagen open. De dubbeltelling zélf wegnemen (parser op vier spaties) ruimt de oorzaak op, maar laat elk bestaand deck met twee-spaties-inspringing — precies wat OciDeck zelf schrijft en wat Tab in de broneditor produceert — zijn niveaus verliezen. Dat is een formaatwijziging vermomd als een constante, en die hoort niet zonder versieveld en migratiepad. Het knopplafond verruimen naar vier *zichtbare* niveaus (acht tabs) lost het gemelde gebrek ook op, maar laat de oorzaak staan en kost breedte in de render, die zelf geen plafond kent. Gekozen is de kleinste ingreep die de échte schade wegneemt: niet meer stil herschrijven wat de gebruiker niet heeft aangeraakt. Hoe diep de knop mag komen is daarmee een aparte vraag, die later los te beantwoorden is. De dubbeltelling blijft staan en is vastgelegd in het commentaar bij de constante. ## Toetsing Beide reparaties zijn één keer teruggezet; precies hun eigen test viel, en niets anders: - `een niveau dieper dan de knop kan, blijft staan als je iets anders typt` — valt zodra het lezen weer klemt. - `TreeEditor een dieper niveau blijft staan en springt met één stap uit` — valt zodra `_indent` weer met `clamp(0, _maxLevel)` werkt. ## Bewaker Bewust overgeslagen: raakt het bestandsformaat niet (tabs blijven de opslagvorm en er verandert niets aan wat er weggeschreven wordt), geen opslag, geen afhankelijkheid, geen uitgaand verkeer, geen publieke belofte. Wel raakte het gebrek de *inhoud* van bestaande decks — die schade is nu juist wat verdwijnt. ## Poorten `make check` groen (exit 0, 9801 tests, dekking 87,0%, per-bestandsvloer 0), `make check-secrets` groen (geen lekken), `make sast` groen (0 bevindingen). DAST niet gedraaid — geen geserveerd oppervlak geraakt. Closes #1558
De opsommingseditors klemden het niveau al bij het lezen op hun maximum, en
_emit schreef dat geklemde niveau weer terug. Eén letter typen in het eerste
item liet daarmee een dieper item zakken — een regel die de gebruiker niet had
aangeraakt, in een editor die hij alleen maar opende (#1558).

Dat trof geïmporteerde en geplakte lijsten. De parser rekent twee spaties per
niveau terwijl markdown doorgaans met vier wordt geschreven, dus vier zichtbare
niveaus staan intern op 0-2-4-6 — en 6 lag boven het plafond.

Lezen gebeurt nu ongeklemd, met dezelfde bulletLevel als de rest van de
codebase; de eigen _levelOf van beide editors kon weg. Alleen de knop begrenst
nog, via één gedeelde kMaxIndentButtonLevel naast bulletLevel, met de
aantekening dat het formaat, de parser, de dia-render en de HTML-export zélf
geen maximum kennen. Wat je niet zelf hebt gemaakt, maakt de editor niet stuk.

De boomeditor hield 6 aan waar de andere twee 4 deden, zonder dat dat ergens
besloten was; die loopt nu mee. Daar zat bovendien een eigen fout: _indent
klemde met clamp(0, _maxLevel), waardoor uitspringen vanaf niveau 6 met één klik
naar 4 sprong in plaats van naar 5. Uitspringen gaat nu altijd één stap.

Beide regressietests vallen zodra hun eigen reparatie eruit gaat.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
docs: het inspringniveau in de changelog
All checks were successful
scans / scans (pull_request) Successful in 1m51s
static-gate / static-gate (pull_request) Successful in 4m28s
2a92d76b16
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
brenno merged commit ff60cd3b49 into main 2026-08-18 21:05:14 +00:00
Sign in to join this conversation.
No description provided.