feat: add shortcut for accepting completion and update related functionality

This commit is contained in:
t8y2 2026-05-26 16:59:22 +08:00
parent 551339cd22
commit 94487384e1
7 changed files with 54 additions and 5 deletions

View File

@ -164,6 +164,8 @@ let buildSqlDiagnosticExtension: (() => import("@codemirror/state").Extension) |
let buildSqlSignatureExtension: (() => import("@codemirror/state").Extension) | null = null;
let codeMirrorSnippetCompletion: typeof import("@codemirror/autocomplete").snippetCompletion;
let codeMirrorCompletionStatus: typeof import("@codemirror/autocomplete").completionStatus | null = null;
let codeMirrorAcceptCompletion: typeof import("@codemirror/autocomplete").acceptCompletion | null = null;
let codeMirrorIndentMore: typeof import("@codemirror/commands").indentMore | null = null;
let setSqlDiagnosticsEffect: import("@codemirror/state").StateEffectType<SqlSemanticDiagnostic[]> | null = null;
let semanticDiagnostics: SqlSemanticDiagnostic[] = [];
let semanticDiagnosticTimer: ReturnType<typeof setTimeout> | null = null;
@ -187,8 +189,6 @@ function syncEditorFontCssVars(fontSize = liveFontSize.value, fontFamily = setti
if (!editorRef.value) return;
editorRef.value.style.setProperty(EDITOR_FONT_SIZE_CSS_VAR, `${clampEditorFontSize(fontSize)}px`);
editorRef.value.style.setProperty(EDITOR_FONT_FAMILY_CSS_VAR, fontFamily);
const cm = editorRef.value.querySelector(".cm-editor") as HTMLElement | null;
if (cm) cm.style.lineHeight = "1.6";
}
let pendingFontReconfig: { size: number; family: string } | null = null;
@ -272,6 +272,18 @@ function onEditorGestureEnd(event: Event) {
zoomCommitScheduler.flush(liveFontSize.value);
}
function handleTab(view: EditorViewType): boolean {
if (codeMirrorCompletionStatus?.(view.state) === "active") return false;
const { state, dispatch } = view;
const sel = state.selection.main;
if (!sel.empty) return codeMirrorIndentMore?.(view) ?? false;
const line = state.doc.lineAt(sel.from);
const before = line.text.slice(0, sel.from - line.from);
if (/^\s*$/.test(before)) return codeMirrorIndentMore?.(view) ?? false;
dispatch(state.update(state.replaceSelection(" "), { userEvent: "input.type" }));
return true;
}
function runKeymapExtension(codeMirrorKeymap: (typeof import("@codemirror/view"))["keymap"]) {
const shortcuts = settingsStore.editorSettings.shortcuts;
return codeMirrorKeymap.of([
@ -319,6 +331,10 @@ function runKeymapExtension(codeMirrorKeymap: (typeof import("@codemirror/view")
return true;
},
},
{
key: shortcutToCodeMirrorKey(shortcuts.acceptCompletion),
run: (view) => codeMirrorAcceptCompletion?.(view) ?? false,
},
]);
}
@ -897,8 +913,16 @@ onMounted(async () => {
{ EditorState, Compartment, Prec, StateEffect, StateField },
{ sql, MSSQL, MySQL, PostgreSQL, SQLDialect },
{ basicSetup },
{ autocompletion, startCompletion, closeBrackets, closeBracketsKeymap, snippetCompletion, completionStatus },
{ indentWithTab },
{
autocompletion,
startCompletion,
acceptCompletion,
closeBrackets,
closeBracketsKeymap,
snippetCompletion,
completionStatus,
},
{ indentMore },
{ bracketMatching },
] = await Promise.all([
import("@codemirror/view"),
@ -919,6 +943,8 @@ onMounted(async () => {
diagnosticComp = new Compartment();
setSqlDiagnosticsEffect = StateEffect.define<SqlSemanticDiagnostic[]>();
codeMirrorCompletionStatus = completionStatus;
codeMirrorAcceptCompletion = acceptCompletion;
codeMirrorIndentMore = indentMore;
const diagnosticTheme = EditorView.baseTheme({
".cm-sql-error": {
@ -1013,7 +1039,7 @@ onMounted(async () => {
hoverTooltip((currentView, pos) => resolveSqlHoverTooltip(currentView, pos)),
buildSqlSignatureExtension(),
diagnosticComp.of(buildSqlDiagnosticExtension()),
Prec.highest(keymap.of([...closeBracketsKeymap, indentWithTab])),
Prec.highest(keymap.of([...closeBracketsKeymap, { key: "Tab", run: handleTab }])),
runKeymapComp.of(runKeymapExtension(keymap)),
wordWrapComp.of(props.forceWordWrap || ss.wordWrap ? EditorView.lineWrapping : []),
readOnlyComp.of([EditorState.readOnly.of(!!props.readOnly), EditorView.editable.of(!props.readOnly)]),

View File

@ -1371,6 +1371,7 @@ export default {
redisScanPageSizeOption: "{count} keys",
shortcutExecuteSql: "Execute SQL",
shortcutSaveSql: "Save SQL",
shortcutAcceptCompletion: "Accept completion",
shortcutCopyCurrentRow: "Copy current data row",
shortcutDeleteCurrentRow: "Delete current data row",
shortcutNewQuery: "New query",

View File

@ -1253,6 +1253,7 @@ export default {
redisScanPageSizeOption: "{count} claves",
shortcutExecuteSql: "Ejecutar SQL",
shortcutSaveSql: "Guardar SQL",
shortcutAcceptCompletion: "Aceptar completado",
shortcutCopyCurrentRow: "Copiar fila de datos actual",
shortcutDeleteCurrentRow: "Eliminar fila de datos actual",
shortcutNewQuery: "Nueva consulta",

View File

@ -1345,6 +1345,7 @@ export default {
redisScanPageSizeOption: "{count} 个 Key",
shortcutExecuteSql: "执行 SQL",
shortcutSaveSql: "保存 SQL",
shortcutAcceptCompletion: "接受补全",
shortcutCopyCurrentRow: "复制当前数据行",
shortcutDeleteCurrentRow: "删除当前数据行",
shortcutNewQuery: "新建查询",

View File

@ -102,6 +102,15 @@ export function buildEditorFontThemeRules(
...(opts?.scrollable ? { ".cm-scroller": { overflow: "auto" } } : {}),
".cm-content": {
fontFamily: `var(${EDITOR_FONT_FAMILY_CSS_VAR}, ${defaults?.family ?? "monospace"})`,
lineHeight: "1.6",
padding: "0",
},
".cm-line": {
padding: "0 2px !important",
},
".cm-selectionLayer .cm-selectionBackground": {
transform: "scaleY(1.55)",
transformOrigin: "center",
},
".cm-gutters": {
borderRight: "0 !important",

View File

@ -96,6 +96,10 @@ export function isSaveShortcut(event: ShortcutLikeEvent, shortcuts?: Partial<Sho
return matchesShortcut(event, actionShortcut("saveSql", shortcuts));
}
export function isAcceptCompletionShortcut(event: ShortcutLikeEvent, shortcuts?: Partial<ShortcutSettings>): boolean {
return matchesShortcut(event, actionShortcut("acceptCompletion", shortcuts));
}
export function isObjectSourceSaveShortcutTarget(
target: { closest(selector: string): unknown } | null | undefined,
): boolean {

View File

@ -1,6 +1,7 @@
export type ShortcutActionId =
| "executeSql"
| "saveSql"
| "acceptCompletion"
| "copyCurrentRow"
| "deleteCurrentRow"
| "newQuery"
@ -34,6 +35,12 @@ export const SHORTCUT_DEFINITIONS: ShortcutDefinition[] = [
scope: "editor",
defaultShortcut: "Mod+S",
},
{
id: "acceptCompletion",
labelKey: "settings.shortcutAcceptCompletion",
scope: "editor",
defaultShortcut: "Tab",
},
{
id: "copyCurrentRow",
labelKey: "settings.shortcutCopyCurrentRow",