From 267310ced1d6073b3a84ff7d3e6d18bf4858fa50 Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Mon, 27 Jul 2026 15:40:15 +0800 Subject: [PATCH] fix(editor): honor configured shortcut precedence --- .../src/components/editor/QueryEditor.vue | 10 +++++----- .../__tests__/EditorSearchPanel.spec.ts | 3 ++- .../__tests__/QueryEditorSearchKeymap.spec.ts | 20 +++++++++++++++++-- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/apps/desktop/src/components/editor/QueryEditor.vue b/apps/desktop/src/components/editor/QueryEditor.vue index fb5faa9d8..9863cde25 100644 --- a/apps/desktop/src/components/editor/QueryEditor.vue +++ b/apps/desktop/src/components/editor/QueryEditor.vue @@ -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 }, { diff --git a/apps/desktop/src/components/editor/__tests__/EditorSearchPanel.spec.ts b/apps/desktop/src/components/editor/__tests__/EditorSearchPanel.spec.ts index ae5630035..5dd34f6dc 100644 --- a/apps/desktop/src/components/editor/__tests__/EditorSearchPanel.spec.ts +++ b/apps/desktop/src/components/editor/__tests__/EditorSearchPanel.spec.ts @@ -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;"); diff --git a/apps/desktop/src/components/editor/__tests__/QueryEditorSearchKeymap.spec.ts b/apps/desktop/src/components/editor/__tests__/QueryEditorSearchKeymap.spec.ts index 69c0d8da3..ec8f3ede0 100644 --- a/apps/desktop/src/components/editor/__tests__/QueryEditorSearchKeymap.spec.ts +++ b/apps/desktop/src/components/editor/__tests__/QueryEditorSearchKeymap.spec.ts @@ -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 })))], }), });