chore(code/find): jump to first result

This commit is contained in:
Elian Doran 2025-05-12 20:26:48 +03:00
parent f2745d546b
commit c4863dec50
No known key found for this signature in database
2 changed files with 47 additions and 6 deletions

View File

@ -1,8 +1,13 @@
import { EditorView, Decoration, MatchDecorator, ViewPlugin, ViewUpdate } from "@codemirror/view";
import { StateEffect, Compartment } from "@codemirror/state";
import { StateEffect, Compartment, EditorSelection, RangeSet } from "@codemirror/state";
const searchMatchDecoration = Decoration.mark({ class: "cm-searchMatch" });
interface Match {
from: number;
to: number;
}
export function createSearchHighlighter(view: EditorView, searchTerm: string, matchCase: boolean, wholeWord: boolean) {
// Escape the search term for use in RegExp
const escapedTerm = searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
@ -16,17 +21,49 @@ export function createSearchHighlighter(view: EditorView, searchTerm: string, ma
});
return ViewPlugin.fromClass(class SearchHighlighter {
matches = matcher.createDeco(view);
totalFound = this.matches.size;
matches!: RangeSet<Decoration>;
totalFound: number;
private parsedMatches: Match[];
constructor(public view: EditorView) { }
constructor(public view: EditorView) {
this.parsedMatches = [];
this.totalFound = 0;
this.updateSearchData(view);
}
updateSearchData(view: EditorView) {
const matches = matcher.createDeco(view);
const cursor = matches.iter();
while (cursor.value) {
this.parsedMatches.push({
from: cursor.from,
to: cursor.to
});
cursor.next();
}
this.matches = matches;
this.totalFound = this.parsedMatches.length;
}
update(update: ViewUpdate) {
if (update.docChanged || update.viewportChanged) {
this.matches = matcher.createDeco(update.view);
this.updateSearchData(update.view);
}
}
scrollToMatch(matchIndex: number) {
if (this.parsedMatches.length <= matchIndex) {
return;
}
const pos = this.parsedMatches[matchIndex];
this.view.dispatch({
effects: EditorView.scrollIntoView(pos.from, { y: "center" }),
scrollIntoView: true
});
}
destroy() {
// Do nothing.
}

View File

@ -176,9 +176,13 @@ export default class CodeMirror extends EditorView {
this.dispatch({
effects: this.searchHighlightCompartment.reconfigure(plugin)
});
// Wait for the plugin to activate in the next render cycle
await new Promise(requestAnimationFrame);
const instance = this.plugin(plugin); // TS workaround
const instance = this.plugin(plugin);
if (instance) {
instance.scrollToMatch(0);
}
return {
totalFound: instance?.totalFound ?? 0