Repository navigation
fix(muya): preserve ordered list source markers - #4776
Conversation
| this.createDomNode(); | ||
| } | ||
|
|
||
| private static _cloneMeta(meta: IListItemState['meta']): IListItemState['meta'] { |
There was a problem hiding this comment.
I prefer a util function rather than static method?
|
Thanks for the fix — the core intent is right and the no-edit open→save round-trip is correct and well-tested. I found one save-time crash that should block merge, plus a couple of edit-time numbering inconsistencies that stem from a single design choice, and two small cleanups. 1. Blocker —
|
|
Thanks for the detailed review. I pushed an update addressing these points. For the For the serializer issues: I changed the preservation model so source markers are only used for an unchanged parsed This should address:
I also added regression coverage for the DFM |
Upstream PRs applied (all diff-reviewed, tests included and passing): - marktext#4776: preserve ordered-list source markers — opening and saving no longer rewrites 1./1./1. to 1./2./3. (marktext#4772, silent doc mutation) - marktext#4788: UNC/WSL paths become valid file:// authority URLs (file://server/share/…, not file:////…) so network images load (marktext#4577, marktext#4563) - marktext#4952: table columns size to content (min-width 10em → 2em, marktext#4894) - marktext#4773: malformed percent-escape in a clicked link no longer throws an unhandled URIError (marktext#4749) - marktext#4873: Shift+digit/punctuation keybindings recordable and matchable again (patch-package fix for @hfelix/electron-localshortcut, marktext#4863) - marktext#4910: sidebar icons match by extension first, so Dockerfile-Notes.md gets the markdown icon (marktext#4890) - marktext#4317: restored windows are clamped to the target display's work area (multi-monitor / DPI, marktext#2928, marktext#1947) Found while integrating marktext#4776: cloneStateTree shallow-copied meta, so array-valued fields (order-list sourceMarkers, table aligns) stayed SHARED between a getState() clone and the live document — mutating a returned tree corrupted the document. Meta arrays are now copied, and the clone walks an explicit work list instead of recursing, so pathological nesting (600-level lists, marktext#4747) can no longer overflow the call stack (10k-depth regression test). Also: folder search debounces its per-keystroke ripgrep run (300ms, Enter searches immediately, IME-composing keys ignored) (marktext#3556), and a new undoFloor spec pins that undoing past the opened baseline never empties the document (marktext#5028 — legacy-engine bug, does not reproduce on @muyajs/core). muya 1536/1536, desktop 783/783, lint/tsc/madge clean. PLANS.md gains a prioritized backlog from the full 563-item issue/PR survey.
The previous case read `muya.getMarkdown()` straight after boot, which serializes the parsed JSON state without touching the block tree, so it passed even with the list-item meta dropped from `ListItem.getState()`. Replace the list with its clone first so the markers must survive the block round trip that loose-list toggling and indenting rely on. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01D3wiiczGv6VCkvm7egv6h1
`compatibleTaskList` already matches each ordered item's marker to derive the delimiter, so record the full marker on the token there instead of re-running a second regex over `item.raw` twice per item in `markdownToState`. Parsed states are unchanged. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01D3wiiczGv6VCkvm7egv6h1
`JSONState.getState()` and the serializer both deep-clone state, and nothing mutates `sourceMarkers` in place, so the dedicated clone helper guards nothing. Keep `OrderList` in line with `BulletList` and `TaskList`, which hold their meta by reference and shallow-copy it in `getState()`. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01D3wiiczGv6VCkvm7egv6h1
The serializer already clones each list's meta onto `_listType` and advances `start` on it per item. Drop `sourceMarkers` from that clone when the list no longer matches its parsed items and shift one marker per item, instead of widening the meta type with a preserve flag and a second counter that tracked `start`. Output is unchanged. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01D3wiiczGv6VCkvm7egv6h1
… reopen The marktext#5341 and marktext#5349 specs assert that the state after Tab or Shift+Tab equals the state the parser rebuilds from the saved markdown. Ordered lists now carry their parsed markers, and an edit leaves those describing the list as it was parsed, while reopening reparses fresh ones. Compare structure without the marker hints; the markdown is still required to round-trip unchanged. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01D3wiiczGv6VCkvm7egv6h1
|
Thanks for the rework — the fallback model fixes all five points from the first review. I pushed a few follow-up commits directly to the branch so this can land without another round trip:
Scope stays as you implemented it: authored markers are kept only while a parsed list is structurally unchanged, and any insert/delete/reorder renumbers from |
Closes #4772
Summary
Preserve ordered-list source markers when opening and saving Markdown.
Previously, MarkText parsed ordered lists into semantic list state but dropped each list item's original marker. The serializer then regenerated markers by incrementing the list-level
startvalue.For example:
could be saved back as:
That creates an avoidable diff for users who intentionally use repeated ordered-list markers, which is valid Markdown and common in source-oriented workflows.
This PR fixes the data-loss point directly:
MarkdownToStatenow records the original ordered marker for parser-created list items, the Muya list-item block preserves that metadata through the live editor tree, andStateToMarkdownuses the stored marker when serializing. List items without preserved marker metadata, such as newly created editor items or manually constructed state, still use the existing generated-number fallback.Type of change
Test plan
The following checks all passed:
The lint command reports existing complexity / regexp warnings, but 0 errors.
Manual verification used the #4772 Markdown fixture on Windows and confirmed the saved Markdown source still preserves
1. / 1. / 1.. The WYSIWYG view continues to render the ordered list visually as1, 2, 3, which is expected<ol>behavior and separate from source-marker preservation.Notes for reviewers [optional]
The root cause is that the state model only preserved ordered-list metadata at the list level:
That is enough to render an ordered list, but not enough to round-trip the Markdown source. After parsing, the editor no longer knew whether the original items were written as
1. / 1. / 1.,1. / 2. / 3.,10) / 20), or another valid marker sequence.The fix stores the source marker on parser-created list items:
StateToMarkdownnow serializes that marker when present. If no item-level marker exists, it keeps the previous behavior and generates markers fromorder-list.meta.start.This is intentionally source-preserving rather than a global formatting option. It does not force all ordered lists to use
1.and it does not change the editor's visual ordered-list rendering. The UI can still display semantic ordered lists as1, 2, 3; the saved Markdown source keeps the user's original markers.Regression coverage includes:
10) one/20) two.Muyablock-tree round-trip viamuya.getMarkdown(), ensuring the metadata is not lost after parsing into live editor blocks.By submitting this pull request, I confirm that my contribution is made under the terms of the MIT license).