Bold wrapping a code span came back inverted: ``**`B93934206`**``
serialized to `` `**B93934206**` ``, turning bold text into literal
asterisks.
ProseMirror ranks a text node's marks by schema order, which Tiptap
derives from extension priority, so the parser's correct order was
renormalized. Raise code above emphasis; link stays below code so
linked code labels keep serializing.
The upstream tokenizer matched `$([^$]+)$` with no delimiter rule, so a
second dollar sign anywhere in the paragraph turned prose into a math
span: `Costs are US$ 5,000 and R$ 40,000` lost the space after `US$`.
Require a non-space next to each delimiter and forbid a newline inside,
matching the common dialect. Real math still parses.
A file saved by an earlier Orca version carries class="orca-details"
in its markdown source. The prior commit stopped the serializer from
ever writing that class, which also stopped it from preserving one a
source already had, so re-saving such a file dropped the class and
the round-trip eligibility check then failed to recognize the file as
its own, regressing it back to Source mode. The details node now
carries a flag set only when its source opening tag had the class, and
the serializer re-emits the class only when that flag is set.
The markdown serializer always injected class="orca-details" into
saved <details> tags. The rich-mode round-trip check compares the
serialized output against the source's literal opening tag, so any
user-authored <details> without that class failed the comparison and
fell back to Source mode, making the details extension unreachable
from a file. The class is already applied to the rendered DOM node
independently, so the serializer no longer needs to write it into the
markdown source.
The nested (?:[ >]*(...)?)* quantifier let a long run of leading
spaces or > with no closing [ trigger catastrophic backtracking,
freezing the renderer on any document with such a line. Replace it
with a single non-nested character class, which is linear and safe
to over-admit since the parser confirms every candidate.
hasLinkReferenceDefinition ran a full remark parse on every content
change with no size guard, unlike the HTML round-trip check beside it.
Above the same 50,000-char cap, the pre-filter match is now trusted as
a definition, keeping rich mode blocked rather than risking an
unparsed document opening in it.
The pre-filter only matched one list-or-blockquote transition, so a
definition under e.g. list-then-blockquote or three-level nesting
skipped the parser confirmation and rich mode stayed on for content it
cannot round-trip.
The reference-links check only looked for a line starting with
[label]: followed by non-whitespace, so prose like "[Bug]: steps to
reproduce…" tripped rich-mode's fallback to Source mode. CommonMark
only treats [label]: as a link reference definition when the rest of
the line is a destination plus optional title, so detection now
parses the document with remark-parse/remark-gfm and checks for an
mdast definition node instead of guessing the shape with regex.
Re-parse each block after serialize and keep the candidate that still
matches the document, preferring fewer escapes. Restores \# / 1. / \| /
\$HOME\$ / link dests that 3.31.3's escapeMarkdownSyntax drops.
Co-authored-by: averydev <averybloom@gmail.com>
Align the canonical diff inputs with the source final newline when getMarkdown omits it, so EOF edits land before that newline and keep untouched source bytes. Preserve the source line-ending style on every canonical fallback.
Co-authored-by: averydev <averybloom@gmail.com>
The closing-fence pattern used `\s`, which also matches non-ASCII
whitespace such as U+00A0. A closer followed by one ended the fenced
range early, so a `<details>` block still inside the fence reached the
details tokenizer and was rewritten as editable markup.
The 1000ms ceiling passed even with the early return removed, since the
guarded per-paragraph scans cost far less than the bound on this input.
Assert markdownFenceRanges/markdownCodeSpanRanges call counts instead:
zero for a toggle-free document, one per call whose remaining source
holds the toggle. The wall-clock check survives as an opt-in benchmark
gated by ORCA_DETAILS_SCAN_BENCH, matching this repo's existing
bench-test convention.
# Conflicts:
# src/renderer/src/components/editor/markdown-scan-ranges.test.ts
The nested-toggle strip handed a <details> candidate inside a code span
to the block matcher, which consumed the span's closing tag and left the
containing block unmatched. The editability sweep then rejected any
remaining tag-shaped text, so a body quoting details markup fell back to
passthrough HTML.
A backtick inside a fenced block paired with a later prose backtick,
producing a span that covered everything between and hid any <details>
block in that stretch from the tokenizer.
The details markdown extension registered a bare `<details` string as
its marked start hook, which @tiptap/markdown turns into a raw
indexOf scan over unlexed block source. A `<details>` mention inside
backtick code spans or fenced code therefore split the surrounding
paragraph and let marked's own HTML-block rule swallow the remaining
prose into a details node, corrupting the saved file.
findDetailsBlockStart replaces the literal start hook with a scan that
skips fenced and code-span ranges and requires the tag to open a line
per CommonMark's HTML-block rule. matchDetailsHtmlBlock's tag-depth
pairing scan gets the same code-span exclusion, fixing a related gap
where a </details>-shaped code span inside a real block's body could
close the tag pairing early.
The scanning helpers move to markdown-scan-ranges.ts to keep
details-markdown-html.ts under the project's max-lines limit.
# Conflicts:
# src/renderer/src/components/editor/details-markdown-html.ts
* fix(editor): keep an unresolvable mirrored file tab open with a truthful terminal state
A host-mirrored file whose read keeps answering `selector_not_found` used
to sit on the raw code forever (and, in the reverted #21363, was closed
outright, discarding drafts). `selector_not_found` is the host's "could
not resolve right now", not proof the workspace is gone, and the file-read
path has no definitive absence code.
Bound the retries as before, then swap in a truthful terminal message
with Retry and Close tab. The tab is never closed automatically; Close
routes through the unsaved-changes queue so a dirty draft is confirmed.
Fixes#21041
* fix(editor): classify selector_not_found by RPC code, not message text
Preserve `RuntimeRpcCallError.code` on `FileContent.loadErrorCode` and gate
the host-unresolved terminal transition with `hasRuntimeRpcErrorCode`, so a
host that sends `{ code: 'selector_not_found', message: 'Selector not found' }`
reaches the same truthful state as one that puts the bare token on the
message. Also drop the Close action on inline conflict-review rows, which
are not open tabs and would have been a dead control.
* fix(editor): localize the host-unresolved copy by sentinel, and pin the token matcher
Separate the terminal state's comparison key from its display text: the
retry hook stores `WORKTREE_HOST_UNRESOLVED_CODE` on `loadErrorCode`, and
the error view localizes by that code (`editor.fileLoad.hostUnresolved`),
so translating the message can never break the terminal check. Export the
selector_not_found matcher and cover near misses (case, suffix, prose,
wrong code) so only the defined token classifies.
* test(editor): name the it.each parameter for the host answer it labels
* fix(editor): drop the load-error Close action; closing stays with the tab strip
The Close button routed through `requestEditorFileClose`, which skips the
pinned-tab and shared-reference checks the tab strip applies, has no
listener outside the Terminal workbench (floating editor panels), and on
the conflict-review overview could target an unrelated open tab whose id
is the same absolute path as a synthesized inline row. Rather than
reimplement the tab strip's close semantics in a second place, the error
view keeps Retry and its copy points the user at closing the tab.
* fix(editor): reword the host-unresolved copy and namespace its sentinel
The copy no longer points at a Close control that is gone ("close this
tab from the tab strip") and no longer claims a scan is in progress, since
`selector_not_found` is also thrown synchronously for unregistered folder
workspaces and removed repos. The sentinel becomes
`editor_host_workspace_unresolved` so it cannot be confused with the CLI's
`worktree_host_unresolved` client error. The doc comment narrows the
"no definitive absence code" claim to git worktrees and names the two host
codes that are definitive but not yet classified.
Refs #21041