fix(editor): honor configured shortcut precedence

This commit is contained in:
t8y2 2026-07-27 15:40:15 +08:00
parent ed47877723
commit 267310ced1
No known key found for this signature in database
3 changed files with 25 additions and 8 deletions

View File

@ -1371,6 +1371,11 @@ function runKeymapExtension(codeMirrorKeymap: (typeof import("@codemirror/view")
if (sql.trim()) emit("sendSelectionToAi", sql);
return true;
}),
...createQueryEditorSearchKeymap({
openSearch,
openReplace,
isReadOnly: () => !!props.readOnly,
}),
]),
) ?? [],
codeMirrorKeymap.of(
@ -3731,11 +3736,6 @@ onMounted(async () => {
buildResultSourceRangeExtension(),
Prec.highest(
keymap.of([
...createQueryEditorSearchKeymap({
openSearch,
openReplace,
isReadOnly: () => !!props.readOnly,
}),
{ key: "'", run: handleSqlSingleQuote },
{ key: "Tab", run: handleTab },
{

View File

@ -40,7 +40,8 @@ describe("QueryEditor search shortcuts", () => {
});
it("keeps the existing search navigation and read-only replace guards", () => {
expect(queryEditorSource).toMatch(/Prec\.highest\(\s*keymap\.of\(\[\s*\.\.\.createQueryEditorSearchKeymap/);
expect(queryEditorSource).toMatch(/\.\.\.binding\(shortcuts\.sendSelectionToAi[\s\S]*\.\.\.createQueryEditorSearchKeymap/);
expect(queryEditorSource).not.toMatch(/Prec\.highest\(\s*keymap\.of\(\[\s*\.\.\.createQueryEditorSearchKeymap/);
expect(queryEditorSource).toMatch(/function openReplace\(\): boolean \{\s*if \(props\.readOnly\) return false;/);
expect(contentAreaSource).toContain('if (props.activeTab.mode === "query") return queryEditorRef.value?.openSearch() ?? false;');
expect(contentAreaSource).toContain("return queryEditorRef.value?.openReplace() ?? false;");

View File

@ -6,13 +6,29 @@ import { describe, expect, it, vi } from "vitest";
import { createQueryEditorSearchKeymap } from "@/lib/editor/queryEditorSearchKeymap";
describe("QueryEditor search keymap precedence", () => {
it("runs the custom search binding before lower-priority CodeMirror bindings", () => {
it("runs configured editor actions before the built-in search fallback", () => {
const formatSql = vi.fn(() => true);
const openSearch = vi.fn(() => true);
const view = new EditorView({
parent: document.createElement("div"),
state: EditorState.create({
extensions: [Prec.high(keymap.of([{ key: "Mod-f", run: formatSql }, ...createQueryEditorSearchKeymap({ openSearch, openReplace: () => true, isReadOnly: () => false })]))],
}),
});
expect(runScopeHandlers(view, new KeyboardEvent("keydown", { key: "f", ctrlKey: true }), "editor")).toBe(true);
expect(formatSql).toHaveBeenCalledOnce();
expect(openSearch).not.toHaveBeenCalled();
view.destroy();
});
it("keeps the search fallback above lower-priority CodeMirror bindings", () => {
const openSearch = vi.fn(() => true);
const lowerPrioritySearch = vi.fn(() => true);
const view = new EditorView({
parent: document.createElement("div"),
state: EditorState.create({
extensions: [keymap.of([{ key: "Mod-f", run: lowerPrioritySearch }]), Prec.highest(keymap.of(createQueryEditorSearchKeymap({ openSearch, openReplace: () => true, isReadOnly: () => false })))],
extensions: [keymap.of([{ key: "Mod-f", run: lowerPrioritySearch }]), Prec.high(keymap.of(createQueryEditorSearchKeymap({ openSearch, openReplace: () => true, isReadOnly: () => false })))],
}),
});