Repository navigation
fix: #4899 keep trailing content out of the child list when outdenting a list item - #4913
Merged
Jocs merged 1 commit intoSep 14, 2026
Merged
Conversation
niyo-oyin
added a commit
to niyo-oyin/marktext-ja
that referenced
this pull request
Jul 29, 2026
- PR marktext#4946 (includes its base PR marktext#4942): removes the quadratic costs that froze large documents and mounts them progressively — a 2.1 MB document goes from an indefinite freeze to interactive in seconds. Applied verbatim; upstream review addressed 19 findings with 31 regression tests, all passing here. - PR marktext#4931 (marktext#4926): deleting at an offset inside a surrogate pair left a lone surrogate that crashed text-unicode ("Invalid offset - splits unicode bytes"). The content.ts hunk conflicted with our Phase 1 isComposed guards and was integrated by hand; the new cursor snap additionally runs only when no IME composition is open, since moving the DOM selection mid-composition would detach the IME anchor. - PR marktext#4913 (marktext#4899): Shift+Tab outdent with trailing sibling blocks corrupted the state tree (paragraphs appended directly into a list), crashing the next composed op. muya hunks only — the PR's legacy muyajs hunks target the removed engine. - PR marktext#4911 skipped: the equivalent detached-block guard already exists in @muyajs/core's language selector (marktext#4654), verified in source. - PR marktext#4930 (marktext#4921): CodeMirror instance wrapped in a Vue proxy broke source-code mode; markRaw fix applied cleanly. muya suite 1515/1515, tsc/eslint/madge clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ef4yFuXFbyKNTazkwUtygY
niyo-oyin
added a commit
to niyo-oyin/marktext-ja
that referenced
this pull request
Jul 29, 2026
- PR marktext#4946 (includes its base PR marktext#4942): removes the quadratic costs that froze large documents and mounts them progressively — a 2.1 MB document goes from an indefinite freeze to interactive in seconds. Applied verbatim; upstream review addressed 19 findings with 31 regression tests, all passing here. - PR marktext#4931 (marktext#4926): deleting at an offset inside a surrogate pair left a lone surrogate that crashed text-unicode ("Invalid offset - splits unicode bytes"). The content.ts hunk conflicted with our Phase 1 isComposed guards and was integrated by hand; the new cursor snap additionally runs only when no IME composition is open, since moving the DOM selection mid-composition would detach the IME anchor. - PR marktext#4913 (marktext#4899): Shift+Tab outdent with trailing sibling blocks corrupted the state tree (paragraphs appended directly into a list), crashing the next composed op. muya hunks only — the PR's legacy muyajs hunks target the removed engine. - PR marktext#4911 skipped: the equivalent detached-block guard already exists in @muyajs/core's language selector (marktext#4654), verified in source. - PR marktext#4930 (marktext#4921): CodeMirror instance wrapped in a Vue proxy broke source-code mode; markRaw fix applied cleanly. muya suite 1515/1515, tsc/eslint/madge clean.
…utdenting Shift+Tab on a nested list item whose list had trailing sibling blocks appended those blocks (paragraphs) directly into the new nested child list without a list-item wrapper. The state became schema-invalid, and the next edit's composed op crashed ot-json1 with 'Cannot use numerical key for object container'. Trailing blocks after the nested list are the outdented item's own content — append them to the new list item itself, and only create the child list for remaining sibling list items. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Jocs
force-pushed
the
fix/4899-list-outdent-merge-crash
branch
from
September 14, 2026 06:01
edece74 to
f8f5999
Compare
Member
|
Thanks @doktorigi — the outdent fix is correct. I rebased the branch onto
|
This was referenced Sep 14, 2026
Closed
Closed
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Fixes #4899 — and very likely explains #4826/#4827, which were closed as unreproducible. Following the reporter's keystrokes in a Playwright run against the e2e host page reproduces the exact crash deterministically:
Root cause
Instrumenting
JSONState._flushOperationCacheduring the repro shows the state is already schema-invalid one flush before the crash. The Shift+Tab outdent (_unindentListItem,UnindentType.INDENT) produced:{ "name": "bullet-list", "children": [ { "name": "paragraph", "text": "c" } ] }— a paragraph as a direct child of a list block, no
list-itemwrapper.In
packages/muya/src/block/content/paragraphContent/index.ts, the INDENT branch handles two kinds of leftovers when outdenting an item:listItem.next— remaining sibling list items, which correctly move into a freshly created nested child list; andlist.next— blocks that followed the nested list inside the outer item (paragraphs etc.), which are the outdented item's own trailing content — but were appended into that same child list.ot-json1 doesn't validate the schema, so the corrupt insert applies cleanly; the next edit (the reporter's final Backspace) then produces ops whose composed paths descend into a block object with a numeric array index, which ot-json1 rejects — the deferred flush throws and the renderer reports the crash. That downstream-flush distance is presumably why #4827 was so hard to reproduce.
Fix
Append
list.nextblocks to the new list item itself, and only create the nested child list when there are sibling list items (listItem.next) to carry. Foroutdenting
bnow yieldscas trailing content of the new- bitem (previously: a corrupt list). A side benefit: the outdent no longer leaves an emptybullet-listbehind when there are no sibling items.Tests
unindentTrailingContent.spec.ts, boots real Muya in happy-dom like the existingunindentReplacement.spec.ts): outdent with trailing paragraphs, and with both sibling items + trailing paragraphs; asserts every list child is a list item and the markdown keepscunder the outdented item. Both fail without the fix withbullet-list child must be a list item, got paragraph.list-paste-outdent-4899.spec.ts): replays the reporter's exact keystrokes (pastea\n\nb\n\ncinto a fresh list,-a line up, Shift+Tab, ↓, Backspace) and asserts no renderer errors and no content loss. Fails without the fix with the exactCannot use numerical key for object container.muya unit suite: 1439 passed (1 pre-existing unrelated failure in
tableChessboard.spec.ts, fails on clean develop too). muyalint,lint:types,check-circularpass. e2e stability/typing/editing groups: no new failures (2 pre-existing env-dependent failures on this Windows machine, identical on clean develop).🤖 Generated with Claude Code