{{ message }}
Repository navigation
fix(muya): keep the search highlight across a full re-render (#5651) - #5652
Merged
Merged
Conversation
`setOptions(options, true)` and `locale()` re-render every block through `Muya._forceRender()`, which rebuilt the tree without re-applying the active search. The find bar kept its count while every highlight span disappeared, for plain word searches and regexp searches alike. `Search.refresh()` now re-runs the remembered query on the new blocks and keeps the active match where it was. The block that also holds the caret is rendered once with both the cursor and its highlights — rendering it twice lets the highlight and the caret overwrite each other — leaving `_forceRender` to restore just the DOM selection.
Keep only the two comments the code cannot state on its own (why the caret is handed to `refresh`, why the stale matches are cleared first).
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Refreshed result counts can leave an invalid active index and are not synchronized with the desktop find UI.
2 open findings
What changed in this PR
Fixes search highlights disappearing after Muya performs a full re-render.
Changes:
- Re-runs active searches after full rendering.
- Preserves highlights, active match, and caret.
- Adds unit and browser regression tests.
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| const cursor: IRenderCursor | undefined = cursorBlock | ||
| ? { block: cursorBlock, anchor: { offset: begin }, focus: { offset: end } } | ||
| : undefined; | ||
| this.editor.searchModule.refresh(cursor); |
Comment on lines
+253
to
+257
| this.search(value, { | ||
| ...this._options, | ||
| highlightIndex: index >= 0 && index < matches.length ? index : -1, | ||
| selectHighlight: false, | ||
| }); |
) `Search.refresh()` re-ran the query but validated the active index against the matches it had just discarded, and it only updated the engine's live instance. The find bar renders a snapshot its own handlers own, so a parse-affecting toggle (e.g. `multilineBlockquote`, which stops `>>>` from being text) could leave a stale count and an index past the end — `1 / 0`. Clamp the index against the matches the new parse produced and emit `search-refreshed` so the desktop replaces its snapshot.
Contributor
|
Build artifacts for PR #5652: Run: https://github.com/marktext/marktext/actions/runs/37734779724 |
Jocs
force-pushed
the
fix/5651-search-highlight-survives-rerender
branch
from
October 8, 2026 05:51
15bab43 to
22844ea
Compare
Review of the refresh rework turned up two defects: - `search()` trusts `highlightIndex` unconditionally, but callers pass one from before the text changed — `replace()` rewrites the text and `refresh()` re-parses it — so a shrunk result set left the index past the end (`1 / 0` in the find bar, no active highlight). Clamp it to the last match the search produced, which covers both callers; `matches.length - 1` is already -1 when nothing matched. - `Muya._forceRender()` stopped re-rendering the caret's block, so the syntax markers around the caret stayed collapsed after a preference toggle. Restore that render, after the search refresh so the highlight pass cannot drop it again. Tests: the caret case no longer asserts a highlight survives in the caret's block (the caret render replaces it), and the e2e spec whose cases the unit spec already covered is gone. Also folds in the find-bar tidy-up (one `emptySearch()` default, dead comment removal), two desktop typo fixes and cSpell words.
Jocs
force-pushed
the
fix/5651-search-highlight-survives-rerender
branch
from
October 8, 2026 05:54
22844ea to
280d655
Compare
csells
added a commit
to csells/MarkText
that referenced
this pull request
Oct 13, 2026
…nder Upstream marktext#5651 (marktext#5652) re-runs Muya's search after a forced render and refreshes the find bar through `search-refreshed`. Core find paints its own highlights, so Muya now emits `force-rendered` and the editor repaints the current result on the re-created blocks. Stepping through matches also records the active match in the search snapshot, which a parse-affecting preference's refresh and Replace One act on; both used the first match before.
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.


Closes #5651
Summary
setOptions(options, true)andlocale()re-render every block throughMuya._forceRender(), which rebuilt the tree but never re-applied the active search. The find bar kept showing its count while everymu-highlight/mu-selectionspan disappeared — for plain word searches and regexp searches alike. So toggling e.g. Preferences → Markdown → "将软换行视为空格" mid-search wiped the highlight.Search.refresh()now re-runs the remembered query against the rebuilt blocks and keeps the active match where it was. The block that also holds the caret is rendered once with both the cursor and its highlights — rendering it twice lets the highlight and the caret overwrite each other — so_forceRenderrestores only the DOM selection.Type of change
Test plan
New tests added (or explain why not needed)
Manually tested on:
Unit (
src/search/__tests__/searchSurvivesRerender.spec.ts): a word search keeps its highlight and active index acrosssetOptions(..., true); the rebuilt blocks are the ones re-highlighted; a closed find bar is not resurrected; the caret survives when its block also holds the active match.E2E (
e2e/tests/editing/search-rerender-highlight.spec.ts): the same two scenarios in a real browser, asserting both the highlight spans andwindow.getSelection().Both specs fail without the fix (verified by stashing the source changes).
pnpm -C packages/muya exec vitest run— 2433 passing;lint/lint:typesclean;tests/editinge2e green.Notes for reviewers [optional]
The search highlight is re-applied only when a query is active, so
_forceRenderkeeps its old behaviour when the find bar is closed._optionsstores the last query's options so the re-run reproduces the original flags (case sensitivity, whole word, regexp).By submitting this pull request, I confirm that my contribution is made under the terms of the MIT license.