fix(editor): improve SQL Server editing support

This commit is contained in:
t8y2
2026-05-09 18:17:56 +08:00
parent 9663a9b9cb
commit 9b81fa5f38
7 changed files with 47 additions and 10 deletions
+16 -1
View File
@@ -30,6 +30,7 @@ const editFontFamily = ref(settingsStore.editorSettings.fontFamily);
const editFontSize = ref(settingsStore.editorSettings.fontSize);
const editTheme = ref(settingsStore.editorSettings.theme);
const editExecuteMode = ref(settingsStore.editorSettings.executeMode);
const editWordWrap = ref(settingsStore.editorSettings.wordWrap);
// Sync from store when dialog opens
watch(
@@ -40,6 +41,7 @@ watch(
editFontSize.value = settingsStore.editorSettings.fontSize;
editTheme.value = settingsStore.editorSettings.theme;
editExecuteMode.value = settingsStore.editorSettings.executeMode;
editWordWrap.value = settingsStore.editorSettings.wordWrap;
}
},
);
@@ -49,7 +51,8 @@ function hasChanges(): boolean {
editFontFamily.value !== settingsStore.editorSettings.fontFamily ||
editFontSize.value !== settingsStore.editorSettings.fontSize ||
editTheme.value !== settingsStore.editorSettings.theme ||
editExecuteMode.value !== settingsStore.editorSettings.executeMode
editExecuteMode.value !== settingsStore.editorSettings.executeMode ||
editWordWrap.value !== settingsStore.editorSettings.wordWrap
);
}
@@ -59,6 +62,7 @@ function applySettings() {
fontSize: editFontSize.value,
theme: editTheme.value,
executeMode: editExecuteMode.value,
wordWrap: editWordWrap.value,
});
emit("update:open", false);
}
@@ -68,6 +72,7 @@ function resetDefaults() {
editFontSize.value = DEFAULT_EDITOR_SETTINGS.fontSize;
editTheme.value = DEFAULT_EDITOR_SETTINGS.theme;
editExecuteMode.value = DEFAULT_EDITOR_SETTINGS.executeMode;
editWordWrap.value = DEFAULT_EDITOR_SETTINGS.wordWrap;
}
function onExecuteModeChange(v: any) {
@@ -340,6 +345,16 @@ watch(
<Separator />
<div class="flex items-center justify-between gap-4">
<div class="space-y-1">
<Label>{{ t("settings.wordWrap") }}</Label>
<p class="text-xs text-muted-foreground">{{ t("settings.wordWrapDescription") }}</p>
</div>
<input v-model="editWordWrap" type="checkbox" class="h-4 w-4 shrink-0 accent-primary" />
</div>
<Separator />
<!-- Live Preview -->
<div class="space-y-2">
<Label>{{ t("settings.preview") }}</Label>
+10 -6
View File
@@ -15,7 +15,7 @@ const props = defineProps<{
modelValue: string;
connectionId?: string;
database?: string;
dialect?: "mysql" | "postgres";
dialect?: "mysql" | "postgres" | "sqlserver";
formatDialect?: SqlFormatDialect;
formatRequestId?: number;
}>();
@@ -40,6 +40,7 @@ const MAX_FONT_SIZE = 24;
let editorViewModule: typeof import("@codemirror/view") | null = null;
let fontThemeComp: import("@codemirror/state").Compartment | null = null;
let codeMirrorTheme: import("@codemirror/state").Compartment | null = null;
let wordWrapComp: import("@codemirror/state").Compartment | null = null;
// Completion cache
let cachedTables: Array<{ name: string; schema?: string; type?: "table" | "view" }> = [];
@@ -206,8 +207,8 @@ onMounted(async () => {
const [
{ EditorView, keymap },
{ EditorState, Compartment },
{ sql, MySQL, PostgreSQL, SQLDialect },
{ EditorState, Compartment, Prec },
{ sql, MSSQL, MySQL, PostgreSQL, SQLDialect },
{ basicSetup },
{ autocompletion, startCompletion },
{ indentWithTab },
@@ -222,10 +223,11 @@ onMounted(async () => {
editorViewModule = { EditorView, keymap } as typeof import("@codemirror/view");
fontThemeComp = new Compartment();
codeMirrorTheme = new Compartment();
wordWrapComp = new Compartment();
const ss = settingsStore.editorSettings;
const baseDialect = props.dialect === "postgres" ? PostgreSQL : MySQL;
const baseDialect = props.dialect === "postgres" ? PostgreSQL : props.dialect === "sqlserver" ? MSSQL : MySQL;
const extraKeywords =
"PIVOT UNPIVOT EXCLUDE REPLACE QUALIFY ASOF POSITIONAL ANTI SEMI SAMPLE TABLESAMPLE STRUCT MAP LIST ARRAY LAMBDA UNNEST LATERAL FILTER RECURSIVE SUMMARIZE PRAGMA READ_CSV READ_PARQUET READ_JSON DESCRIBE SHOW COPY EXPORT IMPORT";
const dialect = SQLDialect.define({
@@ -283,8 +285,9 @@ onMounted(async () => {
override: [async (context: CompletionContext) => provideSqlCompletions(context.state, context.pos)],
}),
codeMirrorTheme.of(theme),
keymap.of([indentWithTab]),
Prec.highest(keymap.of([indentWithTab])),
runKeymap,
wordWrapComp.of(ss.wordWrap ? EditorView.lineWrapping : []),
EditorView.updateListener.of((update) => {
if (update.docChanged) {
emit("update:modelValue", update.state.doc.toString());
@@ -486,11 +489,12 @@ watch(
watch(
() => settingsStore.editorSettings,
async (ss) => {
if (!view.value || !codeMirrorTheme || !fontThemeComp || !editorViewModule) return;
if (!view.value || !codeMirrorTheme || !fontThemeComp || !wordWrapComp || !editorViewModule) return;
const themeExt = await loadEditorTheme(ss.theme);
view.value.dispatch({
effects: [
codeMirrorTheme.reconfigure(themeExt),
wordWrapComp.reconfigure(ss.wordWrap ? editorViewModule.EditorView.lineWrapping : []),
fontThemeComp.reconfigure(
editorFontTheme(editorViewModule.EditorView, ss.fontSize, ss.fontFamily, {
fixedHeight: true,
+5 -3
View File
@@ -71,9 +71,11 @@ const activeSqlFormatDialect = computed<SqlFormatDialect>(() => {
}
});
const editorDialect = computed<"mysql" | "postgres">(() =>
props.activeConnection?.db_type === "postgres" ? "postgres" : "mysql",
);
const editorDialect = computed<"mysql" | "postgres" | "sqlserver">(() => {
if (props.activeConnection?.db_type === "postgres") return "postgres";
if (props.activeConnection?.db_type === "sqlserver") return "sqlserver";
return "mysql";
});
const hasNumericData = computed(() => {
const r = props.activeTab.result;
+2
View File
@@ -737,6 +737,8 @@ export default {
executeMode: "Execute Mode (Cmd+Enter)",
executeModeAll: "Execute all SQL",
executeModeCurrent: "Execute statement at cursor",
wordWrap: "Word wrap",
wordWrapDescription: "Wrap long SQL lines within the editor width",
preview: "Live Preview",
aboutDescription: "An open-source, lightweight database management tool.",
community: "Community",
+2
View File
@@ -725,6 +725,8 @@ export default {
executeMode: "执行模式 (Cmd+Enter)",
executeModeAll: "执行全部 SQL",
executeModeCurrent: "执行光标所在语句",
wordWrap: "自动换行",
wordWrapDescription: "长 SQL 在编辑器宽度内自动折行显示",
preview: "实时预览",
aboutDescription: "开源、轻量的数据库管理工具。",
community: "社区",
+9
View File
@@ -84,6 +84,15 @@ const SQL_KEYWORDS = [
"APPLY",
"CROSS APPLY",
"OUTER APPLY",
"ISJSON",
"JSON_ARRAY",
"JSON_ARRAYAGG",
"JSON_MODIFY",
"JSON_OBJECT",
"JSON_OBJECTAGG",
"JSON_PATH_EXISTS",
"JSON_QUERY",
"JSON_VALUE",
"OPENJSON",
"OPENXML",
"OPENROWSET",
+3
View File
@@ -45,6 +45,7 @@ export interface EditorSettings {
fontSize: number;
theme: EditorTheme;
executeMode: "all" | "current";
wordWrap: boolean;
}
export const EDITOR_THEMES: { value: EditorTheme; label: string; dark: boolean }[] = [
@@ -74,6 +75,7 @@ export const DEFAULT_EDITOR_SETTINGS: EditorSettings = {
fontSize: 13,
theme: "one-dark",
executeMode: "all",
wordWrap: false,
};
export const STORAGE_KEY = "dbx-editor-settings";
@@ -90,6 +92,7 @@ function loadEditorSettings(): EditorSettings {
fontSize: parsed.fontSize ?? DEFAULT_EDITOR_SETTINGS.fontSize,
theme: parsed.theme ?? DEFAULT_EDITOR_SETTINGS.theme,
executeMode: parsed.executeMode ?? DEFAULT_EDITOR_SETTINGS.executeMode,
wordWrap: parsed.wordWrap ?? DEFAULT_EDITOR_SETTINGS.wordWrap,
};
}
} catch {