🎨 Change configuration structure

This commit is contained in:
2025-06-03 00:19:16 +08:00
parent 77bd15bed7
commit 81868e8d37
12 changed files with 525 additions and 386 deletions

View File

@@ -10,23 +10,33 @@ import {Create as $Create} from "@wailsio/runtime";
import * as time$0 from "../../../time/models.js";
/**
* AppConfig 应用配置 - 包含业务配置和路径配置
* AppConfig 应用配置 - 按照前端设置页面分类组织
*/
export class AppConfig {
/**
* 编辑器配
* 通用设
*/
"editor": EditorConfig;
"general": GeneralConfig;
/**
* 文档配
* 编辑设
*/
"document": DocumentConfig;
"editing": EditingConfig;
/**
* 路径配
* 外观设
*/
"paths": PathsConfig;
"appearance": AppearanceConfig;
/**
* 快捷键设置
*/
"keyBindings": KeyBindingsConfig;
/**
* 更新设置
*/
"updates": UpdatesConfig;
/**
* 配置元数据
@@ -35,14 +45,20 @@ export class AppConfig {
/** Creates a new AppConfig instance. */
constructor($$source: Partial<AppConfig> = {}) {
if (!("editor" in $$source)) {
this["editor"] = (new EditorConfig());
if (!("general" in $$source)) {
this["general"] = (new GeneralConfig());
}
if (!("document" in $$source)) {
this["document"] = (new DocumentConfig());
if (!("editing" in $$source)) {
this["editing"] = (new EditingConfig());
}
if (!("paths" in $$source)) {
this["paths"] = (new PathsConfig());
if (!("appearance" in $$source)) {
this["appearance"] = (new AppearanceConfig());
}
if (!("keyBindings" in $$source)) {
this["keyBindings"] = (new KeyBindingsConfig());
}
if (!("updates" in $$source)) {
this["updates"] = (new UpdatesConfig());
}
if (!("metadata" in $$source)) {
this["metadata"] = (new ConfigMetadata());
@@ -59,23 +75,58 @@ export class AppConfig {
const $$createField1_0 = $$createType1;
const $$createField2_0 = $$createType2;
const $$createField3_0 = $$createType3;
const $$createField4_0 = $$createType4;
const $$createField5_0 = $$createType5;
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
if ("editor" in $$parsedSource) {
$$parsedSource["editor"] = $$createField0_0($$parsedSource["editor"]);
if ("general" in $$parsedSource) {
$$parsedSource["general"] = $$createField0_0($$parsedSource["general"]);
}
if ("document" in $$parsedSource) {
$$parsedSource["document"] = $$createField1_0($$parsedSource["document"]);
if ("editing" in $$parsedSource) {
$$parsedSource["editing"] = $$createField1_0($$parsedSource["editing"]);
}
if ("paths" in $$parsedSource) {
$$parsedSource["paths"] = $$createField2_0($$parsedSource["paths"]);
if ("appearance" in $$parsedSource) {
$$parsedSource["appearance"] = $$createField2_0($$parsedSource["appearance"]);
}
if ("keyBindings" in $$parsedSource) {
$$parsedSource["keyBindings"] = $$createField3_0($$parsedSource["keyBindings"]);
}
if ("updates" in $$parsedSource) {
$$parsedSource["updates"] = $$createField4_0($$parsedSource["updates"]);
}
if ("metadata" in $$parsedSource) {
$$parsedSource["metadata"] = $$createField3_0($$parsedSource["metadata"]);
$$parsedSource["metadata"] = $$createField5_0($$parsedSource["metadata"]);
}
return new AppConfig($$parsedSource as Partial<AppConfig>);
}
}
/**
* AppearanceConfig 外观设置配置
*/
export class AppearanceConfig {
/**
* 界面语言
*/
"language": LanguageType;
/** Creates a new AppearanceConfig instance. */
constructor($$source: Partial<AppearanceConfig> = {}) {
if (!("language" in $$source)) {
this["language"] = ("" as LanguageType);
}
Object.assign(this, $$source);
}
/**
* Creates a new AppearanceConfig instance from a string or object.
*/
static createFrom($$source: any = {}): AppearanceConfig {
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
return new AppearanceConfig($$parsedSource as Partial<AppearanceConfig>);
}
}
/**
* ConfigMetadata 配置元数据
*/
@@ -141,7 +192,7 @@ export class Document {
* Creates a new Document instance from a string or object.
*/
static createFrom($$source: any = {}): Document {
const $$createField0_0 = $$createType4;
const $$createField0_0 = $$createType6;
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
if ("meta" in $$parsedSource) {
$$parsedSource["meta"] = $$createField0_0($$parsedSource["meta"]);
@@ -150,49 +201,6 @@ export class Document {
}
}
/**
* DocumentConfig 定义文档配置
*/
export class DocumentConfig {
/**
* 自动保存延迟(毫秒)- 内容变更后多久自动保存
*/
"autoSaveDelay": number;
/**
* 变更字符阈值,超过此阈值立即触发保存
*/
"changeThreshold": number;
/**
* 最小保存间隔(毫秒)- 两次保存之间的最小时间间隔避免频繁IO
*/
"minSaveInterval": number;
/** Creates a new DocumentConfig instance. */
constructor($$source: Partial<DocumentConfig> = {}) {
if (!("autoSaveDelay" in $$source)) {
this["autoSaveDelay"] = 0;
}
if (!("changeThreshold" in $$source)) {
this["changeThreshold"] = 0;
}
if (!("minSaveInterval" in $$source)) {
this["minSaveInterval"] = 0;
}
Object.assign(this, $$source);
}
/**
* Creates a new DocumentConfig instance from a string or object.
*/
static createFrom($$source: any = {}): DocumentConfig {
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
return new DocumentConfig($$parsedSource as Partial<DocumentConfig>);
}
}
/**
* DocumentMeta 文档元数据
*/
@@ -245,10 +253,11 @@ export class DocumentMeta {
}
/**
* EditorConfig 定义编辑器配置
* EditingConfig 编辑设置配置
*/
export class EditorConfig {
export class EditingConfig {
/**
* 字体设置
* 字体大小
*/
"fontSize": number;
@@ -269,6 +278,7 @@ export class EditorConfig {
"lineHeight": number;
/**
* Tab设置
* 是否启用Tab缩进
*/
"enableTabIndent": boolean;
@@ -284,17 +294,23 @@ export class EditorConfig {
"tabType": TabType;
/**
* 界面语言
* 保存选项
* 自动保存延迟(毫秒)
*/
"language": LanguageType;
"autoSaveDelay": number;
/**
* 窗口是否置顶
* 变更字符阈值
*/
"alwaysOnTop": boolean;
"changeThreshold": number;
/** Creates a new EditorConfig instance. */
constructor($$source: Partial<EditorConfig> = {}) {
/**
* 最小保存间隔(毫秒)
*/
"minSaveInterval": number;
/** Creates a new EditingConfig instance. */
constructor($$source: Partial<EditingConfig> = {}) {
if (!("fontSize" in $$source)) {
this["fontSize"] = 0;
}
@@ -316,22 +332,80 @@ export class EditorConfig {
if (!("tabType" in $$source)) {
this["tabType"] = ("" as TabType);
}
if (!("language" in $$source)) {
this["language"] = ("" as LanguageType);
if (!("autoSaveDelay" in $$source)) {
this["autoSaveDelay"] = 0;
}
if (!("alwaysOnTop" in $$source)) {
this["alwaysOnTop"] = false;
if (!("changeThreshold" in $$source)) {
this["changeThreshold"] = 0;
}
if (!("minSaveInterval" in $$source)) {
this["minSaveInterval"] = 0;
}
Object.assign(this, $$source);
}
/**
* Creates a new EditorConfig instance from a string or object.
* Creates a new EditingConfig instance from a string or object.
*/
static createFrom($$source: any = {}): EditorConfig {
static createFrom($$source: any = {}): EditingConfig {
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
return new EditorConfig($$parsedSource as Partial<EditorConfig>);
return new EditingConfig($$parsedSource as Partial<EditingConfig>);
}
}
/**
* GeneralConfig 通用设置配置
*/
export class GeneralConfig {
/**
* 窗口是否置顶
*/
"alwaysOnTop": boolean;
/**
* 数据存储路径
*/
"dataPath": string;
/** Creates a new GeneralConfig instance. */
constructor($$source: Partial<GeneralConfig> = {}) {
if (!("alwaysOnTop" in $$source)) {
this["alwaysOnTop"] = false;
}
if (!("dataPath" in $$source)) {
this["dataPath"] = "";
}
Object.assign(this, $$source);
}
/**
* Creates a new GeneralConfig instance from a string or object.
*/
static createFrom($$source: any = {}): GeneralConfig {
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
return new GeneralConfig($$parsedSource as Partial<GeneralConfig>);
}
}
/**
* KeyBindingsConfig 快捷键设置配置
*/
export class KeyBindingsConfig {
/** Creates a new KeyBindingsConfig instance. */
constructor($$source: Partial<KeyBindingsConfig> = {}) {
Object.assign(this, $$source);
}
/**
* Creates a new KeyBindingsConfig instance from a string or object.
*/
static createFrom($$source: any = {}): KeyBindingsConfig {
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
return new KeyBindingsConfig($$parsedSource as Partial<KeyBindingsConfig>);
}
}
@@ -355,33 +429,6 @@ export enum LanguageType {
LangEnUS = "en-US",
};
/**
* PathsConfig 路径配置集合
*/
export class PathsConfig {
/**
* 数据存储路径
*/
"dataPath": string;
/** Creates a new PathsConfig instance. */
constructor($$source: Partial<PathsConfig> = {}) {
if (!("dataPath" in $$source)) {
this["dataPath"] = "";
}
Object.assign(this, $$source);
}
/**
* Creates a new PathsConfig instance from a string or object.
*/
static createFrom($$source: any = {}): PathsConfig {
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
return new PathsConfig($$parsedSource as Partial<PathsConfig>);
}
}
/**
* TabType 定义了制表符类型
*/
@@ -402,9 +449,31 @@ export enum TabType {
TabTypeTab = "tab",
};
/**
* UpdatesConfig 更新设置配置
*/
export class UpdatesConfig {
/** Creates a new UpdatesConfig instance. */
constructor($$source: Partial<UpdatesConfig> = {}) {
Object.assign(this, $$source);
}
/**
* Creates a new UpdatesConfig instance from a string or object.
*/
static createFrom($$source: any = {}): UpdatesConfig {
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
return new UpdatesConfig($$parsedSource as Partial<UpdatesConfig>);
}
}
// Private type creation functions
const $$createType0 = EditorConfig.createFrom;
const $$createType1 = DocumentConfig.createFrom;
const $$createType2 = PathsConfig.createFrom;
const $$createType3 = ConfigMetadata.createFrom;
const $$createType4 = DocumentMeta.createFrom;
const $$createType0 = GeneralConfig.createFrom;
const $$createType1 = EditingConfig.createFrom;
const $$createType2 = AppearanceConfig.createFrom;
const $$createType3 = KeyBindingsConfig.createFrom;
const $$createType4 = UpdatesConfig.createFrom;
const $$createType5 = ConfigMetadata.createFrom;
const $$createType6 = DocumentMeta.createFrom;

View File

@@ -61,7 +61,7 @@ export function GetDiffInfo(oldText: string, newText: string): Promise<$models.D
/**
* GetSaveSettings 获取文档保存设置
*/
export function GetSaveSettings(): Promise<models$0.DocumentConfig | null> & { cancel(): void } {
export function GetSaveSettings(): Promise<models$0.EditingConfig | null> & { cancel(): void } {
let $resultPromise = $Call.ByID(4257471801) as any;
let $typingPromise = $resultPromise.then(($result: any) => {
return $$createType4($result);
@@ -129,7 +129,7 @@ export function UpdateActiveDocumentContent(content: string): Promise<void> & {
/**
* UpdateSaveSettings 更新文档保存设置
*/
export function UpdateSaveSettings(docConfig: models$0.DocumentConfig): Promise<void> & { cancel(): void } {
export function UpdateSaveSettings(docConfig: models$0.EditingConfig): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(1245479534, docConfig) as any;
return $resultPromise;
}
@@ -138,5 +138,5 @@ export function UpdateSaveSettings(docConfig: models$0.DocumentConfig): Promise<
const $$createType0 = models$0.Document.createFrom;
const $$createType1 = $Create.Nullable($$createType0);
const $$createType2 = $models.DiffResult.createFrom;
const $$createType3 = models$0.DocumentConfig.createFrom;
const $$createType3 = models$0.EditingConfig.createFrom;
const $$createType4 = $Create.Nullable($$createType3);

View File

@@ -1,75 +1,79 @@
<script setup lang="ts">
import {useEditorStore} from '@/stores/editorStore';
import {useConfigStore, SUPPORTED_LOCALES, type SupportedLocaleType} from '@/stores/configStore';
import {useLogStore} from '@/stores/logStore';
import { useErrorHandler } from '@/utils/errorHandler';
import { useI18n } from 'vue-i18n';
import { ref, onMounted, watch } from 'vue';
import { useConfigStore } from '@/stores/configStore';
import { useEditorStore } from '@/stores/editorStore';
import { useErrorHandler } from '@/utils/errorHandler';
import * as runtime from '@wailsio/runtime';
import { useRouter } from 'vue-router';
const editorStore = useEditorStore();
const configStore = useConfigStore();
const logStore = useLogStore();
const { safeCall } = useErrorHandler();
const { t, locale } = useI18n();
const router = useRouter();
// 语言下拉菜单
const showLanguageMenu = ref(false);
// 切换语言
const changeLanguage = async (localeCode: SupportedLocaleType) => {
await safeCall(
() => configStore.setLocale(localeCode),
'config.languageChangeFailed'
);
showLanguageMenu.value = false;
};
const supportedLanguages = [
{ code: 'zh-CN', name: '简体中文' },
{ code: 'en-US', name: 'English' }
];
// 切换语言菜单显示
const toggleLanguageMenu = () => {
showLanguageMenu.value = !showLanguageMenu.value;
};
// 窗口置顶控制
const closeLanguageMenu = () => {
showLanguageMenu.value = false;
};
const changeLanguage = async (langCode: string) => {
await safeCall(() => configStore.setLanguage(langCode as any), 'language.changeFailed');
closeLanguageMenu();
};
// 设置窗口置顶
const setWindowAlwaysOnTop = async (isTop: boolean) => {
await safeCall(async () => {
await runtime.Window.SetAlwaysOnTop(isTop);
}, 'window.setTopFailed');
};
// 切换窗口置顶
const toggleAlwaysOnTop = async () => {
await safeCall(async () => {
await configStore.toggleAlwaysOnTop();
// 使用Window.SetAlwaysOnTop方法设置窗口置顶状态
await runtime.Window.SetAlwaysOnTop(configStore.config.alwaysOnTop);
await runtime.Window.SetAlwaysOnTop(configStore.config.general.alwaysOnTop);
}, 'config.alwaysOnTopFailed');
};
// 打开设置页面
const openSettings = () => {
// 跳转到设置页面
const goToSettings = () => {
router.push('/settings');
};
// 设置窗口置顶状态的通用函数
const setWindowAlwaysOnTop = async (alwaysOnTop: boolean) => {
await safeCall(
() => runtime.Window.SetAlwaysOnTop(alwaysOnTop),
'config.alwaysOnTopFailed'
);
};
const isLoaded = ref(false);
// 初始化配置
onMounted(async () => {
// 加载配置
if (!configStore.configLoaded) {
await configStore.initConfig();
}
// 设置窗口置顶状态
if (configStore.config.alwaysOnTop) {
await setWindowAlwaysOnTop(true);
}
onMounted(() => {
isLoaded.value = true;
});
// 监听配置加载完成
watch(() => configStore.configLoaded, (isLoaded) => {
if (isLoaded && configStore.config.alwaysOnTop) {
setWindowAlwaysOnTop(true);
// 监听置顶设置变化
watch(
() => configStore.config.general.alwaysOnTop,
async (newValue) => {
if (!isLoaded.value) return;
await runtime.Window.SetAlwaysOnTop(newValue);
}
);
// 在组件加载完成后应用置顶设置
watch(isLoaded, async (newLoaded) => {
if (newLoaded && configStore.config.general.alwaysOnTop) {
await setWindowAlwaysOnTop(true);
}
});
</script>
@@ -86,34 +90,30 @@ watch(() => configStore.configLoaded, (isLoaded) => {
<span class="stat-item" :title="t('toolbar.editor.selected')" v-if="editorStore.documentStats.selectedCharacters > 0">
{{ t('toolbar.editor.selected') }}: <span class="stat-value">{{ editorStore.documentStats.selectedCharacters }}</span>
</span>
<span v-if="logStore.showLog && logStore.latestLog" class="log-item" :class="'log-' + logStore.latestLog.level"
@click="logStore.hideCurrentLog()">
{{ logStore.latestLog.message }}
</span>
</div>
<div class="actions">
<span class="font-size" :title="t('toolbar.fontSizeTooltip')" @click="() => configStore.resetFontSize()">
{{ configStore.config.fontSize }}px
{{ configStore.config.editing.fontSize }}px
</span>
<span class="tab-settings">
<label :title="t('toolbar.tabLabel')" class="tab-toggle">
<input type="checkbox" :checked="configStore.config.enableTabIndent" @change="() => configStore.toggleTabIndent()"/>
<input type="checkbox" :checked="configStore.config.editing.enableTabIndent" @change="() => configStore.toggleTabIndent()"/>
<span>{{ t('toolbar.tabLabel') }}</span>
</label>
<span class="tab-type" :title="t('toolbar.tabType.' + (configStore.config.tabType === 'spaces' ? 'spaces' : 'tab'))" @click="() => configStore.toggleTabType()">
{{ t('toolbar.tabType.' + (configStore.config.tabType === 'spaces' ? 'spaces' : 'tab')) }}
<span class="tab-type" :title="t('toolbar.tabType.' + (configStore.config.editing.tabType === 'spaces' ? 'spaces' : 'tab'))" @click="() => configStore.toggleTabType()">
{{ t('toolbar.tabType.' + (configStore.config.editing.tabType === 'spaces' ? 'spaces' : 'tab')) }}
</span>
<span class="tab-size" title="Tab大小" v-if="configStore.config.tabType === 'spaces'">
<button class="tab-btn" @click="() => configStore.decreaseTabSize()" :disabled="configStore.config.tabSize <= configStore.tabSize.min">-</button>
<span>{{ configStore.config.tabSize }}</span>
<button class="tab-btn" @click="() => configStore.increaseTabSize()" :disabled="configStore.config.tabSize >= configStore.tabSize.max">+</button>
<span class="tab-size" title="Tab大小" v-if="configStore.config.editing.tabType === 'spaces'">
<button class="tab-btn" @click="() => configStore.decreaseTabSize()" :disabled="configStore.config.editing.tabSize <= configStore.tabSize.min">-</button>
<span>{{ configStore.config.editing.tabSize }}</span>
<button class="tab-btn" @click="() => configStore.increaseTabSize()" :disabled="configStore.config.editing.tabSize >= configStore.tabSize.max">+</button>
</span>
</span>
<!-- 窗口置顶图标按钮 -->
<div
class="pin-button"
:class="{ 'active': configStore.config.alwaysOnTop }"
:class="{ 'active': configStore.config.general.alwaysOnTop }"
:title="t('toolbar.alwaysOnTop')"
@click="toggleAlwaysOnTop"
>
@@ -130,7 +130,7 @@ watch(() => configStore.configLoaded, (isLoaded) => {
</button>
<div class="selector-menu" v-if="showLanguageMenu">
<div
v-for="lang in SUPPORTED_LOCALES"
v-for="lang in supportedLanguages"
:key="lang.code"
class="selector-option"
:class="{ active: locale === lang.code }"
@@ -141,7 +141,7 @@ watch(() => configStore.configLoaded, (isLoaded) => {
</div>
</div>
<button class="settings-btn" :title="t('toolbar.settings')" @click="openSettings">
<button class="settings-btn" :title="t('toolbar.settings')" @click="goToSettings">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="3"></circle>
@@ -177,24 +177,6 @@ watch(() => configStore.configLoaded, (isLoaded) => {
color: #e0e0e0;
}
}
.log-item {
cursor: default;
font-size: 12px;
transition: opacity 0.3s ease;
&.log-info {
color: rgba(177, 176, 176, 0.8);
}
&.log-warning {
color: rgba(240, 230, 140, 0.8);
}
&.log-error {
color: rgba(255, 107, 107, 0.8);
}
}
}
.actions {

View File

@@ -3,7 +3,7 @@ import {computed, reactive} from 'vue';
import {
ConfigService
} from '@/../bindings/voidraft/internal/services';
import {EditorConfig, TabType, LanguageType} from '@/../bindings/voidraft/internal/models/models';
import {AppConfig, GeneralConfig, EditingConfig, AppearanceConfig, TabType, LanguageType} from '@/../bindings/voidraft/internal/models';
import { useI18n } from 'vue-i18n';
import { useErrorHandler } from '@/utils/errorHandler';
import { ConfigUtils } from '@/utils/configUtils';
@@ -24,26 +24,41 @@ export const SUPPORTED_LOCALES = [
] as const;
// 配置键映射和限制的类型定义
type ConfigKeyMap = {
readonly [K in keyof EditorConfig]: string;
type GeneralConfigKeyMap = {
readonly [K in keyof GeneralConfig]: string;
};
type EditingConfigKeyMap = {
readonly [K in keyof EditingConfig]: string;
};
type AppearanceConfigKeyMap = {
readonly [K in keyof AppearanceConfig]: string;
};
type NumberConfigKey = 'fontSize' | 'tabSize' | 'lineHeight';
type StringConfigKey = 'fontFamily' | 'fontWeight';
type BooleanConfigKey = 'enableTabIndent' | 'alwaysOnTop';
type EnumConfigKey = 'tabType' | 'language';
// 配置键映射
const CONFIG_KEY_MAP: ConfigKeyMap = {
fontSize: 'editor.font_size',
fontFamily: 'editor.font_family',
fontWeight: 'editor.font_weight',
lineHeight: 'editor.line_height',
enableTabIndent: 'editor.enable_tab_indent',
tabSize: 'editor.tab_size',
tabType: 'editor.tab_type',
language: 'editor.language',
alwaysOnTop: 'editor.always_on_top'
const GENERAL_CONFIG_KEY_MAP: GeneralConfigKeyMap = {
alwaysOnTop: 'general.always_on_top',
dataPath: 'general.data_path'
} as const;
const EDITING_CONFIG_KEY_MAP: EditingConfigKeyMap = {
fontSize: 'editing.font_size',
fontFamily: 'editing.font_family',
fontWeight: 'editing.font_weight',
lineHeight: 'editing.line_height',
enableTabIndent: 'editing.enable_tab_indent',
tabSize: 'editing.tab_size',
tabType: 'editing.tab_type',
autoSaveDelay: 'editing.auto_save_delay',
changeThreshold: 'editing.change_threshold',
minSaveInterval: 'editing.min_save_interval'
} as const;
const APPEARANCE_CONFIG_KEY_MAP: AppearanceConfigKeyMap = {
language: 'appearance.language'
} as const;
// 配置限制
@@ -80,16 +95,32 @@ const getBrowserLanguage = (): SupportedLocaleType => {
};
// 默认配置
const DEFAULT_CONFIG: EditorConfig = {
fontSize: CONFIG_LIMITS.fontSize.default,
fontFamily: FONT_OPTIONS[0].value,
fontWeight: 'normal',
lineHeight: CONFIG_LIMITS.lineHeight.default,
enableTabIndent: true,
tabSize: CONFIG_LIMITS.tabSize.default,
tabType: CONFIG_LIMITS.tabType.default,
language: LanguageType.LangZhCN,
alwaysOnTop: false
const DEFAULT_CONFIG: AppConfig = {
general: {
alwaysOnTop: false,
dataPath: './data'
},
editing: {
fontSize: CONFIG_LIMITS.fontSize.default,
fontFamily: FONT_OPTIONS[0].value,
fontWeight: 'normal',
lineHeight: CONFIG_LIMITS.lineHeight.default,
enableTabIndent: true,
tabSize: CONFIG_LIMITS.tabSize.default,
tabType: CONFIG_LIMITS.tabType.default,
autoSaveDelay: 5000,
changeThreshold: 500,
minSaveInterval: 1000
},
appearance: {
language: LanguageType.LangZhCN
},
keyBindings: {},
updates: {},
metadata: {
version: '1.0.0',
lastUpdated: null
}
};
export const useConfigStore = defineStore('config', () => {
@@ -98,7 +129,7 @@ export const useConfigStore = defineStore('config', () => {
// 响应式状态
const state = reactive({
config: { ...DEFAULT_CONFIG } as EditorConfig,
config: { ...DEFAULT_CONFIG } as AppConfig,
isLoading: false,
configLoaded: false
});
@@ -110,19 +141,49 @@ export const useConfigStore = defineStore('config', () => {
) as Record<NumberConfigKey, ReturnType<typeof createLimitComputed>>;
// 通用配置更新方法
const updateConfig = async <K extends keyof EditorConfig>(key: K, value: EditorConfig[K]): Promise<void> => {
const updateGeneralConfig = async <K extends keyof GeneralConfig>(key: K, value: GeneralConfig[K]): Promise<void> => {
// 确保配置已加载
if (!state.configLoaded && !state.isLoading) {
await initConfig();
}
const backendKey = CONFIG_KEY_MAP[key];
const backendKey = GENERAL_CONFIG_KEY_MAP[key];
if (!backendKey) {
throw new Error(`No backend key mapping found for ${key.toString()}`);
throw new Error(`No backend key mapping found for general.${key.toString()}`);
}
await ConfigService.Set(backendKey, value);
state.config[key] = value;
state.config.general[key] = value;
};
const updateEditingConfig = async <K extends keyof EditingConfig>(key: K, value: EditingConfig[K]): Promise<void> => {
// 确保配置已加载
if (!state.configLoaded && !state.isLoading) {
await initConfig();
}
const backendKey = EDITING_CONFIG_KEY_MAP[key];
if (!backendKey) {
throw new Error(`No backend key mapping found for editing.${key.toString()}`);
}
await ConfigService.Set(backendKey, value);
state.config.editing[key] = value;
};
const updateAppearanceConfig = async <K extends keyof AppearanceConfig>(key: K, value: AppearanceConfig[K]): Promise<void> => {
// 确保配置已加载
if (!state.configLoaded && !state.isLoading) {
await initConfig();
}
const backendKey = APPEARANCE_CONFIG_KEY_MAP[key];
if (!backendKey) {
throw new Error(`No backend key mapping found for appearance.${key.toString()}`);
}
await ConfigService.Set(backendKey, value);
state.config.appearance[key] = value;
};
// 加载配置
@@ -133,8 +194,14 @@ export const useConfigStore = defineStore('config', () => {
try {
const appConfig = await ConfigService.GetConfig();
if (appConfig?.editor) {
Object.assign(state.config, appConfig.editor);
if (appConfig) {
// 合并配置
if (appConfig.general) Object.assign(state.config.general, appConfig.general);
if (appConfig.editing) Object.assign(state.config.editing, appConfig.editing);
if (appConfig.appearance) Object.assign(state.config.appearance, appConfig.appearance);
if (appConfig.keyBindings) Object.assign(state.config.keyBindings, appConfig.keyBindings);
if (appConfig.updates) Object.assign(state.config.updates, appConfig.updates);
if (appConfig.metadata) Object.assign(state.config.metadata, appConfig.metadata);
}
state.configLoaded = true;
@@ -149,23 +216,26 @@ export const useConfigStore = defineStore('config', () => {
const clamp = (value: number) => ConfigUtils.clamp(value, limit.min, limit.max);
return {
increase: () => safeCall(() => updateConfig(key, clamp(state.config[key] + 1)), 'config.saveFailed', 'config.saveSuccess'),
decrease: () => safeCall(() => updateConfig(key, clamp(state.config[key] - 1)), 'config.saveFailed', 'config.saveSuccess'),
set: (value: number) => safeCall(() => updateConfig(key, clamp(value)), 'config.saveFailed', 'config.saveSuccess'),
reset: () => safeCall(() => updateConfig(key, limit.default), 'config.saveFailed', 'config.saveSuccess')
increase: () => safeCall(() => updateEditingConfig(key, clamp(state.config.editing[key] + 1)), 'config.saveFailed', 'config.saveSuccess'),
decrease: () => safeCall(() => updateEditingConfig(key, clamp(state.config.editing[key] - 1)), 'config.saveFailed', 'config.saveSuccess'),
set: (value: number) => safeCall(() => updateEditingConfig(key, clamp(value)), 'config.saveFailed', 'config.saveSuccess'),
reset: () => safeCall(() => updateEditingConfig(key, limit.default), 'config.saveFailed', 'config.saveSuccess')
};
};
// 通用布尔值切换器
const createToggler = <T extends BooleanConfigKey>(key: T) =>
() => safeCall(() => updateConfig(key, !state.config[key]), 'config.saveFailed', 'config.saveSuccess');
const createGeneralToggler = <T extends keyof GeneralConfig>(key: T) =>
() => safeCall(() => updateGeneralConfig(key, !state.config.general[key] as GeneralConfig[T]), 'config.saveFailed', 'config.saveSuccess');
const createEditingToggler = <T extends keyof EditingConfig>(key: T) =>
() => safeCall(() => updateEditingConfig(key, !state.config.editing[key] as EditingConfig[T]), 'config.saveFailed', 'config.saveSuccess');
// 枚举值切换器
const createEnumToggler = <T extends TabType>(key: 'tabType', values: readonly T[]) =>
() => {
const currentIndex = values.indexOf(state.config[key] as T);
const currentIndex = values.indexOf(state.config.editing[key] as T);
const nextIndex = (currentIndex + 1) % values.length;
return safeCall(() => updateConfig(key, values[nextIndex]), 'config.saveFailed', 'config.saveSuccess');
return safeCall(() => updateEditingConfig(key, values[nextIndex]), 'config.saveFailed', 'config.saveSuccess');
};
// 重置配置
@@ -184,8 +254,7 @@ export const useConfigStore = defineStore('config', () => {
// 语言设置方法
const setLanguage = async (language: LanguageType): Promise<void> => {
await safeCall(async () => {
await ConfigService.Set(CONFIG_KEY_MAP.language, language);
state.config.language = language;
await updateAppearanceConfig('language', language);
// 同步更新前端语言
const frontendLocale = ConfigUtils.backendLanguageToFrontend(language);
@@ -193,12 +262,6 @@ export const useConfigStore = defineStore('config', () => {
}, 'config.languageChangeFailed', 'config.languageChanged');
};
// 通过前端语言代码设置语言
const setLocale = async (localeCode: SupportedLocaleType): Promise<void> => {
const backendLanguage = ConfigUtils.frontendLanguageToBackend(localeCode);
await setLanguage(backendLanguage);
};
// 初始化语言设置
const initializeLanguage = async (): Promise<void> => {
try {
@@ -208,7 +271,7 @@ export const useConfigStore = defineStore('config', () => {
}
// 同步前端语言设置
const frontendLocale = ConfigUtils.backendLanguageToFrontend(state.config.language);
const frontendLocale = ConfigUtils.backendLanguageToFrontend(state.config.appearance.language);
locale.value = frontendLocale as any;
} catch (error) {
const browserLang = getBrowserLanguage();
@@ -225,15 +288,16 @@ export const useConfigStore = defineStore('config', () => {
// 创建切换器实例
const togglers = {
tabIndent: createToggler('enableTabIndent'),
alwaysOnTop: createToggler('alwaysOnTop'),
tabIndent: createEditingToggler('enableTabIndent'),
alwaysOnTop: createGeneralToggler('alwaysOnTop'),
tabType: createEnumToggler('tabType', CONFIG_LIMITS.tabType.values)
};
// 字符串配置设置器
const setters = {
fontFamily: (value: string) => safeCall(() => updateConfig('fontFamily', value), 'config.saveFailed', 'config.saveSuccess'),
fontWeight: (value: string) => safeCall(() => updateConfig('fontWeight', value), 'config.saveFailed', 'config.saveSuccess')
fontFamily: (value: string) => safeCall(() => updateEditingConfig('fontFamily', value), 'config.saveFailed', 'config.saveSuccess'),
fontWeight: (value: string) => safeCall(() => updateEditingConfig('fontWeight', value), 'config.saveFailed', 'config.saveSuccess'),
dataPath: (value: string) => safeCall(() => updateGeneralConfig('dataPath', value), 'config.saveFailed', 'config.saveSuccess')
};
return {
@@ -248,11 +312,9 @@ export const useConfigStore = defineStore('config', () => {
// 核心方法
initConfig: () => safeCall(() => initConfig(), 'config.loadFailed', 'config.loadSuccess'),
resetConfig,
updateConfig: (key: keyof EditorConfig, value: any) => safeCall(() => updateConfig(key, value), 'config.saveFailed', 'config.saveSuccess'),
// 语言相关方法
setLanguage,
setLocale,
initializeLanguage,
// 字体大小操作
@@ -279,6 +341,9 @@ export const useConfigStore = defineStore('config', () => {
// 字体操作
setFontFamily: setters.fontFamily,
setFontWeight: setters.fontWeight,
// 路径操作
setDataPath: setters.dataPath,
};
},{
persist: true,

View File

@@ -33,7 +33,7 @@ export const useEditorStore = defineStore('editor', () => {
// 更新编辑器的字体大小
const editorDOM = editorView.value.dom;
if (editorDOM) {
editorDOM.style.fontSize = `${configStore.config.fontSize}px`;
editorDOM.style.fontSize = `${configStore.config.editing.fontSize}px`;
editorView.value?.requestMeasure();
}
}

View File

@@ -53,17 +53,17 @@ const createEditor = async () => {
// 获取Tab相关扩展
const tabExtensions = getTabExtensions(
configStore.config.tabSize,
configStore.config.enableTabIndent,
configStore.config.tabType
configStore.config.editing.tabSize,
configStore.config.editing.enableTabIndent,
configStore.config.editing.tabType
);
// 创建字体扩展
const fontExtension = createFontExtensionFromBackend({
fontFamily: configStore.config.fontFamily,
fontSize: configStore.config.fontSize,
lineHeight: configStore.config.lineHeight,
fontWeight: configStore.config.fontWeight
fontFamily: configStore.config.editing.fontFamily,
fontSize: configStore.config.editing.fontSize,
lineHeight: configStore.config.editing.lineHeight,
fontWeight: configStore.config.editing.fontWeight
});
// 创建统计信息更新扩展
@@ -148,9 +148,9 @@ const reconfigureTabSettings = () => {
if (!editorStore.editorView) return;
updateTabConfig(
editorStore.editorView as EditorView,
configStore.config.tabSize,
configStore.config.enableTabIndent,
configStore.config.tabType
configStore.config.editing.tabSize,
configStore.config.editing.enableTabIndent,
configStore.config.editing.tabType
);
};
@@ -158,33 +158,33 @@ const reconfigureTabSettings = () => {
const reconfigureFontSettings = () => {
if (!editorStore.editorView) return;
updateFontConfig(editorStore.editorView as EditorView, {
fontFamily: configStore.config.fontFamily,
fontSize: configStore.config.fontSize,
lineHeight: configStore.config.lineHeight,
fontWeight: configStore.config.fontWeight
fontFamily: configStore.config.editing.fontFamily,
fontSize: configStore.config.editing.fontSize,
lineHeight: configStore.config.editing.lineHeight,
fontWeight: configStore.config.editing.fontWeight
});
};
// 监听Tab设置变化
watch(() => configStore.config.tabSize, reconfigureTabSettings);
watch(() => configStore.config.enableTabIndent, reconfigureTabSettings);
watch(() => configStore.config.tabType, reconfigureTabSettings);
watch([
() => configStore.config.editing.tabSize,
() => configStore.config.editing.enableTabIndent,
() => configStore.config.editing.tabType,
], () => {
reconfigureTabSettings();
});
// 监听字体大小变化
watch(() => configStore.config.fontSize, () => {
watch([
() => configStore.config.editing.fontFamily,
() => configStore.config.editing.fontSize,
() => configStore.config.editing.lineHeight,
() => configStore.config.editing.fontWeight,
], () => {
reconfigureFontSettings();
editorStore.applyFontSize();
});
// 监听字体族变化
watch(() => configStore.config.fontFamily, reconfigureFontSettings);
// 监听字体粗细变化
watch(() => configStore.config.fontWeight, reconfigureFontSettings);
// 监听行高变化
watch(() => configStore.config.lineHeight, reconfigureFontSettings);
onMounted(() => {
// 创建编辑器
createEditor();

View File

@@ -47,7 +47,7 @@ const selectTheme = (themeId: string) => {
<div class="settings-page">
<SettingSection :title="t('settings.language')">
<SettingItem :title="t('settings.language')" :description="t('settings.restartRequired')">
<select class="select-input" :value="configStore.config.language" @change="updateLanguage">
<select class="select-input" :value="configStore.config.appearance.language" @change="updateLanguage">
<option v-for="option in languageOptions" :key="option.value" :value="option.value">
{{ option.label }}
</option>

View File

@@ -22,7 +22,7 @@ onMounted(async () => {
// 字体选择选项
const fontFamilyOptions = FONT_OPTIONS;
const currentFontFamily = computed(() => configStore.config.fontFamily);
const currentFontFamily = computed(() => configStore.config.editing.fontFamily);
// 字体选择
const handleFontFamilyChange = async (event: Event) => {
@@ -60,7 +60,7 @@ const handleFontWeightChange = async (event: Event) => {
// 行高控制
const increaseLineHeight = async () => {
const newLineHeight = Math.min(3.0, configStore.config.lineHeight + 0.1);
const newLineHeight = Math.min(3.0, configStore.config.editing.lineHeight + 0.1);
await safeCall(
() => configStore.setLineHeight(Math.round(newLineHeight * 10) / 10),
'config.lineHeightIncreaseFailed'
@@ -68,7 +68,7 @@ const increaseLineHeight = async () => {
};
const decreaseLineHeight = async () => {
const newLineHeight = Math.max(1.0, configStore.config.lineHeight - 0.1);
const newLineHeight = Math.max(1.0, configStore.config.editing.lineHeight - 0.1);
await safeCall(
() => configStore.setLineHeight(Math.round(newLineHeight * 10) / 10),
'config.lineHeightDecreaseFailed'
@@ -92,7 +92,7 @@ const decreaseFontSize = async () => {
// Tab类型切换
const tabTypeText = computed(() => {
return configStore.config.tabType === TabType.TabTypeSpaces
return configStore.config.editing.tabType === TabType.TabTypeSpaces
? t('settings.spaces')
: t('settings.tabs');
});
@@ -156,7 +156,7 @@ const handleToggleTabType = async () => {
>
<div class="number-control">
<button @click="decreaseFontSize" class="control-button">-</button>
<span>{{ configStore.config.fontSize }}px</span>
<span>{{ configStore.config.editing.fontSize }}px</span>
<button @click="increaseFontSize" class="control-button">+</button>
</div>
</SettingItem>
@@ -167,7 +167,7 @@ const handleToggleTabType = async () => {
>
<select
class="font-weight-select"
:value="configStore.config.fontWeight"
:value="configStore.config.editing.fontWeight"
@change="handleFontWeightChange"
>
<option
@@ -186,16 +186,16 @@ const handleToggleTabType = async () => {
>
<div class="number-control">
<button @click="decreaseLineHeight" class="control-button">-</button>
<span>{{ configStore.config.lineHeight.toFixed(1) }}</span>
<span>{{ configStore.config.editing.lineHeight.toFixed(1) }}</span>
<button @click="increaseLineHeight" class="control-button">+</button>
</div>
</SettingItem>
<div class="font-preview" :style="{
fontSize: `${configStore.config.fontSize}px`,
fontFamily: configStore.config.fontFamily,
fontWeight: configStore.config.fontWeight,
lineHeight: configStore.config.lineHeight
fontSize: `${configStore.config.editing.fontSize}px`,
fontFamily: configStore.config.editing.fontFamily,
fontWeight: configStore.config.editing.fontWeight,
lineHeight: configStore.config.editing.lineHeight
}">
<div class="preview-label">字体预览</div>
<div class="preview-text">
@@ -210,9 +210,9 @@ const handleToggleTabType = async () => {
<SettingSection :title="t('settings.tabSettings')">
<SettingItem :title="t('settings.tabSize')">
<div class="number-control">
<button @click="decreaseTabSize" class="control-button" :disabled="configStore.config.tabSize <= configStore.tabSize.min">-</button>
<span>{{ configStore.config.tabSize }}</span>
<button @click="increaseTabSize" class="control-button" :disabled="configStore.config.tabSize >= configStore.tabSize.max">+</button>
<button @click="decreaseTabSize" class="control-button" :disabled="configStore.config.editing.tabSize <= configStore.tabSize.min">-</button>
<span>{{ configStore.config.editing.tabSize }}</span>
<button @click="increaseTabSize" class="control-button" :disabled="configStore.config.editing.tabSize >= configStore.tabSize.max">+</button>
</div>
</SettingItem>
@@ -224,7 +224,7 @@ const handleToggleTabType = async () => {
<SettingItem :title="t('settings.enableTabIndent')">
<ToggleSwitch
v-model="configStore.config.enableTabIndent"
v-model="configStore.config.editing.enableTabIndent"
@update:modelValue="handleToggleTabIndent"
/>
</SettingItem>

View File

@@ -52,7 +52,7 @@ const resetSettings = async () => {
<div class="settings-page">
<SettingSection :title="t('settings.globalHotkey')">
<SettingItem :title="t('settings.enableGlobalHotkey')">
<ToggleSwitch v-model="configStore.config.alwaysOnTop" /> <!-- 此处使用alwaysOnTop作为示例 -->
<ToggleSwitch v-model="configStore.config.general.alwaysOnTop" /> <!-- 此处使用alwaysOnTop作为示例 -->
</SettingItem>
<div class="hotkey-selector">
@@ -87,19 +87,19 @@ const resetSettings = async () => {
<SettingSection :title="t('settings.window')">
<SettingItem :title="t('settings.showInSystemTray')">
<ToggleSwitch v-model="configStore.config.alwaysOnTop" /> <!-- 需要后端实现 -->
<ToggleSwitch v-model="configStore.config.general.alwaysOnTop" /> <!-- 需要后端实现 -->
</SettingItem>
<SettingItem :title="t('settings.alwaysOnTop')">
<ToggleSwitch v-model="configStore.config.alwaysOnTop" @update:modelValue="configStore.toggleAlwaysOnTop" />
<ToggleSwitch v-model="configStore.config.general.alwaysOnTop" @update:modelValue="configStore.toggleAlwaysOnTop" />
</SettingItem>
</SettingSection>
<SettingSection :title="t('settings.bufferFiles')">
<SettingItem :title="t('settings.useCustomLocation')">
<ToggleSwitch v-model="configStore.config.alwaysOnTop" /> <!-- 需要后端实现 -->
<ToggleSwitch v-model="configStore.config.general.alwaysOnTop" /> <!-- 需要后端实现 -->
</SettingItem>
<div class="directory-selector">
<div class="path-display">{{ configStore.config.alwaysOnTop ? 'C:/Custom/Path' : 'Default Location' }}</div>
<div class="path-display">{{ configStore.config.general.alwaysOnTop ? 'C:/Custom/Path' : 'Default Location' }}</div>
<button class="select-button">{{ t('settings.selectDirectory') }}</button>
</div>
</SettingSection>

View File

@@ -16,29 +16,6 @@ const (
TabTypeTab TabType = "tab"
)
// DocumentConfig 定义文档配置
type DocumentConfig struct {
// 自动保存延迟(毫秒)- 内容变更后多久自动保存
AutoSaveDelay int `json:"autoSaveDelay" yaml:"auto_save_delay" mapstructure:"auto_save_delay"`
// 变更字符阈值,超过此阈值立即触发保存
ChangeThreshold int `json:"changeThreshold" yaml:"change_threshold" mapstructure:"change_threshold"`
// 最小保存间隔(毫秒)- 两次保存之间的最小时间间隔避免频繁IO
MinSaveInterval int `json:"minSaveInterval" yaml:"min_save_interval" mapstructure:"min_save_interval"`
}
// EditorConfig 定义编辑器配置
type EditorConfig struct {
FontSize int `json:"fontSize" yaml:"font_size" mapstructure:"font_size"` // 字体大小
FontFamily string `json:"fontFamily" yaml:"font_family" mapstructure:"font_family"` // 字体族
FontWeight string `json:"fontWeight" yaml:"font_weight" mapstructure:"font_weight"` // 字体粗细
LineHeight float64 `json:"lineHeight" yaml:"line_height" mapstructure:"line_height"` // 行高
EnableTabIndent bool `json:"enableTabIndent" yaml:"enable_tab_indent" mapstructure:"enable_tab_indent"` // 是否启用Tab缩进
TabSize int `json:"tabSize" yaml:"tab_size" mapstructure:"tab_size"` // Tab大小
TabType TabType `json:"tabType" yaml:"tab_type" mapstructure:"tab_type"` // Tab类型空格或Tab
Language LanguageType `json:"language" yaml:"language" mapstructure:"language"` // 界面语言
AlwaysOnTop bool `json:"alwaysOnTop" yaml:"always_on_top" mapstructure:"always_on_top"` // 窗口是否置顶
}
// LanguageType 语言类型定义
type LanguageType string
@@ -49,17 +26,54 @@ const (
LangEnUS LanguageType = "en-US"
)
// PathsConfig 路径配置集合
type PathsConfig struct {
DataPath string `json:"dataPath" yaml:"data_path" mapstructure:"data_path"` // 数据存储路径
// GeneralConfig 通用设置配置
type GeneralConfig struct {
AlwaysOnTop bool `json:"alwaysOnTop" yaml:"always_on_top" mapstructure:"always_on_top"` // 窗口是否置顶
DataPath string `json:"dataPath" yaml:"data_path" mapstructure:"data_path"` // 数据存储路径
}
// AppConfig 应用配置 - 包含业务配置和路径配置
// EditingConfig 编辑设置配置
type EditingConfig struct {
// 字体设置
FontSize int `json:"fontSize" yaml:"font_size" mapstructure:"font_size"` // 字体大小
FontFamily string `json:"fontFamily" yaml:"font_family" mapstructure:"font_family"` // 字体族
FontWeight string `json:"fontWeight" yaml:"font_weight" mapstructure:"font_weight"` // 字体粗细
LineHeight float64 `json:"lineHeight" yaml:"line_height" mapstructure:"line_height"` // 行高
// Tab设置
EnableTabIndent bool `json:"enableTabIndent" yaml:"enable_tab_indent" mapstructure:"enable_tab_indent"` // 是否启用Tab缩进
TabSize int `json:"tabSize" yaml:"tab_size" mapstructure:"tab_size"` // Tab大小
TabType TabType `json:"tabType" yaml:"tab_type" mapstructure:"tab_type"` // Tab类型空格或Tab
// 保存选项
AutoSaveDelay int `json:"autoSaveDelay" yaml:"auto_save_delay" mapstructure:"auto_save_delay"` // 自动保存延迟(毫秒)
ChangeThreshold int `json:"changeThreshold" yaml:"change_threshold" mapstructure:"change_threshold"` // 变更字符阈值
MinSaveInterval int `json:"minSaveInterval" yaml:"min_save_interval" mapstructure:"min_save_interval"` // 最小保存间隔(毫秒)
}
// AppearanceConfig 外观设置配置
type AppearanceConfig struct {
Language LanguageType `json:"language" yaml:"language" mapstructure:"language"` // 界面语言
}
// KeyBindingsConfig 快捷键设置配置
type KeyBindingsConfig struct {
// 预留给未来的快捷键配置
}
// UpdatesConfig 更新设置配置
type UpdatesConfig struct {
// 预留给未来的更新配置
}
// AppConfig 应用配置 - 按照前端设置页面分类组织
type AppConfig struct {
Editor EditorConfig `json:"editor" yaml:"editor" mapstructure:"editor"` // 编辑器配
Document DocumentConfig `json:"document" yaml:"document" mapstructure:"document"` // 文档配
Paths PathsConfig `json:"paths" yaml:"paths" mapstructure:"paths"` // 路径配
Metadata ConfigMetadata `json:"metadata" yaml:"metadata" mapstructure:"metadata"` // 配置元数据
General GeneralConfig `json:"general" yaml:"general" mapstructure:"general"` // 通用设
Editing EditingConfig `json:"editing" yaml:"editing" mapstructure:"editing"` // 编辑设
Appearance AppearanceConfig `json:"appearance" yaml:"appearance" mapstructure:"appearance"` // 外观设
KeyBindings KeyBindingsConfig `json:"keyBindings" yaml:"key_bindings" mapstructure:"key_bindings"` // 快捷键设置
Updates UpdatesConfig `json:"updates" yaml:"updates" mapstructure:"updates"` // 更新设置
Metadata ConfigMetadata `json:"metadata" yaml:"metadata" mapstructure:"metadata"` // 配置元数据
}
// ConfigMetadata 配置元数据
@@ -80,24 +94,33 @@ func NewDefaultAppConfig() *AppConfig {
dataDir := filepath.Join(currentDir, "data")
return &AppConfig{
Editor: EditorConfig{
FontSize: 13,
FontFamily: `"HarmonyOS Sans SC", "HarmonyOS Sans", "Microsoft YaHei", "PingFang SC", "Helvetica Neue", Arial, sans-serif`,
FontWeight: "normal",
LineHeight: 1.5,
General: GeneralConfig{
AlwaysOnTop: false,
DataPath: dataDir,
},
Editing: EditingConfig{
// 字体设置
FontSize: 13,
FontFamily: `"HarmonyOS Sans SC", "HarmonyOS Sans", "Microsoft YaHei", "PingFang SC", "Helvetica Neue", Arial, sans-serif`,
FontWeight: "normal",
LineHeight: 1.5,
// Tab设置
EnableTabIndent: true,
TabSize: 4,
TabType: TabTypeSpaces,
Language: LangZhCN,
AlwaysOnTop: false,
},
Document: DocumentConfig{
// 保存选项
AutoSaveDelay: 5000, // 5秒后自动保存
ChangeThreshold: 500, // 500个字符变更触发保存
MinSaveInterval: 1000, // 最小间隔1000毫秒
},
Paths: PathsConfig{
DataPath: dataDir,
Appearance: AppearanceConfig{
Language: LangZhCN,
},
KeyBindings: KeyBindingsConfig{
// 预留给未来的快捷键配置
},
Updates: UpdatesConfig{
// 预留给未来的更新配置
},
Metadata: ConfigMetadata{
Version: "1.0.0",

View File

@@ -68,7 +68,7 @@ func (cs *ConfigService) validateAndFixValue(key string, value interface{}) (int
fixed := false
switch key {
case "editor.font_size":
case "editing.font_size":
if intVal, ok := value.(int); ok {
if intVal < limits.FontSizeMin {
cs.logger.Warning("Config: Font size too small, fixing", "original", intVal, "fixed", limits.FontSizeMin)
@@ -80,7 +80,7 @@ func (cs *ConfigService) validateAndFixValue(key string, value interface{}) (int
}
}
case "editor.tab_size":
case "editing.tab_size":
if intVal, ok := value.(int); ok {
if intVal < limits.TabSizeMin {
cs.logger.Warning("Config: Tab size too small, fixing", "original", intVal, "fixed", limits.TabSizeMin)
@@ -92,7 +92,7 @@ func (cs *ConfigService) validateAndFixValue(key string, value interface{}) (int
}
}
case "editor.tab_type":
case "editing.tab_type":
if strVal, ok := value.(string); ok {
validTypes := []string{string(models.TabTypeSpaces), string(models.TabTypeTab)}
isValid := false
@@ -108,7 +108,7 @@ func (cs *ConfigService) validateAndFixValue(key string, value interface{}) (int
}
}
case "editor.language":
case "appearance.language":
if strVal, ok := value.(string); ok {
validLanguages := []string{string(models.LangZhCN), string(models.LangEnUS)}
isValid := false
@@ -124,7 +124,7 @@ func (cs *ConfigService) validateAndFixValue(key string, value interface{}) (int
}
}
case "document.auto_save_delay":
case "editing.auto_save_delay":
if intVal, ok := value.(int); ok {
if intVal < 1000 {
cs.logger.Warning("Config: Auto save delay too small, fixing", "original", intVal, "fixed", 1000)
@@ -136,7 +136,7 @@ func (cs *ConfigService) validateAndFixValue(key string, value interface{}) (int
}
}
case "document.change_threshold":
case "editing.change_threshold":
if intVal, ok := value.(int); ok {
if intVal < 10 {
cs.logger.Warning("Config: Change threshold too small, fixing", "original", intVal, "fixed", 10)
@@ -148,7 +148,7 @@ func (cs *ConfigService) validateAndFixValue(key string, value interface{}) (int
}
}
case "document.min_save_interval":
case "editing.min_save_interval":
if intVal, ok := value.(int); ok {
if intVal < 100 {
cs.logger.Warning("Config: Min save interval too small, fixing", "original", intVal, "fixed", 100)
@@ -175,39 +175,39 @@ func (cs *ConfigService) validateAllConfig() error {
}
// 验证编辑器配置
if fixedValue, fixed := cs.validateAndFixValue("editor.font_size", config.Editor.FontSize); fixed {
cs.viper.Set("editor.font_size", fixedValue)
if fixedValue, fixed := cs.validateAndFixValue("editing.font_size", config.Editing.FontSize); fixed {
cs.viper.Set("editing.font_size", fixedValue)
hasChanges = true
}
if fixedValue, fixed := cs.validateAndFixValue("editor.tab_size", config.Editor.TabSize); fixed {
cs.viper.Set("editor.tab_size", fixedValue)
if fixedValue, fixed := cs.validateAndFixValue("editing.tab_size", config.Editing.TabSize); fixed {
cs.viper.Set("editing.tab_size", fixedValue)
hasChanges = true
}
if fixedValue, fixed := cs.validateAndFixValue("editor.tab_type", string(config.Editor.TabType)); fixed {
cs.viper.Set("editor.tab_type", fixedValue)
if fixedValue, fixed := cs.validateAndFixValue("editing.tab_type", string(config.Editing.TabType)); fixed {
cs.viper.Set("editing.tab_type", fixedValue)
hasChanges = true
}
if fixedValue, fixed := cs.validateAndFixValue("editor.language", string(config.Editor.Language)); fixed {
cs.viper.Set("editor.language", fixedValue)
if fixedValue, fixed := cs.validateAndFixValue("appearance.language", string(config.Appearance.Language)); fixed {
cs.viper.Set("appearance.language", fixedValue)
hasChanges = true
}
// 验证文档配置
if fixedValue, fixed := cs.validateAndFixValue("document.auto_save_delay", config.Document.AutoSaveDelay); fixed {
cs.viper.Set("document.auto_save_delay", fixedValue)
// 验证保存选项配置
if fixedValue, fixed := cs.validateAndFixValue("editing.auto_save_delay", config.Editing.AutoSaveDelay); fixed {
cs.viper.Set("editing.auto_save_delay", fixedValue)
hasChanges = true
}
if fixedValue, fixed := cs.validateAndFixValue("document.change_threshold", config.Document.ChangeThreshold); fixed {
cs.viper.Set("document.change_threshold", fixedValue)
if fixedValue, fixed := cs.validateAndFixValue("editing.change_threshold", config.Editing.ChangeThreshold); fixed {
cs.viper.Set("editing.change_threshold", fixedValue)
hasChanges = true
}
if fixedValue, fixed := cs.validateAndFixValue("document.min_save_interval", config.Document.MinSaveInterval); fixed {
cs.viper.Set("document.min_save_interval", fixedValue)
if fixedValue, fixed := cs.validateAndFixValue("editing.min_save_interval", config.Editing.MinSaveInterval); fixed {
cs.viper.Set("editing.min_save_interval", fixedValue)
hasChanges = true
}
@@ -280,24 +280,24 @@ func NewConfigService(logger *log.LoggerService) *ConfigService {
func setDefaults(v *viper.Viper) {
defaultConfig := models.NewDefaultAppConfig()
// 编辑器配置默认值
v.SetDefault("editor.font_size", defaultConfig.Editor.FontSize)
v.SetDefault("editor.font_family", defaultConfig.Editor.FontFamily)
v.SetDefault("editor.font_weight", defaultConfig.Editor.FontWeight)
v.SetDefault("editor.line_height", defaultConfig.Editor.LineHeight)
v.SetDefault("editor.enable_tab_indent", defaultConfig.Editor.EnableTabIndent)
v.SetDefault("editor.tab_size", defaultConfig.Editor.TabSize)
v.SetDefault("editor.tab_type", defaultConfig.Editor.TabType)
v.SetDefault("editor.language", defaultConfig.Editor.Language)
v.SetDefault("editor.always_on_top", defaultConfig.Editor.AlwaysOnTop)
// 通用设置默认值
v.SetDefault("general.always_on_top", defaultConfig.General.AlwaysOnTop)
v.SetDefault("general.data_path", defaultConfig.General.DataPath)
// 文档配置默认值
v.SetDefault("document.auto_save_delay", defaultConfig.Document.AutoSaveDelay)
v.SetDefault("document.change_threshold", defaultConfig.Document.ChangeThreshold)
v.SetDefault("document.min_save_interval", defaultConfig.Document.MinSaveInterval)
// 编辑设置默认值
v.SetDefault("editing.font_size", defaultConfig.Editing.FontSize)
v.SetDefault("editing.font_family", defaultConfig.Editing.FontFamily)
v.SetDefault("editing.font_weight", defaultConfig.Editing.FontWeight)
v.SetDefault("editing.line_height", defaultConfig.Editing.LineHeight)
v.SetDefault("editing.enable_tab_indent", defaultConfig.Editing.EnableTabIndent)
v.SetDefault("editing.tab_size", defaultConfig.Editing.TabSize)
v.SetDefault("editing.tab_type", defaultConfig.Editing.TabType)
v.SetDefault("editing.auto_save_delay", defaultConfig.Editing.AutoSaveDelay)
v.SetDefault("editing.change_threshold", defaultConfig.Editing.ChangeThreshold)
v.SetDefault("editing.min_save_interval", defaultConfig.Editing.MinSaveInterval)
// 路径配置默认值
v.SetDefault("paths.data_path", defaultConfig.Paths.DataPath)
// 外观设置默认值
v.SetDefault("appearance.language", defaultConfig.Appearance.Language)
// 元数据默认值
v.SetDefault("metadata.version", defaultConfig.Metadata.Version)

View File

@@ -147,9 +147,9 @@ func (ds *DocumentService) scheduleAutoSave() {
// 打印保存设置,便于调试
ds.logger.Debug("Document: Auto save settings",
"autoSaveDelay", config.Document.AutoSaveDelay,
"changeThreshold", config.Document.ChangeThreshold,
"minSaveInterval", config.Document.MinSaveInterval)
"autoSaveDelay", config.Editing.AutoSaveDelay,
"changeThreshold", config.Editing.ChangeThreshold,
"minSaveInterval", config.Editing.MinSaveInterval)
ds.lock.Lock()
defer ds.lock.Unlock()
@@ -160,7 +160,7 @@ func (ds *DocumentService) scheduleAutoSave() {
}
// 创建新的自动保存定时器
autoSaveDelay := config.Document.AutoSaveDelay
autoSaveDelay := config.Editing.AutoSaveDelay
ds.logger.Debug("Document: Scheduling auto save", "delay", autoSaveDelay)
ds.scheduleTimerWithDelay(autoSaveDelay)
}
@@ -197,7 +197,7 @@ func (ds *DocumentService) saveToStore(trigger SaveTrigger) {
// 如果成功获取了配置,使用配置值
if err == nil && config != nil {
minInterval = config.Document.MinSaveInterval
minInterval = config.Editing.MinSaveInterval
}
// 如果是自动保存,检查最小保存间隔
@@ -305,7 +305,7 @@ func (ds *DocumentService) ensureDocumentsDir() error {
}
// 创建文档目录
docsDir := filepath.Join(config.Paths.DataPath, "docs")
docsDir := filepath.Join(config.General.DataPath, "docs")
err = os.MkdirAll(docsDir, 0755)
if err != nil {
return err
@@ -320,7 +320,7 @@ func (ds *DocumentService) getDocumentsDir() (string, error) {
if err != nil {
return "", err
}
return filepath.Join(config.Paths.DataPath, "docs"), nil
return filepath.Join(config.General.DataPath, "docs"), nil
}
// getDefaultDocumentPath 获取默认文档路径
@@ -405,7 +405,7 @@ func (ds *DocumentService) UpdateActiveDocumentContent(content string) error {
// 如果成功获取了配置,使用配置值
if err == nil && config != nil {
threshold = config.Document.ChangeThreshold
threshold = config.Editing.ChangeThreshold
}
ds.lock.Lock()
@@ -520,26 +520,26 @@ func (ds *DocumentService) GetDiffInfo(oldText, newText string) DiffResult {
}
// GetSaveSettings 获取文档保存设置
func (ds *DocumentService) GetSaveSettings() (*models.DocumentConfig, error) {
func (ds *DocumentService) GetSaveSettings() (*models.EditingConfig, error) {
config, err := ds.configService.GetConfig()
if err != nil {
return nil, &DocumentError{Operation: "get_save_settings", Err: err}
}
return &config.Document, nil
return &config.Editing, nil
}
// UpdateSaveSettings 更新文档保存设置
func (ds *DocumentService) UpdateSaveSettings(docConfig models.DocumentConfig) error {
func (ds *DocumentService) UpdateSaveSettings(docConfig models.EditingConfig) error {
// 使用配置服务的 Set 方法更新文档配置
if err := ds.configService.Set("document.auto_save_delay", docConfig.AutoSaveDelay); err != nil {
if err := ds.configService.Set("editing.auto_save_delay", docConfig.AutoSaveDelay); err != nil {
return &DocumentError{Operation: "update_save_settings_auto_save_delay", Err: err}
}
if err := ds.configService.Set("document.change_threshold", docConfig.ChangeThreshold); err != nil {
if err := ds.configService.Set("editing.change_threshold", docConfig.ChangeThreshold); err != nil {
return &DocumentError{Operation: "update_save_settings_change_threshold", Err: err}
}
if err := ds.configService.Set("document.min_save_interval", docConfig.MinSaveInterval); err != nil {
if err := ds.configService.Set("editing.min_save_interval", docConfig.MinSaveInterval); err != nil {
return &DocumentError{Operation: "update_save_settings_min_save_interval", Err: err}
}