diff --git a/apps/client/src/widgets/find_in_code.ts b/apps/client/src/widgets/find_in_code.ts index 4e80f789e..a69ddd758 100644 --- a/apps/client/src/widgets/find_in_code.ts +++ b/apps/client/src/widgets/find_in_code.ts @@ -42,29 +42,11 @@ export default class FindInCode { async findNext(direction: number, currentFound: number, nextFound: number) { const codeEditor = await this.getCodeEditor(); - if (!codeEditor || !this.findResult) { + if (!codeEditor) { return; } - const doc = codeEditor.doc; - - // - // Dehighlight current, highlight & scrollIntoView next - // - - let marker = this.findResult[currentFound]; - let pos = marker.find(); - marker.clear(); - marker = doc.markText(pos.from, pos.to, { className: FIND_RESULT_CSS_CLASSNAME }); - this.findResult[currentFound] = marker; - - marker = this.findResult[nextFound]; - pos = marker.find(); - marker.clear(); - marker = doc.markText(pos.from, pos.to, { className: FIND_RESULT_SELECTED_CSS_CLASSNAME }); - this.findResult[nextFound] = marker; - - codeEditor.scrollIntoView(pos.from); + codeEditor.findNext(direction, currentFound, nextFound); } async findBoxClosed(totalFound: number, currentFound: number) { diff --git a/packages/codemirror/src/find_replace.ts b/packages/codemirror/src/find_replace.ts index c1f4410a7..857b572b3 100644 --- a/packages/codemirror/src/find_replace.ts +++ b/packages/codemirror/src/find_replace.ts @@ -33,11 +33,34 @@ export class SearchHighlighter { regexp: regex, decoration: searchMatchDecoration, }); - this.updateSearchData(this.view); - this.scrollToMatchNearestSelection(); + this.#updateSearchData(this.view); + this.#scrollToMatchNearestSelection(); } - updateSearchData(view: EditorView) { + scrollToMatch(matchIndex: number) { + if (this.parsedMatches.length <= matchIndex) { + return; + } + + const match = this.parsedMatches[matchIndex]; + this.currentFound = matchIndex + 1; + this.view.dispatch({ + effects: EditorView.scrollIntoView(match.from, { y: "center" }), + scrollIntoView: true + }); + } + + update(update: ViewUpdate) { + if (update.docChanged || update.viewportChanged) { + this.#updateSearchData(update.view); + } + } + + destroy() { + // Do nothing. + } + + #updateSearchData(view: EditorView) { if (!this.matcher) { return; } @@ -56,26 +79,7 @@ export class SearchHighlighter { this.totalFound = this.parsedMatches.length; } - update(update: ViewUpdate) { - if (update.docChanged || update.viewportChanged) { - this.updateSearchData(update.view); - } - } - - scrollToMatch(matchIndex: number) { - if (this.parsedMatches.length <= matchIndex) { - return; - } - - const match = this.parsedMatches[matchIndex]; - this.currentFound = matchIndex + 1; - this.view.dispatch({ - effects: EditorView.scrollIntoView(match.from, { y: "center" }), - scrollIntoView: true - }); - } - - scrollToMatchNearestSelection() { + #scrollToMatchNearestSelection() { const cursorPos = this.view.state.selection.main.head; let index = 0; for (const match of this.parsedMatches) { @@ -88,10 +92,6 @@ export class SearchHighlighter { } } - destroy() { - // Do nothing. - } - static deco = (v: SearchHighlighter) => v.matches; } diff --git a/packages/codemirror/src/index.ts b/packages/codemirror/src/index.ts index 64f333d80..cbf12c2d5 100644 --- a/packages/codemirror/src/index.ts +++ b/packages/codemirror/src/index.ts @@ -1,5 +1,5 @@ import { defaultKeymap, history, historyKeymap } from "@codemirror/commands"; -import { EditorView, highlightActiveLine, keymap, lineNumbers, placeholder, ViewUpdate, type EditorViewConfig } from "@codemirror/view"; +import { EditorView, highlightActiveLine, keymap, lineNumbers, placeholder, ViewPlugin, ViewUpdate, type EditorViewConfig } from "@codemirror/view"; import { defaultHighlightStyle, StreamLanguage, syntaxHighlighting, indentUnit, bracketMatching, foldGutter } from "@codemirror/language"; import { Compartment, EditorSelection, EditorState, type Extension } from "@codemirror/state"; import { highlightSelectionMatches } from "@codemirror/search"; @@ -7,7 +7,7 @@ import { vim } from "@replit/codemirror-vim"; import byMimeType from "./syntax_highlighting.js"; import smartIndentWithTab from "./extensions/custom_tab.js"; import type { ThemeDefinition } from "./color_themes.js"; -import { createSearchHighlighter, searchMatchHighlightTheme } from "./find_replace.js"; +import { createSearchHighlighter, SearchHighlighter, searchMatchHighlightTheme } from "./find_replace.js"; export { default as ColorThemes, type ThemeDefinition, getThemeById } from "./color_themes.js"; @@ -31,6 +31,7 @@ export default class CodeMirror extends EditorView { private themeCompartment: Compartment; private lineWrappingCompartment: Compartment; private searchHighlightCompartment: Compartment; + private searchPlugin?: SearchHighlighter | null; constructor(config: EditorConfig) { const languageCompartment = new Compartment(); @@ -181,6 +182,7 @@ export default class CodeMirror extends EditorView { await new Promise(requestAnimationFrame); const instance = this.plugin(plugin); instance?.searchFor(searchTerm, matchCase, wholeWord); + this.searchPlugin = instance; return { totalFound: instance?.totalFound ?? 0, @@ -188,6 +190,10 @@ export default class CodeMirror extends EditorView { } } + async findNext(direction: number, currentFound: number, nextFound: number) { + this.searchPlugin?.scrollToMatch(nextFound); + } + async setMimeType(mime: string) { let newExtension: Extension[] = [];