diff --git a/apps/desktop/src/components/editor/EditorSettingsDialog.vue b/apps/desktop/src/components/editor/EditorSettingsDialog.vue index 66d05e075e..e465db37ba 100644 --- a/apps/desktop/src/components/editor/EditorSettingsDialog.vue +++ b/apps/desktop/src/components/editor/EditorSettingsDialog.vue @@ -273,6 +273,7 @@ const editCustomThemes = ref([...settingsStore.editorSettings.cus const editActiveCustomThemeId = ref(settingsStore.editorSettings.activeCustomThemeId); const showThemeCustomizer = ref(false); const editExecuteMode = ref(settingsStore.editorSettings.executeMode); +const editExecuteAllOnBlankLine = ref(settingsStore.editorSettings.executeAllOnBlankLine); const editGlobalConnectTimeoutSecs = ref(settingsStore.editorSettings.globalConnectTimeoutSecs); const editGlobalQueryTimeoutSecs = ref(settingsStore.editorSettings.globalQueryTimeoutSecs); const editShowExecutionTargetPicker = ref(settingsStore.editorSettings.showExecutionTargetPicker); @@ -444,6 +445,7 @@ function currentEditorSettingsDraft(): EditorSettingsDraft { customThemes: editCustomThemes.value, activeCustomThemeId: editActiveCustomThemeId.value, executeMode: editExecuteMode.value, + executeAllOnBlankLine: editExecuteAllOnBlankLine.value, globalConnectTimeoutSecs: editGlobalConnectTimeoutSecs.value, globalQueryTimeoutSecs: editGlobalQueryTimeoutSecs.value, showExecutionTargetPicker: editShowExecutionTargetPicker.value, @@ -714,6 +716,7 @@ function syncEditorSettingsDraftFromStore() { editCustomThemes.value = [...settingsStore.editorSettings.customThemes]; editActiveCustomThemeId.value = settingsStore.editorSettings.activeCustomThemeId; editExecuteMode.value = settingsStore.editorSettings.executeMode; + editExecuteAllOnBlankLine.value = settingsStore.editorSettings.executeAllOnBlankLine; editGlobalConnectTimeoutSecs.value = settingsStore.editorSettings.globalConnectTimeoutSecs; editGlobalQueryTimeoutSecs.value = settingsStore.editorSettings.globalQueryTimeoutSecs; editShowExecutionTargetPicker.value = settingsStore.editorSettings.showExecutionTargetPicker; @@ -929,6 +932,7 @@ function resetDefaultsForTab(tab: SettingsCategory) { editFontFamily.value = DEFAULT_EDITOR_SETTINGS.fontFamily; editFontSize.value = DEFAULT_EDITOR_SETTINGS.fontSize; editExecuteMode.value = DEFAULT_EDITOR_SETTINGS.executeMode; + editExecuteAllOnBlankLine.value = DEFAULT_EDITOR_SETTINGS.executeAllOnBlankLine; editGlobalConnectTimeoutSecs.value = DEFAULT_EDITOR_SETTINGS.globalConnectTimeoutSecs; editGlobalQueryTimeoutSecs.value = DEFAULT_EDITOR_SETTINGS.globalQueryTimeoutSecs; editShowExecutionTargetPicker.value = DEFAULT_EDITOR_SETTINGS.showExecutionTargetPicker; @@ -1024,6 +1028,7 @@ function resetAllDefaults() { editCustomThemes.value = [...DEFAULT_EDITOR_SETTINGS.customThemes]; editActiveCustomThemeId.value = DEFAULT_EDITOR_SETTINGS.activeCustomThemeId; editExecuteMode.value = DEFAULT_EDITOR_SETTINGS.executeMode; + editExecuteAllOnBlankLine.value = DEFAULT_EDITOR_SETTINGS.executeAllOnBlankLine; editGlobalConnectTimeoutSecs.value = DEFAULT_EDITOR_SETTINGS.globalConnectTimeoutSecs; editGlobalQueryTimeoutSecs.value = DEFAULT_EDITOR_SETTINGS.globalQueryTimeoutSecs; editShowExecutionTargetPicker.value = DEFAULT_EDITOR_SETTINGS.showExecutionTargetPicker; @@ -3621,6 +3626,16 @@ onUnmounted(() => { +
+
+ +

+ {{ t("settings.executeAllOnBlankLineDescription") }} +

+
+ +
+
diff --git a/apps/desktop/src/components/editor/QueryEditor.vue b/apps/desktop/src/components/editor/QueryEditor.vue index d318977093..4b59551c35 100644 --- a/apps/desktop/src/components/editor/QueryEditor.vue +++ b/apps/desktop/src/components/editor/QueryEditor.vue @@ -800,12 +800,21 @@ function requestExecuteFromView(currentView: EditorViewType, cursorPos: number, const doc = currentView.state.doc.toString(); const parameterOptions = sqlStatementParameterOptions(); const candidates = buildExecutionCandidates(doc, cursorPos, props.databaseType, parameterOptions); - if (candidates.length === 0) return true; + const executeMode = settingsStore.editorSettings.executeMode; + if (candidates.length === 0) { + if (executeMode === "current") toast(t("editor.noExecutableStatementAtCursor"), 3000); + return true; + } + const candidate = executionCandidateForMode(candidates, executeMode, { + executeAllOnBlankLine: settingsStore.editorSettings.executeAllOnBlankLine, + }); + if (!candidate) { + toast(t("editor.noExecutableStatementAtCursor"), 3000); + return true; + } // The execution shortcut keeps executing the configured target (cursor/all) directly: // it stays keyboard-driven and never pops the picker, which is reserved for click entry points. if (options.bypassPicker || !settingsStore.editorSettings.showExecutionTargetPicker || !hasMultipleExecutionTargets(doc, props.databaseType, parameterOptions)) { - const candidate = executionCandidateForMode(candidates, settingsStore.editorSettings.executeMode); - if (!candidate) return true; emitExecutionRequest(sqlExecutionSnapshotForRange(currentView, candidate), options.openInNewResultTab); return true; } diff --git a/apps/desktop/src/i18n/locales/en.ts b/apps/desktop/src/i18n/locales/en.ts index 412db6440b..7b2488fe72 100644 --- a/apps/desktop/src/i18n/locales/en.ts +++ b/apps/desktop/src/i18n/locales/en.ts @@ -1227,6 +1227,7 @@ export default { noResults: "No results", inSelection: "In selection", }, + noExecutableStatementAtCursor: "There is no executable statement at the cursor.", executionPicker: { title: "Execution Target", currentStatement: "Current SQL", @@ -5537,6 +5538,8 @@ export default { executeMode: "Execute Mode (Cmd+Enter)", executeModeAll: "Execute all SQL", executeModeCurrent: "Execute statement at cursor", + executeAllOnBlankLine: "Execute all SQL from blank lines", + executeAllOnBlankLineDescription: "In current-statement mode, execute all SQL when there is no statement at the cursor. Disabled by default.", showExecutionTargetPicker: "Show execution target picker", showExecutionTargetPickerDescription: "When enabled, running without a selection lets you choose between the current statement and all SQL.", showStatementRunButtons: "Show left-side run buttons", diff --git a/apps/desktop/src/i18n/locales/es.ts b/apps/desktop/src/i18n/locales/es.ts index 922ec4edc2..a9e3fb4871 100644 --- a/apps/desktop/src/i18n/locales/es.ts +++ b/apps/desktop/src/i18n/locales/es.ts @@ -1191,6 +1191,7 @@ export default withEnglishFallback({ noResults: "Sin resultados", inSelection: "En la selección", }, + noExecutableStatementAtCursor: "No hay ninguna sentencia ejecutable en la posición del cursor.", executionPicker: { title: "Execution Target", currentStatement: "Current SQL", @@ -5267,6 +5268,8 @@ export default withEnglishFallback({ executeMode: "Modo de ejecución (Cmd+Enter)", executeModeAll: "Ejecutar todo el SQL", executeModeCurrent: "Ejecutar sentencia en el cursor", + executeAllOnBlankLine: "Ejecutar todo el SQL desde líneas en blanco", + executeAllOnBlankLineDescription: "En el modo de sentencia actual, ejecuta todo el SQL cuando no hay una sentencia en el cursor. Desactivado de forma predeterminada.", showExecutionTargetPicker: "Mostrar selector de objetivo", showExecutionTargetPickerDescription: "Al activarlo, ejecutar sin selección permite elegir entre la sentencia actual y todo el SQL.", showStatementRunButtons: "Mostrar botones de ejecución laterales", diff --git a/apps/desktop/src/i18n/locales/it.ts b/apps/desktop/src/i18n/locales/it.ts index 801cb926a0..b753546b8f 100644 --- a/apps/desktop/src/i18n/locales/it.ts +++ b/apps/desktop/src/i18n/locales/it.ts @@ -1189,6 +1189,7 @@ export default withEnglishFallback({ noResults: "Nessun risultato", inSelection: "Nella selezione", }, + noExecutableStatementAtCursor: "Non è presente alcuna istruzione eseguibile in corrispondenza del cursore.", executionPicker: { title: "Execution Target", currentStatement: "Current SQL", @@ -5267,6 +5268,8 @@ export default withEnglishFallback({ executeMode: "Modalità Esecuzione (Cmd+Enter)", executeModeAll: "Esegui tutto l'SQL", executeModeCurrent: "Esegui istruzione al cursore", + executeAllOnBlankLine: "Esegui tutto l'SQL dalle righe vuote", + executeAllOnBlankLineDescription: "In modalità istruzione corrente, esegue tutto l'SQL quando non è presente un'istruzione al cursore. Disattivato per impostazione predefinita.", showExecutionTargetPicker: "Mostra selettore destinazione", showExecutionTargetPickerDescription: "Se attivo, l'esecuzione senza selezione permette di scegliere tra istruzione corrente e tutto l'SQL.", showStatementRunButtons: "Mostra pulsanti di esecuzione laterali", diff --git a/apps/desktop/src/i18n/locales/ja.ts b/apps/desktop/src/i18n/locales/ja.ts index cf3972d52b..0a95ebc61a 100644 --- a/apps/desktop/src/i18n/locales/ja.ts +++ b/apps/desktop/src/i18n/locales/ja.ts @@ -1209,6 +1209,7 @@ export default withEnglishFallback({ noResults: "結果なし", inSelection: "選択範囲内", }, + noExecutableStatementAtCursor: "カーソル位置に実行可能な文がありません。", executionPicker: { title: "Execution Target", currentStatement: "Current SQL", @@ -5296,6 +5297,8 @@ export default withEnglishFallback({ executeMode: "実行モード (Cmd+Enter)", executeModeAll: "すべてのSQLを実行", executeModeCurrent: "カーソル位置の文を実行", + executeAllOnBlankLine: "空行ではすべてのSQLを実行", + executeAllOnBlankLineDescription: "現在の文を実行するモードで、カーソル位置に文がない場合はすべてのSQLを実行します。既定では無効です。", showExecutionTargetPicker: "実行対象ピッカーを表示", showExecutionTargetPickerDescription: "有効にすると、選択なしで実行するときに現在の文とすべてのSQLを一時的に選べます。", showStatementRunButtons: "左側の実行ボタンを表示", diff --git a/apps/desktop/src/i18n/locales/ko.ts b/apps/desktop/src/i18n/locales/ko.ts index d7d0196882..36d15dac20 100644 --- a/apps/desktop/src/i18n/locales/ko.ts +++ b/apps/desktop/src/i18n/locales/ko.ts @@ -1117,6 +1117,7 @@ export default withEnglishFallback({ noResults: "결과 없음", inSelection: "선택 영역 내", }, + noExecutableStatementAtCursor: "커서 위치에 실행 가능한 구문이 없습니다.", executionPicker: { title: "실행 대상", currentStatement: "현재 SQL", @@ -5035,6 +5036,8 @@ export default withEnglishFallback({ executeMode: "실행 모드 (Cmd+Enter)", executeModeAll: "모든 SQL 실행", executeModeCurrent: "커서 위치의 구문 실행", + executeAllOnBlankLine: "빈 줄에서 모든 SQL 실행", + executeAllOnBlankLineDescription: "현재 구문 실행 모드에서 커서 위치에 구문이 없으면 모든 SQL을 실행합니다. 기본적으로 비활성화됩니다.", showExecutionTargetPicker: "실행 대상 선택기 표시", showExecutionTargetPickerDescription: "활성화하면 선택 없이 실행할 때 현재 구문과 전체 SQL 중에서 선택할 수 있습니다.", showStatementRunButtons: "왼쪽 실행 버튼 표시", diff --git a/apps/desktop/src/i18n/locales/pt-BR.ts b/apps/desktop/src/i18n/locales/pt-BR.ts index 2cb1a19b7d..07f6550ae5 100644 --- a/apps/desktop/src/i18n/locales/pt-BR.ts +++ b/apps/desktop/src/i18n/locales/pt-BR.ts @@ -1190,6 +1190,7 @@ export default withEnglishFallback({ noResults: "Nenhum resultado", inSelection: "Na seleção", }, + noExecutableStatementAtCursor: "Não há instrução executável na posição do cursor.", executionPicker: { title: "Execution Target", currentStatement: "Current SQL", @@ -5269,6 +5270,8 @@ export default withEnglishFallback({ executeMode: "Modo de execução (Cmd+Enter)", executeModeAll: "Executar todo o SQL", executeModeCurrent: "Executar instrução no cursor", + executeAllOnBlankLine: "Executar todo o SQL em linhas em branco", + executeAllOnBlankLineDescription: "No modo de instrução atual, executa todo o SQL quando não há instrução no cursor. Desativado por padrão.", showExecutionTargetPicker: "Mostrar seletor de destino", showExecutionTargetPickerDescription: "Quando ativado, executar sem seleção permite escolher entre a instrução atual e todo o SQL.", showStatementRunButtons: "Mostrar botões de execução laterais", diff --git a/apps/desktop/src/i18n/locales/zh-CN.ts b/apps/desktop/src/i18n/locales/zh-CN.ts index 2412622bd5..da4f89aae9 100644 --- a/apps/desktop/src/i18n/locales/zh-CN.ts +++ b/apps/desktop/src/i18n/locales/zh-CN.ts @@ -1152,6 +1152,7 @@ export default withEnglishFallback({ noResults: "无结果", inSelection: "选区内", }, + noExecutableStatementAtCursor: "光标所在位置没有可执行语句", executionPicker: { title: "执行目标", currentStatement: "当前 SQL", @@ -5458,6 +5459,8 @@ export default withEnglishFallback({ executeMode: "执行模式 (Cmd+Enter)", executeModeAll: "执行全部 SQL", executeModeCurrent: "执行光标所在语句", + executeAllOnBlankLine: "空白位置执行全部 SQL", + executeAllOnBlankLineDescription: "在“执行光标所在语句”模式下,光标没有对应语句时执行全部 SQL。默认关闭。", showExecutionTargetPicker: "显示执行目标选择器", showExecutionTargetPickerDescription: "开启后,无选区执行时可在当前语句和全部 SQL 之间临时选择。", showStatementRunButtons: "显示左侧执行按钮", diff --git a/apps/desktop/src/i18n/locales/zh-TW.ts b/apps/desktop/src/i18n/locales/zh-TW.ts index 7b8e6ce4d7..b2e6b9859a 100644 --- a/apps/desktop/src/i18n/locales/zh-TW.ts +++ b/apps/desktop/src/i18n/locales/zh-TW.ts @@ -1189,6 +1189,7 @@ export default withEnglishFallback({ noResults: "無結果", inSelection: "選取區內", }, + noExecutableStatementAtCursor: "游標所在位置沒有可執行語句", executionPicker: { title: "執行目標", currentStatement: "當前 SQL", @@ -4712,6 +4713,8 @@ export default withEnglishFallback({ executeMode: "執行模式 (Cmd+Enter)", executeModeAll: "執行全部 SQL", executeModeCurrent: "執行指標所在語句", + executeAllOnBlankLine: "空白位置執行全部 SQL", + executeAllOnBlankLineDescription: "在「執行游標所在語句」模式下,游標沒有對應語句時執行全部 SQL。預設關閉。", showExecutionTargetPicker: "顯示執行目標選擇器", showExecutionTargetPickerDescription: "啟用後,無選取執行時可在目前語句與全部 SQL 之間臨時選擇。", showStatementRunButtons: "顯示左側執行按鈕", diff --git a/apps/desktop/src/lib/__tests__/editor/queryEditorExecution.spec.ts b/apps/desktop/src/lib/__tests__/editor/queryEditorExecution.spec.ts index 5b07d04069..3f09c5779a 100644 --- a/apps/desktop/src/lib/__tests__/editor/queryEditorExecution.spec.ts +++ b/apps/desktop/src/lib/__tests__/editor/queryEditorExecution.spec.ts @@ -21,20 +21,21 @@ describe("QueryEditor execution routing", () => { it("keeps selection priority and the configured current/all target choice", () => { const selectionBranch = queryEditorSource.indexOf("if (!options.ignoreSelection && !selection.empty)"); - const executeModeBranch = queryEditorSource.indexOf("executionCandidateForMode(candidates, settingsStore.editorSettings.executeMode)"); + const executeModeBranch = queryEditorSource.indexOf("executionCandidateForMode(candidates, executeMode"); expect(selectionBranch).toBeGreaterThan(-1); expect(executeModeBranch).toBeGreaterThan(selectionBranch); }); - it("does not fall back to all SQL when current mode has no statement at the cursor", () => { - expect(queryEditorSource).toContain("const candidate = executionCandidateForMode(candidates, settingsStore.editorSettings.executeMode)"); - expect(queryEditorSource).toContain("if (!candidate) return true"); + it("uses the opt-in blank-line fallback and otherwise reports the missing cursor statement", () => { + expect(queryEditorSource).toContain("executeAllOnBlankLine: settingsStore.editorSettings.executeAllOnBlankLine"); + expect(queryEditorSource).toContain('toast(t("editor.noExecutableStatementAtCursor"), 3000)'); expect(queryEditorSource).not.toContain("?? candidates[0]"); }); - it("consumes the execution shortcut when the editor has no executable target", () => { - expect(queryEditorSource).toContain("if (candidates.length === 0) return true"); + it("consumes the execution shortcut and reports an empty current target", () => { + expect(queryEditorSource).toContain("if (candidates.length === 0)"); + expect(queryEditorSource).toContain('if (executeMode === "current") toast(t("editor.noExecutableStatementAtCursor"), 3000)'); }); it("preserves the source range when executing a current/all candidate without a manual selection", () => { diff --git a/apps/desktop/src/lib/__tests__/sql/sqlExecutionTarget.spec.ts b/apps/desktop/src/lib/__tests__/sql/sqlExecutionTarget.spec.ts index 5544928ffa..54b7b5eb04 100644 --- a/apps/desktop/src/lib/__tests__/sql/sqlExecutionTarget.spec.ts +++ b/apps/desktop/src/lib/__tests__/sql/sqlExecutionTarget.spec.ts @@ -23,6 +23,13 @@ describe("executionCandidateForMode", () => { expect(executionCandidateForMode([all], "all")).toBe(all); }); + it("falls back to all SQL only when blank-line execution is enabled", () => { + const all = candidate("all", ["all"]); + + expect(executionCandidateForMode([all], "current", { executeAllOnBlankLine: false })).toBeNull(); + expect(executionCandidateForMode([all], "current", { executeAllOnBlankLine: true })).toBe(all); + }); + it("uses the deduplicated candidate when one statement is both current and all", () => { const currentAndAll = candidate("all", ["cursor", "all"]); diff --git a/apps/desktop/src/lib/__tests__/sql/sqlStatementRanges.spec.ts b/apps/desktop/src/lib/__tests__/sql/sqlStatementRanges.spec.ts index ddb51131ae..95eb9f0743 100644 --- a/apps/desktop/src/lib/__tests__/sql/sqlStatementRanges.spec.ts +++ b/apps/desktop/src/lib/__tests__/sql/sqlStatementRanges.spec.ts @@ -1321,6 +1321,7 @@ WHERE t2.product_name = '12345' expect(candidateKinds(candidates)).toEqual(["all"]); expect(candidates[0].supportedKinds).toEqual(["all"]); expect(executionCandidateForMode(candidates, "current")).toBeNull(); + expect(executionCandidateForMode(candidates, "current", { executeAllOnBlankLine: true })).toBe(candidates[0]); expect(executionCandidateForMode(candidates, "all")).toBe(candidates[0]); }); diff --git a/apps/desktop/src/lib/settings/editorSettingsDraft.ts b/apps/desktop/src/lib/settings/editorSettingsDraft.ts index 9628965ce3..75f17ca194 100644 --- a/apps/desktop/src/lib/settings/editorSettingsDraft.ts +++ b/apps/desktop/src/lib/settings/editorSettingsDraft.ts @@ -12,6 +12,7 @@ export const EDITOR_SETTINGS_DRAFT_KEYS = [ "customThemes", "activeCustomThemeId", "executeMode", + "executeAllOnBlankLine", "globalConnectTimeoutSecs", "globalQueryTimeoutSecs", "showExecutionTargetPicker", diff --git a/apps/desktop/src/lib/settings/settingsSearch.ts b/apps/desktop/src/lib/settings/settingsSearch.ts index f53142f1d8..789841bb5e 100644 --- a/apps/desktop/src/lib/settings/settingsSearch.ts +++ b/apps/desktop/src/lib/settings/settingsSearch.ts @@ -106,6 +106,7 @@ export const SETTINGS_SEARCH_DEFINITIONS: readonly SettingsSearchDefinition[] = { id: "editor-theme", category: "editor", titleKey: "settings.theme", targetId: "editor" }, { id: "editor-font-size", category: "editor", titleKey: "settings.fontSize", targetId: "editor" }, { id: "editor-execute-mode", category: "editor", titleKey: "settings.executeMode", targetId: "editor" }, + { id: "editor-execute-all-on-blank-line", category: "editor", titleKey: "settings.executeAllOnBlankLine", descriptionKey: "settings.executeAllOnBlankLineDescription", targetId: "editor" }, { id: "editor-global-connect-timeout", category: "editor", titleKey: "settings.globalConnectTimeout", descriptionKey: "settings.globalConnectTimeoutDescription", targetId: "editor" }, { id: "editor-global-query-timeout", category: "editor", titleKey: "settings.globalQueryTimeout", descriptionKey: "settings.globalQueryTimeoutDescription", targetId: "editor" }, { id: "editor-execution-target", category: "editor", titleKey: "settings.showExecutionTargetPicker", descriptionKey: "settings.showExecutionTargetPickerDescription", targetId: "editor" }, diff --git a/apps/desktop/src/lib/sql/sqlExecutionTarget.ts b/apps/desktop/src/lib/sql/sqlExecutionTarget.ts index e7146abb92..4e7f124efd 100644 --- a/apps/desktop/src/lib/sql/sqlExecutionTarget.ts +++ b/apps/desktop/src/lib/sql/sqlExecutionTarget.ts @@ -41,9 +41,11 @@ export function isSqlExecutionSnapshot(value: SqlExecutionOverride | undefined): return typeof value === "object" && value !== null && typeof value.fullSql === "string" && typeof value.selectedSql === "string" && typeof value.cursorPos === "number" && typeof value.selectionFrom === "number" && typeof value.selectionTo === "number"; } -export function executionCandidateForMode(candidates: SqlExecutionCandidate[], mode: ExecuteMode): SqlExecutionCandidate | null { +export function executionCandidateForMode(candidates: SqlExecutionCandidate[], mode: ExecuteMode, options: { executeAllOnBlankLine?: boolean } = {}): SqlExecutionCandidate | null { const targetKind: SqlExecutionTargetKind = mode === "current" ? "cursor" : "all"; - return candidates.find((candidate) => candidate.supportedKinds.includes(targetKind)) ?? null; + const candidate = candidates.find((item) => item.supportedKinds.includes(targetKind)); + if (candidate || mode !== "current" || !options.executeAllOnBlankLine) return candidate ?? null; + return candidates.find((item) => item.supportedKinds.includes("all")) ?? null; } export function resolveExecutableSql(fullSql: string, selectedSql: string, options?: { mode?: ExecuteMode; cursorPos?: number }): string { diff --git a/apps/desktop/src/stores/__tests__/settingsStore.spec.ts b/apps/desktop/src/stores/__tests__/settingsStore.spec.ts index 9f2aafc848..459850a7b2 100644 --- a/apps/desktop/src/stores/__tests__/settingsStore.spec.ts +++ b/apps/desktop/src/stores/__tests__/settingsStore.spec.ts @@ -52,6 +52,12 @@ describe("normalizeEditorSettings", () => { ).toBe("all"); }); + it("keeps blank-line execute-all disabled by default and preserves an explicit opt-in", () => { + expect(normalizeEditorSettings({}).executeAllOnBlankLine).toBe(false); + expect(normalizeEditorSettings({ executeAllOnBlankLine: false }).executeAllOnBlankLine).toBe(false); + expect(normalizeEditorSettings({ executeAllOnBlankLine: true }).executeAllOnBlankLine).toBe(true); + }); + it("enables automatic table aliases by default", () => { expect(normalizeEditorSettings({}).autoAliasTables).toBe(true); }); diff --git a/apps/desktop/src/stores/settingsStore.ts b/apps/desktop/src/stores/settingsStore.ts index cd0866408c..1ffe71eb10 100644 --- a/apps/desktop/src/stores/settingsStore.ts +++ b/apps/desktop/src/stores/settingsStore.ts @@ -478,6 +478,7 @@ export interface EditorSettings { activeCustomThemeId: string; executeMode: "all" | "current"; executeModeDefaultVersion: number; + executeAllOnBlankLine: boolean; globalConnectTimeoutSecs: number; connectTimeoutInheritConnectionIds: string[]; globalQueryTimeoutSecs: number; @@ -664,6 +665,7 @@ export const DEFAULT_EDITOR_SETTINGS: EditorSettings = { activeCustomThemeId: "default", executeMode: "current", executeModeDefaultVersion: EXECUTE_MODE_CURRENT_DEFAULT_VERSION, + executeAllOnBlankLine: false, globalConnectTimeoutSecs: 10, connectTimeoutInheritConnectionIds: [], globalQueryTimeoutSecs: 30, @@ -992,6 +994,7 @@ export function normalizeEditorSettings(settings: Partial, exist activeCustomThemeId: settings.activeCustomThemeId ?? "default", executeMode: hasCurrentExecuteModeDefault && (settings.executeMode === "all" || settings.executeMode === "current") ? settings.executeMode : DEFAULT_EDITOR_SETTINGS.executeMode, executeModeDefaultVersion, + executeAllOnBlankLine: settings.executeAllOnBlankLine === true, globalConnectTimeoutSecs: normalizeGlobalConnectTimeoutSecs(settings.globalConnectTimeoutSecs), connectTimeoutInheritConnectionIds: Array.isArray(settings.connectTimeoutInheritConnectionIds) ? [...new Set(settings.connectTimeoutInheritConnectionIds.filter((id): id is string => typeof id === "string" && id.trim().length > 0).map((id) => id.trim()))] : [], globalQueryTimeoutSecs: normalizeGlobalQueryTimeoutSecs(settings.globalQueryTimeoutSecs ?? legacyTimeoutSettings.queryTimeoutSecs), @@ -1525,6 +1528,7 @@ export const useSettingsStore = defineStore("settings", () => { } } if (partial.executeMode !== undefined) editorSettings.value.executeMode = partial.executeMode; + if (partial.executeAllOnBlankLine !== undefined) editorSettings.value.executeAllOnBlankLine = partial.executeAllOnBlankLine === true; if (partial.globalConnectTimeoutSecs !== undefined) editorSettings.value.globalConnectTimeoutSecs = normalizeGlobalConnectTimeoutSecs(partial.globalConnectTimeoutSecs); if (partial.connectTimeoutInheritConnectionIds !== undefined) { editorSettings.value.connectTimeoutInheritConnectionIds = [...new Set(partial.connectTimeoutInheritConnectionIds.filter((id): id is string => typeof id === "string" && id.trim().length > 0).map((id) => id.trim()))];