✨ Added key binding service
This commit is contained in:
@@ -40,50 +40,45 @@ const (
|
||||
|
||||
// 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"` // 数据存储路径
|
||||
EnableSystemTray bool `json:"enableSystemTray" yaml:"enable_system_tray" mapstructure:"enable_system_tray"` // 是否启用系统托盘
|
||||
AlwaysOnTop bool `json:"alwaysOnTop"` // 窗口是否置顶
|
||||
DataPath string `json:"dataPath"` // 数据存储路径
|
||||
EnableSystemTray bool `json:"enableSystemTray"` // 是否启用系统托盘
|
||||
|
||||
// 全局热键设置
|
||||
EnableGlobalHotkey bool `json:"enableGlobalHotkey" yaml:"enable_global_hotkey" mapstructure:"enable_global_hotkey"` // 是否启用全局热键
|
||||
GlobalHotkey HotkeyCombo `json:"globalHotkey" yaml:"global_hotkey" mapstructure:"global_hotkey"` // 全局热键组合
|
||||
EnableGlobalHotkey bool `json:"enableGlobalHotkey"` // 是否启用全局热键
|
||||
GlobalHotkey HotkeyCombo `json:"globalHotkey"` // 全局热键组合
|
||||
}
|
||||
|
||||
// HotkeyCombo 热键组合定义
|
||||
type HotkeyCombo struct {
|
||||
Ctrl bool `json:"ctrl" yaml:"ctrl" mapstructure:"ctrl"` // Ctrl键
|
||||
Shift bool `json:"shift" yaml:"shift" mapstructure:"shift"` // Shift键
|
||||
Alt bool `json:"alt" yaml:"alt" mapstructure:"alt"` // Alt键
|
||||
Win bool `json:"win" yaml:"win" mapstructure:"win"` // Win键
|
||||
Key string `json:"key" yaml:"key" mapstructure:"key"` // 主键(如 'X', 'F1' 等)
|
||||
Ctrl bool `json:"ctrl"` // Ctrl键
|
||||
Shift bool `json:"shift"` // Shift键
|
||||
Alt bool `json:"alt"` // Alt键
|
||||
Win bool `json:"win"` // Win键
|
||||
Key string `json:"key"` // 主键(如 'X', 'F1' 等)
|
||||
}
|
||||
|
||||
// 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"` // 行高
|
||||
FontSize int `json:"fontSize"` // 字体大小
|
||||
FontFamily string `json:"fontFamily"` // 字体族
|
||||
FontWeight string `json:"fontWeight"` // 字体粗细
|
||||
LineHeight float64 `json:"lineHeight"` // 行高
|
||||
|
||||
// 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)
|
||||
EnableTabIndent bool `json:"enableTabIndent"` // 是否启用Tab缩进
|
||||
TabSize int `json:"tabSize"` // Tab大小
|
||||
TabType TabType `json:"tabType"` // Tab类型(空格或Tab)
|
||||
|
||||
// 保存选项
|
||||
AutoSaveDelay int `json:"autoSaveDelay" yaml:"auto_save_delay" mapstructure:"auto_save_delay"` // 自动保存延迟(毫秒)
|
||||
AutoSaveDelay int `json:"autoSaveDelay"` // 自动保存延迟(毫秒)
|
||||
}
|
||||
|
||||
// AppearanceConfig 外观设置配置
|
||||
type AppearanceConfig struct {
|
||||
Language LanguageType `json:"language" yaml:"language" mapstructure:"language"` // 界面语言
|
||||
SystemTheme SystemThemeType `json:"systemTheme" yaml:"system_theme" mapstructure:"system_theme"` // 系统界面主题
|
||||
}
|
||||
|
||||
// KeyBindingsConfig 快捷键设置配置
|
||||
type KeyBindingsConfig struct {
|
||||
// 预留给未来的快捷键配置
|
||||
Language LanguageType `json:"language"` // 界面语言
|
||||
SystemTheme SystemThemeType `json:"systemTheme"` // 系统界面主题
|
||||
}
|
||||
|
||||
// UpdatesConfig 更新设置配置
|
||||
@@ -93,18 +88,16 @@ type UpdatesConfig struct {
|
||||
|
||||
// AppConfig 应用配置 - 按照前端设置页面分类组织
|
||||
type AppConfig struct {
|
||||
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"` // 配置元数据
|
||||
General GeneralConfig `json:"general"` // 通用设置
|
||||
Editing EditingConfig `json:"editing"` // 编辑设置
|
||||
Appearance AppearanceConfig `json:"appearance"` // 外观设置
|
||||
Updates UpdatesConfig `json:"updates"` // 更新设置
|
||||
Metadata ConfigMetadata `json:"metadata"` // 配置元数据
|
||||
}
|
||||
|
||||
// ConfigMetadata 配置元数据
|
||||
type ConfigMetadata struct {
|
||||
Version string `json:"version" yaml:"version" mapstructure:"version"` // 配置版本
|
||||
LastUpdated time.Time `json:"lastUpdated" yaml:"last_updated" mapstructure:"last_updated"` // 最后更新时间
|
||||
LastUpdated string `json:"lastUpdated"` // 最后更新时间
|
||||
}
|
||||
|
||||
// NewDefaultAppConfig 创建默认应用配置
|
||||
@@ -149,15 +142,9 @@ func NewDefaultAppConfig() *AppConfig {
|
||||
Language: LangZhCN,
|
||||
SystemTheme: SystemThemeDark, // 默认使用深色系统主题
|
||||
},
|
||||
KeyBindings: KeyBindingsConfig{
|
||||
// 预留给未来的快捷键配置
|
||||
},
|
||||
Updates: UpdatesConfig{
|
||||
// 预留给未来的更新配置
|
||||
},
|
||||
Updates: UpdatesConfig{},
|
||||
Metadata: ConfigMetadata{
|
||||
Version: "1.0.0",
|
||||
LastUpdated: time.Now(),
|
||||
LastUpdated: time.Now().Format(time.RFC3339),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
462
internal/models/key_bindings.go
Normal file
462
internal/models/key_bindings.go
Normal file
@@ -0,0 +1,462 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
// KeyBinding 单个快捷键绑定
|
||||
type KeyBinding struct {
|
||||
ID string `json:"id"` // 快捷键唯一标识
|
||||
Action KeyBindingAction `json:"action"` // 快捷键动作
|
||||
Category KeyBindingCategory `json:"category"` // 快捷键分类
|
||||
Scope KeyBindingScope `json:"scope"` // 快捷键作用域
|
||||
Key string `json:"key"` // 快捷键组合(如 "Mod-f", "Ctrl-Shift-p")
|
||||
Enabled bool `json:"enabled"` // 是否启用
|
||||
IsDefault bool `json:"isDefault"` // 是否为默认快捷键
|
||||
}
|
||||
|
||||
// KeyBindingCategory 快捷键分类
|
||||
type KeyBindingCategory string
|
||||
|
||||
const (
|
||||
CategorySearch KeyBindingCategory = "search" // 搜索相关
|
||||
CategoryEdit KeyBindingCategory = "edit" // 编辑相关
|
||||
CategoryCodeBlock KeyBindingCategory = "codeblock" // 代码块相关
|
||||
CategoryNavigation KeyBindingCategory = "navigation" // 导航相关
|
||||
CategoryView KeyBindingCategory = "view" // 视图相关
|
||||
CategoryFile KeyBindingCategory = "file" // 文件相关
|
||||
CategoryApp KeyBindingCategory = "app" // 应用相关
|
||||
)
|
||||
|
||||
// KeyBindingScope 快捷键作用域
|
||||
type KeyBindingScope string
|
||||
|
||||
const (
|
||||
ScopeGlobal KeyBindingScope = "global" // 全局作用域
|
||||
ScopeEditor KeyBindingScope = "editor" // 编辑器作用域
|
||||
ScopeSearch KeyBindingScope = "search" // 搜索面板作用域
|
||||
)
|
||||
|
||||
// KeyBindingAction 快捷键动作类型
|
||||
type KeyBindingAction string
|
||||
|
||||
const (
|
||||
// 搜索相关
|
||||
ActionShowSearch KeyBindingAction = "showSearch" // 显示搜索
|
||||
ActionHideSearch KeyBindingAction = "hideSearch" // 隐藏搜索
|
||||
ActionFindNext KeyBindingAction = "findNext" // 查找下一个
|
||||
ActionFindPrevious KeyBindingAction = "findPrevious" // 查找上一个
|
||||
ActionShowReplace KeyBindingAction = "showReplace" // 显示替换
|
||||
ActionReplaceNext KeyBindingAction = "replaceNext" // 替换下一个
|
||||
ActionReplaceAll KeyBindingAction = "replaceAll" // 替换全部
|
||||
ActionToggleCase KeyBindingAction = "toggleCase" // 切换大小写匹配
|
||||
ActionToggleWholeWord KeyBindingAction = "toggleWholeWord" // 切换全词匹配
|
||||
ActionToggleRegex KeyBindingAction = "toggleRegex" // 切换正则表达式
|
||||
|
||||
// 编辑相关
|
||||
ActionSelectAll KeyBindingAction = "selectAll" // 全选
|
||||
ActionCopy KeyBindingAction = "copy" // 复制
|
||||
ActionCut KeyBindingAction = "cut" // 剪切
|
||||
ActionPaste KeyBindingAction = "paste" // 粘贴
|
||||
ActionUndo KeyBindingAction = "undo" // 撤销
|
||||
ActionRedo KeyBindingAction = "redo" // 重做
|
||||
ActionDuplicateLine KeyBindingAction = "duplicateLine" // 复制行
|
||||
ActionDeleteLine KeyBindingAction = "deleteLine" // 删除行
|
||||
ActionMoveLineUp KeyBindingAction = "moveLineUp" // 上移行
|
||||
ActionMoveLineDown KeyBindingAction = "moveLineDown" // 下移行
|
||||
ActionToggleComment KeyBindingAction = "toggleComment" // 切换注释
|
||||
ActionIndent KeyBindingAction = "indent" // 缩进
|
||||
ActionOutdent KeyBindingAction = "outdent" // 取消缩进
|
||||
|
||||
// 代码块相关
|
||||
ActionNewCodeBlock KeyBindingAction = "newCodeBlock" // 新建代码块
|
||||
ActionDeleteCodeBlock KeyBindingAction = "deleteCodeBlock" // 删除代码块
|
||||
ActionSelectCodeBlock KeyBindingAction = "selectCodeBlock" // 选择代码块
|
||||
ActionFormatCode KeyBindingAction = "formatCode" // 格式化代码
|
||||
ActionChangeLanguage KeyBindingAction = "changeLanguage" // 更改语言
|
||||
|
||||
// 导航相关
|
||||
ActionGoToLine KeyBindingAction = "goToLine" // 跳转到行
|
||||
ActionFoldAll KeyBindingAction = "foldAll" // 折叠所有
|
||||
ActionUnfoldAll KeyBindingAction = "unfoldAll" // 展开所有
|
||||
ActionToggleFold KeyBindingAction = "toggleFold" // 切换折叠
|
||||
|
||||
// 视图相关
|
||||
ActionZoomIn KeyBindingAction = "zoomIn" // 放大
|
||||
ActionZoomOut KeyBindingAction = "zoomOut" // 缩小
|
||||
ActionResetZoom KeyBindingAction = "resetZoom" // 重置缩放
|
||||
ActionToggleMinimap KeyBindingAction = "toggleMinimap" // 切换小地图
|
||||
ActionToggleLineNumbers KeyBindingAction = "toggleLineNumbers" // 切换行号
|
||||
|
||||
// 文件相关
|
||||
ActionSave KeyBindingAction = "save" // 保存
|
||||
)
|
||||
|
||||
// KeyBindingMetadata 快捷键配置元数据
|
||||
type KeyBindingMetadata struct {
|
||||
LastUpdated string `json:"lastUpdated"` // 最后更新时间
|
||||
}
|
||||
|
||||
// KeyBindingConfig 快捷键配置
|
||||
type KeyBindingConfig struct {
|
||||
KeyBindings []KeyBinding `json:"keyBindings"` // 快捷键列表
|
||||
Metadata KeyBindingMetadata `json:"metadata"` // 配置元数据
|
||||
}
|
||||
|
||||
// NewDefaultKeyBindingConfig 创建默认快捷键配置
|
||||
func NewDefaultKeyBindingConfig() *KeyBindingConfig {
|
||||
return &KeyBindingConfig{
|
||||
KeyBindings: NewDefaultKeyBindings(),
|
||||
Metadata: KeyBindingMetadata{
|
||||
LastUpdated: time.Now().Format(time.RFC3339),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewDefaultKeyBindings 创建默认快捷键配置
|
||||
func NewDefaultKeyBindings() []KeyBinding {
|
||||
return []KeyBinding{
|
||||
// 搜索相关快捷键
|
||||
{
|
||||
ID: "search.show",
|
||||
Action: ActionShowSearch,
|
||||
Category: CategorySearch,
|
||||
Scope: ScopeGlobal,
|
||||
Key: "Mod-f",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "search.hide",
|
||||
Action: ActionHideSearch,
|
||||
Category: CategorySearch,
|
||||
Scope: ScopeSearch,
|
||||
Key: "Escape",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "search.findNext",
|
||||
Action: ActionFindNext,
|
||||
Category: CategorySearch,
|
||||
Scope: ScopeSearch,
|
||||
Key: "Enter",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "search.findPrevious",
|
||||
Action: ActionFindPrevious,
|
||||
Category: CategorySearch,
|
||||
Scope: ScopeSearch,
|
||||
Key: "Shift-Enter",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "search.showReplace",
|
||||
Action: ActionShowReplace,
|
||||
Category: CategorySearch,
|
||||
Scope: ScopeSearch,
|
||||
Key: "Mod-h",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "search.replaceAll",
|
||||
Action: ActionReplaceAll,
|
||||
Category: CategorySearch,
|
||||
Scope: ScopeSearch,
|
||||
Key: "Mod-Alt-Enter",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "search.toggleCase",
|
||||
Action: ActionToggleCase,
|
||||
Category: CategorySearch,
|
||||
Scope: ScopeSearch,
|
||||
Key: "Alt-c",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "search.toggleWholeWord",
|
||||
Action: ActionToggleWholeWord,
|
||||
Category: CategorySearch,
|
||||
Scope: ScopeSearch,
|
||||
Key: "Alt-w",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "search.toggleRegex",
|
||||
Action: ActionToggleRegex,
|
||||
Category: CategorySearch,
|
||||
Scope: ScopeSearch,
|
||||
Key: "Alt-r",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
|
||||
// 编辑相关快捷键
|
||||
{
|
||||
ID: "edit.selectAll",
|
||||
Action: ActionSelectAll,
|
||||
Category: CategoryEdit,
|
||||
Scope: ScopeEditor,
|
||||
Key: "Mod-a",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "edit.copy",
|
||||
Action: ActionCopy,
|
||||
Category: CategoryEdit,
|
||||
Scope: ScopeEditor,
|
||||
Key: "Mod-c",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "edit.cut",
|
||||
Action: ActionCut,
|
||||
Category: CategoryEdit,
|
||||
Scope: ScopeEditor,
|
||||
Key: "Mod-x",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "edit.paste",
|
||||
Action: ActionPaste,
|
||||
Category: CategoryEdit,
|
||||
Scope: ScopeEditor,
|
||||
Key: "Mod-v",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "edit.undo",
|
||||
Action: ActionUndo,
|
||||
Category: CategoryEdit,
|
||||
Scope: ScopeEditor,
|
||||
Key: "Mod-z",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "edit.redo",
|
||||
Action: ActionRedo,
|
||||
Category: CategoryEdit,
|
||||
Scope: ScopeEditor,
|
||||
Key: "Mod-y",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "edit.duplicateLine",
|
||||
Action: ActionDuplicateLine,
|
||||
Category: CategoryEdit,
|
||||
Scope: ScopeEditor,
|
||||
Key: "Mod-d",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "edit.deleteLine",
|
||||
Action: ActionDeleteLine,
|
||||
Category: CategoryEdit,
|
||||
Scope: ScopeEditor,
|
||||
Key: "Mod-Shift-k",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "edit.moveLineUp",
|
||||
Action: ActionMoveLineUp,
|
||||
Category: CategoryEdit,
|
||||
Scope: ScopeEditor,
|
||||
Key: "Alt-ArrowUp",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "edit.moveLineDown",
|
||||
Action: ActionMoveLineDown,
|
||||
Category: CategoryEdit,
|
||||
Scope: ScopeEditor,
|
||||
Key: "Alt-ArrowDown",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "edit.toggleComment",
|
||||
Action: ActionToggleComment,
|
||||
Category: CategoryEdit,
|
||||
Scope: ScopeEditor,
|
||||
Key: "Mod-/",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "edit.indent",
|
||||
Action: ActionIndent,
|
||||
Category: CategoryEdit,
|
||||
Scope: ScopeEditor,
|
||||
Key: "Tab",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "edit.outdent",
|
||||
Action: ActionOutdent,
|
||||
Category: CategoryEdit,
|
||||
Scope: ScopeEditor,
|
||||
Key: "Shift-Tab",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
|
||||
// 代码块相关快捷键
|
||||
{
|
||||
ID: "codeblock.new",
|
||||
Action: ActionNewCodeBlock,
|
||||
Category: CategoryCodeBlock,
|
||||
Scope: ScopeEditor,
|
||||
Key: "Mod-Alt-n",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "codeblock.delete",
|
||||
Action: ActionDeleteCodeBlock,
|
||||
Category: CategoryCodeBlock,
|
||||
Scope: ScopeEditor,
|
||||
Key: "Mod-Alt-d",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "codeblock.select",
|
||||
Action: ActionSelectCodeBlock,
|
||||
Category: CategoryCodeBlock,
|
||||
Scope: ScopeEditor,
|
||||
Key: "Mod-Alt-a",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "codeblock.format",
|
||||
Action: ActionFormatCode,
|
||||
Category: CategoryCodeBlock,
|
||||
Scope: ScopeEditor,
|
||||
Key: "Mod-Alt-f",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "codeblock.changeLanguage",
|
||||
Action: ActionChangeLanguage,
|
||||
Category: CategoryCodeBlock,
|
||||
Scope: ScopeEditor,
|
||||
Key: "Mod-Alt-l",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
|
||||
// 导航相关快捷键
|
||||
{
|
||||
ID: "navigation.goToLine",
|
||||
Action: ActionGoToLine,
|
||||
Category: CategoryNavigation,
|
||||
Scope: ScopeEditor,
|
||||
Key: "Mod-g",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "navigation.foldAll",
|
||||
Action: ActionFoldAll,
|
||||
Category: CategoryNavigation,
|
||||
Scope: ScopeEditor,
|
||||
Key: "Mod-k Mod-0",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "navigation.unfoldAll",
|
||||
Action: ActionUnfoldAll,
|
||||
Category: CategoryNavigation,
|
||||
Scope: ScopeEditor,
|
||||
Key: "Mod-k Mod-j",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "navigation.toggleFold",
|
||||
Action: ActionToggleFold,
|
||||
Category: CategoryNavigation,
|
||||
Scope: ScopeEditor,
|
||||
Key: "Mod-k Mod-l",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
|
||||
// 视图相关快捷键
|
||||
{
|
||||
ID: "view.zoomIn",
|
||||
Action: ActionZoomIn,
|
||||
Category: CategoryView,
|
||||
Scope: ScopeGlobal,
|
||||
Key: "Mod-=",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "view.zoomOut",
|
||||
Action: ActionZoomOut,
|
||||
Category: CategoryView,
|
||||
Scope: ScopeGlobal,
|
||||
Key: "Mod--",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "view.resetZoom",
|
||||
Action: ActionResetZoom,
|
||||
Category: CategoryView,
|
||||
Scope: ScopeGlobal,
|
||||
Key: "Mod-0",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "view.toggleMinimap",
|
||||
Action: ActionToggleMinimap,
|
||||
Category: CategoryView,
|
||||
Scope: ScopeGlobal,
|
||||
Key: "Mod-m",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
{
|
||||
ID: "view.toggleLineNumbers",
|
||||
Action: ActionToggleLineNumbers,
|
||||
Category: CategoryView,
|
||||
Scope: ScopeGlobal,
|
||||
Key: "Mod-l",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
|
||||
// 文件相关快捷键
|
||||
{
|
||||
ID: "file.save",
|
||||
Action: ActionSave,
|
||||
Category: CategoryFile,
|
||||
Scope: ScopeGlobal,
|
||||
Key: "Mod-s",
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
},
|
||||
}
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
@@ -62,14 +63,14 @@ func NewConfigService(logger *log.LoggerService) *ConfigService {
|
||||
|
||||
// 固定配置路径和文件名
|
||||
configPath := filepath.Join(currentDir, "config")
|
||||
configName := "config"
|
||||
configName := "settings"
|
||||
|
||||
// 创建 Viper 实例
|
||||
v := viper.New()
|
||||
|
||||
// 配置 Viper
|
||||
v.SetConfigName(configName)
|
||||
v.SetConfigType("yaml")
|
||||
v.SetConfigType("json")
|
||||
v.AddConfigPath(configPath)
|
||||
|
||||
// 设置环境变量前缀
|
||||
@@ -104,33 +105,32 @@ func setDefaults(v *viper.Viper) {
|
||||
defaultConfig := models.NewDefaultAppConfig()
|
||||
|
||||
// 通用设置默认值
|
||||
v.SetDefault("general.always_on_top", defaultConfig.General.AlwaysOnTop)
|
||||
v.SetDefault("general.data_path", defaultConfig.General.DataPath)
|
||||
v.SetDefault("general.enable_system_tray", defaultConfig.General.EnableSystemTray)
|
||||
v.SetDefault("general.enable_global_hotkey", defaultConfig.General.EnableGlobalHotkey)
|
||||
v.SetDefault("general.global_hotkey.ctrl", defaultConfig.General.GlobalHotkey.Ctrl)
|
||||
v.SetDefault("general.global_hotkey.shift", defaultConfig.General.GlobalHotkey.Shift)
|
||||
v.SetDefault("general.global_hotkey.alt", defaultConfig.General.GlobalHotkey.Alt)
|
||||
v.SetDefault("general.global_hotkey.win", defaultConfig.General.GlobalHotkey.Win)
|
||||
v.SetDefault("general.global_hotkey.key", defaultConfig.General.GlobalHotkey.Key)
|
||||
v.SetDefault("general.alwaysOnTop", defaultConfig.General.AlwaysOnTop)
|
||||
v.SetDefault("general.dataPath", defaultConfig.General.DataPath)
|
||||
v.SetDefault("general.enableSystemTray", defaultConfig.General.EnableSystemTray)
|
||||
v.SetDefault("general.enableGlobalHotkey", defaultConfig.General.EnableGlobalHotkey)
|
||||
v.SetDefault("general.globalHotkey.ctrl", defaultConfig.General.GlobalHotkey.Ctrl)
|
||||
v.SetDefault("general.globalHotkey.shift", defaultConfig.General.GlobalHotkey.Shift)
|
||||
v.SetDefault("general.globalHotkey.alt", defaultConfig.General.GlobalHotkey.Alt)
|
||||
v.SetDefault("general.globalHotkey.win", defaultConfig.General.GlobalHotkey.Win)
|
||||
v.SetDefault("general.globalHotkey.key", defaultConfig.General.GlobalHotkey.Key)
|
||||
|
||||
// 编辑设置默认值
|
||||
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.fontSize", defaultConfig.Editing.FontSize)
|
||||
v.SetDefault("editing.fontFamily", defaultConfig.Editing.FontFamily)
|
||||
v.SetDefault("editing.fontWeight", defaultConfig.Editing.FontWeight)
|
||||
v.SetDefault("editing.lineHeight", defaultConfig.Editing.LineHeight)
|
||||
v.SetDefault("editing.enableTabIndent", defaultConfig.Editing.EnableTabIndent)
|
||||
v.SetDefault("editing.tabSize", defaultConfig.Editing.TabSize)
|
||||
v.SetDefault("editing.tabType", defaultConfig.Editing.TabType)
|
||||
v.SetDefault("editing.autoSaveDelay", defaultConfig.Editing.AutoSaveDelay)
|
||||
|
||||
// 外观设置默认值
|
||||
v.SetDefault("appearance.language", defaultConfig.Appearance.Language)
|
||||
v.SetDefault("appearance.system_theme", defaultConfig.Appearance.SystemTheme)
|
||||
v.SetDefault("appearance.systemTheme", defaultConfig.Appearance.SystemTheme)
|
||||
|
||||
// 元数据默认值
|
||||
v.SetDefault("metadata.version", defaultConfig.Metadata.Version)
|
||||
v.SetDefault("metadata.last_updated", defaultConfig.Metadata.LastUpdated)
|
||||
v.SetDefault("metadata.lastUpdated", defaultConfig.Metadata.LastUpdated)
|
||||
}
|
||||
|
||||
// initConfig 初始化配置
|
||||
@@ -162,21 +162,32 @@ func (cs *ConfigService) createDefaultConfig() error {
|
||||
currentDir = "."
|
||||
}
|
||||
configDir := filepath.Join(currentDir, "config")
|
||||
configPath := filepath.Join(configDir, "config.yaml")
|
||||
configPath := filepath.Join(configDir, "settings.json")
|
||||
|
||||
// 确保配置目录存在
|
||||
if err := os.MkdirAll(configDir, 0755); err != nil {
|
||||
return &ConfigError{Operation: "create_config_dir", Err: err}
|
||||
}
|
||||
|
||||
// 设置当前时间为最后更新时间
|
||||
cs.viper.Set("metadata.last_updated", time.Now())
|
||||
// 获取默认配置
|
||||
defaultConfig := models.NewDefaultAppConfig()
|
||||
|
||||
// 使用 SafeWriteConfigAs 写入配置文件(如果文件不存在则创建)
|
||||
if err := cs.viper.SafeWriteConfigAs(configPath); err != nil {
|
||||
// 使用 JSON marshal 方式设置完整的默认配置
|
||||
configBytes, err := json.MarshalIndent(defaultConfig, "", " ")
|
||||
if err != nil {
|
||||
return &ConfigError{Operation: "marshal_default_config", Err: err}
|
||||
}
|
||||
|
||||
// 写入配置文件
|
||||
if err := os.WriteFile(configPath, configBytes, 0644); err != nil {
|
||||
return &ConfigError{Operation: "write_default_config", Err: err}
|
||||
}
|
||||
|
||||
// 重新读取配置文件到viper
|
||||
if err := cs.viper.ReadInConfig(); err != nil {
|
||||
return &ConfigError{Operation: "read_created_config", Err: err}
|
||||
}
|
||||
|
||||
cs.logger.Info("Config: Created default config file", "path", configPath)
|
||||
return nil
|
||||
}
|
||||
@@ -213,11 +224,21 @@ func (cs *ConfigService) GetConfig() (*models.AppConfig, error) {
|
||||
func (cs *ConfigService) Set(key string, value interface{}) error {
|
||||
cs.mu.Lock()
|
||||
defer cs.mu.Unlock()
|
||||
// 设置验证后的值
|
||||
|
||||
// 设置值到viper
|
||||
cs.viper.Set(key, value)
|
||||
|
||||
// 使用 WriteConfig 写入配置文件(会触发文件监听)
|
||||
if err := cs.viper.WriteConfig(); err != nil {
|
||||
// 直接从viper获取配置并构建AppConfig结构
|
||||
var config models.AppConfig
|
||||
if err := cs.viper.Unmarshal(&config); err != nil {
|
||||
return &ConfigError{Operation: "unmarshal_config_for_set", Err: err}
|
||||
}
|
||||
|
||||
// 更新时间戳
|
||||
config.Metadata.LastUpdated = time.Now().Format(time.RFC3339)
|
||||
|
||||
// 直接写入JSON文件
|
||||
if err := cs.writeConfigToFile(&config); err != nil {
|
||||
return &ConfigError{Operation: "set_config", Err: err}
|
||||
}
|
||||
|
||||
@@ -238,43 +259,49 @@ func (cs *ConfigService) ResetConfig() {
|
||||
|
||||
defaultConfig := models.NewDefaultAppConfig()
|
||||
|
||||
// 通用设置 - 批量设置到viper中
|
||||
cs.viper.Set("general.always_on_top", defaultConfig.General.AlwaysOnTop)
|
||||
cs.viper.Set("general.data_path", defaultConfig.General.DataPath)
|
||||
cs.viper.Set("general.enable_system_tray", defaultConfig.General.EnableSystemTray)
|
||||
cs.viper.Set("general.enable_global_hotkey", defaultConfig.General.EnableGlobalHotkey)
|
||||
cs.viper.Set("general.global_hotkey.ctrl", defaultConfig.General.GlobalHotkey.Ctrl)
|
||||
cs.viper.Set("general.global_hotkey.shift", defaultConfig.General.GlobalHotkey.Shift)
|
||||
cs.viper.Set("general.global_hotkey.alt", defaultConfig.General.GlobalHotkey.Alt)
|
||||
cs.viper.Set("general.global_hotkey.win", defaultConfig.General.GlobalHotkey.Win)
|
||||
cs.viper.Set("general.global_hotkey.key", defaultConfig.General.GlobalHotkey.Key)
|
||||
|
||||
// 编辑设置 - 批量设置到viper中
|
||||
cs.viper.Set("editing.font_size", defaultConfig.Editing.FontSize)
|
||||
cs.viper.Set("editing.font_family", defaultConfig.Editing.FontFamily)
|
||||
cs.viper.Set("editing.font_weight", defaultConfig.Editing.FontWeight)
|
||||
cs.viper.Set("editing.line_height", defaultConfig.Editing.LineHeight)
|
||||
cs.viper.Set("editing.enable_tab_indent", defaultConfig.Editing.EnableTabIndent)
|
||||
cs.viper.Set("editing.tab_size", defaultConfig.Editing.TabSize)
|
||||
cs.viper.Set("editing.tab_type", defaultConfig.Editing.TabType)
|
||||
cs.viper.Set("editing.auto_save_delay", defaultConfig.Editing.AutoSaveDelay)
|
||||
|
||||
// 外观设置 - 批量设置到viper中
|
||||
cs.viper.Set("appearance.language", defaultConfig.Appearance.Language)
|
||||
cs.viper.Set("appearance.system_theme", defaultConfig.Appearance.SystemTheme)
|
||||
|
||||
// 元数据 - 批量设置到viper中
|
||||
cs.viper.Set("metadata.version", defaultConfig.Metadata.Version)
|
||||
cs.viper.Set("metadata.last_updated", time.Now())
|
||||
|
||||
// 一次性写入配置文件,触发配置变更通知
|
||||
if err := cs.viper.WriteConfig(); err != nil {
|
||||
// 直接写入JSON文件
|
||||
if err := cs.writeConfigToFile(defaultConfig); err != nil {
|
||||
cs.logger.Error("Config: Failed to write config during reset", "error", err)
|
||||
} else {
|
||||
cs.logger.Info("Config: All settings have been reset to defaults")
|
||||
// 手动触发配置变更检查,确保通知系统能感知到变更
|
||||
cs.notificationService.CheckConfigChanges()
|
||||
return
|
||||
}
|
||||
|
||||
// 重新读取配置文件到viper
|
||||
if err := cs.viper.ReadInConfig(); err != nil {
|
||||
cs.logger.Error("Config: Failed to reload config after reset", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
cs.logger.Info("Config: All settings have been reset to defaults")
|
||||
// 手动触发配置变更检查,确保通知系统能感知到变更
|
||||
cs.notificationService.CheckConfigChanges()
|
||||
}
|
||||
|
||||
// writeConfigToFile 直接写入配置到JSON文件
|
||||
func (cs *ConfigService) writeConfigToFile(config *models.AppConfig) error {
|
||||
// 获取配置文件路径
|
||||
currentDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
currentDir = "."
|
||||
}
|
||||
configPath := filepath.Join(currentDir, "config", "settings.json")
|
||||
|
||||
// 序列化为JSON
|
||||
configBytes, err := json.MarshalIndent(config, "", " ")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal config: %v", err)
|
||||
}
|
||||
|
||||
// 写入文件
|
||||
if err := os.WriteFile(configPath, configBytes, 0644); err != nil {
|
||||
return fmt.Errorf("failed to write config file: %v", err)
|
||||
}
|
||||
|
||||
// 重新读取到viper中
|
||||
if err := cs.viper.ReadInConfig(); err != nil {
|
||||
return fmt.Errorf("failed to reload config: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetHotkeyChangeCallback 设置热键配置变更回调
|
||||
|
631
internal/services/keybinding_service.go
Normal file
631
internal/services/keybinding_service.go
Normal file
@@ -0,0 +1,631 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"voidraft/internal/models"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/wailsapp/wails/v3/pkg/services/log"
|
||||
)
|
||||
|
||||
// KeyBindingService 快捷键管理服务
|
||||
type KeyBindingService struct {
|
||||
viper *viper.Viper // Viper 实例
|
||||
logger *log.LoggerService // 日志服务
|
||||
mu sync.RWMutex // 读写锁
|
||||
}
|
||||
|
||||
// KeyBindingError 快捷键错误
|
||||
type KeyBindingError struct {
|
||||
Operation string // 操作名称
|
||||
KeyID string // 快捷键ID
|
||||
Err error // 原始错误
|
||||
}
|
||||
|
||||
// Error 实现error接口
|
||||
func (e *KeyBindingError) Error() string {
|
||||
if e.KeyID != "" {
|
||||
return fmt.Sprintf("keybinding error during %s for key %s: %v", e.Operation, e.KeyID, e.Err)
|
||||
}
|
||||
return fmt.Sprintf("keybinding error during %s: %v", e.Operation, e.Err)
|
||||
}
|
||||
|
||||
// Unwrap 获取原始错误
|
||||
func (e *KeyBindingError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
// Is 实现错误匹配
|
||||
func (e *KeyBindingError) Is(target error) bool {
|
||||
var keyBindingError *KeyBindingError
|
||||
ok := errors.As(target, &keyBindingError)
|
||||
return ok
|
||||
}
|
||||
|
||||
// NewKeyBindingService 创建新的快捷键服务实例
|
||||
func NewKeyBindingService(logger *log.LoggerService) *KeyBindingService {
|
||||
// 设置日志服务
|
||||
if logger == nil {
|
||||
logger = log.New()
|
||||
}
|
||||
|
||||
// 获取当前工作目录
|
||||
currentDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
currentDir = "."
|
||||
}
|
||||
|
||||
// 固定配置路径和文件名
|
||||
configPath := filepath.Join(currentDir, "config")
|
||||
configName := "keybindings"
|
||||
|
||||
// 创建 Viper 实例
|
||||
v := viper.New()
|
||||
|
||||
// 配置 Viper
|
||||
v.SetConfigName(configName)
|
||||
v.SetConfigType("json")
|
||||
v.AddConfigPath(configPath)
|
||||
|
||||
// 设置环境变量前缀
|
||||
v.SetEnvPrefix("VOIDRAFT_KEYBINDING")
|
||||
v.AutomaticEnv()
|
||||
|
||||
// 设置默认值
|
||||
setKeyBindingDefaults(v)
|
||||
|
||||
// 构造快捷键服务实例
|
||||
service := &KeyBindingService{
|
||||
viper: v,
|
||||
logger: logger,
|
||||
}
|
||||
|
||||
// 初始化配置
|
||||
if err := service.initConfig(); err != nil {
|
||||
service.logger.Error("KeyBinding: Failed to initialize keybinding config", "error", err)
|
||||
}
|
||||
|
||||
// 启动配置文件监听
|
||||
service.startWatching()
|
||||
|
||||
return service
|
||||
}
|
||||
|
||||
// setKeyBindingDefaults 设置默认快捷键配置值
|
||||
func setKeyBindingDefaults(v *viper.Viper) {
|
||||
defaultConfig := models.NewDefaultKeyBindingConfig()
|
||||
|
||||
// 快捷键列表默认值
|
||||
v.SetDefault("keyBindings", defaultConfig.KeyBindings)
|
||||
|
||||
// 元数据默认值
|
||||
v.SetDefault("metadata.lastUpdated", defaultConfig.Metadata.LastUpdated)
|
||||
}
|
||||
|
||||
// initConfig 初始化配置
|
||||
func (kbs *KeyBindingService) initConfig() error {
|
||||
kbs.mu.Lock()
|
||||
defer kbs.mu.Unlock()
|
||||
|
||||
// 尝试读取配置文件
|
||||
if err := kbs.viper.ReadInConfig(); err != nil {
|
||||
var configFileNotFoundError viper.ConfigFileNotFoundError
|
||||
if errors.As(err, &configFileNotFoundError) {
|
||||
// 配置文件不存在,创建默认配置文件
|
||||
kbs.logger.Info("KeyBinding: Config file not found, creating default keybinding config")
|
||||
return kbs.createDefaultConfig()
|
||||
}
|
||||
// 配置文件存在但读取失败
|
||||
return &KeyBindingError{Operation: "read_keybinding_config", Err: err}
|
||||
}
|
||||
|
||||
kbs.logger.Info("KeyBinding: Successfully loaded keybinding config file", "file", kbs.viper.ConfigFileUsed())
|
||||
return nil
|
||||
}
|
||||
|
||||
// createDefaultConfig 创建默认配置文件
|
||||
func (kbs *KeyBindingService) createDefaultConfig() error {
|
||||
// 获取配置目录路径
|
||||
currentDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
currentDir = "."
|
||||
}
|
||||
configDir := filepath.Join(currentDir, "config")
|
||||
configPath := filepath.Join(configDir, "keybindings.json")
|
||||
|
||||
// 确保配置目录存在
|
||||
if err := os.MkdirAll(configDir, 0755); err != nil {
|
||||
return &KeyBindingError{Operation: "create_keybinding_config_dir", Err: err}
|
||||
}
|
||||
|
||||
// 获取默认配置
|
||||
defaultConfig := models.NewDefaultKeyBindingConfig()
|
||||
configBytes, err := json.MarshalIndent(defaultConfig, "", " ")
|
||||
if err != nil {
|
||||
return &KeyBindingError{Operation: "marshal_default_keybinding_config", Err: err}
|
||||
}
|
||||
|
||||
// 写入配置文件
|
||||
if err := os.WriteFile(configPath, configBytes, 0644); err != nil {
|
||||
return &KeyBindingError{Operation: "write_default_keybinding_config", Err: err}
|
||||
}
|
||||
|
||||
// 重新读取配置文件到viper
|
||||
if err := kbs.viper.ReadInConfig(); err != nil {
|
||||
return &KeyBindingError{Operation: "read_created_keybinding_config", Err: err}
|
||||
}
|
||||
|
||||
kbs.logger.Info("KeyBinding: Created default keybinding config file", "path", configPath)
|
||||
return nil
|
||||
}
|
||||
|
||||
// startWatching 启动配置文件监听
|
||||
func (kbs *KeyBindingService) startWatching() {
|
||||
// 设置配置变化回调
|
||||
kbs.viper.OnConfigChange(func(e fsnotify.Event) {
|
||||
kbs.logger.Info("KeyBinding: Config file changed", "file", e.Name, "operation", e.Op.String())
|
||||
})
|
||||
|
||||
// 启动配置文件监听
|
||||
kbs.viper.WatchConfig()
|
||||
kbs.logger.Info("KeyBinding: Started watching keybinding config file for changes")
|
||||
}
|
||||
|
||||
// GetKeyBindingConfig 获取完整快捷键配置
|
||||
func (kbs *KeyBindingService) GetKeyBindingConfig() (*models.KeyBindingConfig, error) {
|
||||
kbs.mu.RLock()
|
||||
defer kbs.mu.RUnlock()
|
||||
|
||||
var config models.KeyBindingConfig
|
||||
if err := kbs.viper.Unmarshal(&config); err != nil {
|
||||
return nil, &KeyBindingError{Operation: "unmarshal_keybinding_config", Err: err}
|
||||
}
|
||||
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
// GetAllKeyBindings 获取所有快捷键配置
|
||||
func (kbs *KeyBindingService) GetAllKeyBindings() ([]models.KeyBinding, error) {
|
||||
kbs.mu.RLock()
|
||||
defer kbs.mu.RUnlock()
|
||||
|
||||
config, err := kbs.GetKeyBindingConfig()
|
||||
if err != nil {
|
||||
return nil, &KeyBindingError{Operation: "get_all_keybindings", Err: err}
|
||||
}
|
||||
|
||||
return config.KeyBindings, nil
|
||||
}
|
||||
|
||||
// GetKeyBindingsByCategory 根据分类获取快捷键
|
||||
func (kbs *KeyBindingService) GetKeyBindingsByCategory(category models.KeyBindingCategory) ([]models.KeyBinding, error) {
|
||||
kbs.mu.RLock()
|
||||
defer kbs.mu.RUnlock()
|
||||
|
||||
allKeyBindings, err := kbs.GetAllKeyBindings()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result []models.KeyBinding
|
||||
for _, kb := range allKeyBindings {
|
||||
if kb.Category == category {
|
||||
result = append(result, kb)
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetKeyBindingsByScope 根据作用域获取快捷键
|
||||
func (kbs *KeyBindingService) GetKeyBindingsByScope(scope models.KeyBindingScope) ([]models.KeyBinding, error) {
|
||||
kbs.mu.RLock()
|
||||
defer kbs.mu.RUnlock()
|
||||
|
||||
allKeyBindings, err := kbs.GetAllKeyBindings()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result []models.KeyBinding
|
||||
for _, kb := range allKeyBindings {
|
||||
if kb.Scope == scope && kb.Enabled {
|
||||
result = append(result, kb)
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetKeyBindingByID 根据ID获取快捷键
|
||||
func (kbs *KeyBindingService) GetKeyBindingByID(id string) (*models.KeyBinding, error) {
|
||||
kbs.mu.RLock()
|
||||
defer kbs.mu.RUnlock()
|
||||
|
||||
allKeyBindings, err := kbs.GetAllKeyBindings()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, kb := range allKeyBindings {
|
||||
if kb.ID == id {
|
||||
return &kb, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, &KeyBindingError{
|
||||
Operation: "get_keybinding_by_id",
|
||||
KeyID: id,
|
||||
Err: errors.New("keybinding not found"),
|
||||
}
|
||||
}
|
||||
|
||||
// GetKeyBindingByAction 根据动作获取快捷键
|
||||
func (kbs *KeyBindingService) GetKeyBindingByAction(action models.KeyBindingAction) (*models.KeyBinding, error) {
|
||||
kbs.mu.RLock()
|
||||
defer kbs.mu.RUnlock()
|
||||
|
||||
allKeyBindings, err := kbs.GetAllKeyBindings()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, kb := range allKeyBindings {
|
||||
if kb.Action == action && kb.Enabled {
|
||||
return &kb, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, &KeyBindingError{
|
||||
Operation: "get_keybinding_by_action",
|
||||
Err: fmt.Errorf("keybinding for action %s not found", action),
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateKeyBinding 更新快捷键
|
||||
func (kbs *KeyBindingService) UpdateKeyBinding(id string, newKey string) error {
|
||||
kbs.mu.Lock()
|
||||
defer kbs.mu.Unlock()
|
||||
|
||||
// 验证新的快捷键格式
|
||||
if err := kbs.validateKeyFormat(newKey); err != nil {
|
||||
return &KeyBindingError{
|
||||
Operation: "update_keybinding",
|
||||
KeyID: id,
|
||||
Err: fmt.Errorf("invalid key format: %v", err),
|
||||
}
|
||||
}
|
||||
|
||||
// 检查快捷键冲突
|
||||
if err := kbs.checkKeyConflict(id, newKey); err != nil {
|
||||
return &KeyBindingError{
|
||||
Operation: "update_keybinding",
|
||||
KeyID: id,
|
||||
Err: fmt.Errorf("key conflict: %v", err),
|
||||
}
|
||||
}
|
||||
|
||||
// 获取当前配置
|
||||
config, err := kbs.GetKeyBindingConfig()
|
||||
if err != nil {
|
||||
return &KeyBindingError{Operation: "update_keybinding", KeyID: id, Err: err}
|
||||
}
|
||||
|
||||
// 查找并更新快捷键
|
||||
found := false
|
||||
for i, kb := range config.KeyBindings {
|
||||
if kb.ID == id {
|
||||
config.KeyBindings[i].Key = newKey
|
||||
config.KeyBindings[i].IsDefault = false // 标记为非默认
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
return &KeyBindingError{
|
||||
Operation: "update_keybinding",
|
||||
KeyID: id,
|
||||
Err: errors.New("keybinding not found"),
|
||||
}
|
||||
}
|
||||
|
||||
// 更新时间戳
|
||||
config.Metadata.LastUpdated = time.Now().Format(time.RFC3339)
|
||||
|
||||
// 保存配置
|
||||
if err := kbs.saveConfig(config); err != nil {
|
||||
return &KeyBindingError{Operation: "update_keybinding", KeyID: id, Err: err}
|
||||
}
|
||||
|
||||
kbs.logger.Info("KeyBinding: Updated keybinding", "id", id, "newKey", newKey)
|
||||
return nil
|
||||
}
|
||||
|
||||
// EnableKeyBinding 启用快捷键
|
||||
func (kbs *KeyBindingService) EnableKeyBinding(id string) error {
|
||||
return kbs.setKeyBindingEnabled(id, true)
|
||||
}
|
||||
|
||||
// DisableKeyBinding 禁用快捷键
|
||||
func (kbs *KeyBindingService) DisableKeyBinding(id string) error {
|
||||
return kbs.setKeyBindingEnabled(id, false)
|
||||
}
|
||||
|
||||
// setKeyBindingEnabled 设置快捷键启用状态
|
||||
func (kbs *KeyBindingService) setKeyBindingEnabled(id string, enabled bool) error {
|
||||
kbs.mu.Lock()
|
||||
defer kbs.mu.Unlock()
|
||||
|
||||
// 获取当前配置
|
||||
config, err := kbs.GetKeyBindingConfig()
|
||||
if err != nil {
|
||||
return &KeyBindingError{Operation: "set_keybinding_enabled", KeyID: id, Err: err}
|
||||
}
|
||||
|
||||
// 查找并更新快捷键
|
||||
found := false
|
||||
for i, kb := range config.KeyBindings {
|
||||
if kb.ID == id {
|
||||
config.KeyBindings[i].Enabled = enabled
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
return &KeyBindingError{
|
||||
Operation: "set_keybinding_enabled",
|
||||
KeyID: id,
|
||||
Err: errors.New("keybinding not found"),
|
||||
}
|
||||
}
|
||||
|
||||
// 更新时间戳
|
||||
config.Metadata.LastUpdated = time.Now().Format(time.RFC3339)
|
||||
|
||||
// 保存配置
|
||||
if err := kbs.saveConfig(config); err != nil {
|
||||
return &KeyBindingError{Operation: "set_keybinding_enabled", KeyID: id, Err: err}
|
||||
}
|
||||
|
||||
action := "enabled"
|
||||
if !enabled {
|
||||
action = "disabled"
|
||||
}
|
||||
kbs.logger.Info("KeyBinding: "+action+" keybinding", "id", id)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResetKeyBinding 重置快捷键到默认值
|
||||
func (kbs *KeyBindingService) ResetKeyBinding(id string) error {
|
||||
kbs.mu.Lock()
|
||||
defer kbs.mu.Unlock()
|
||||
|
||||
// 获取默认配置
|
||||
defaultKeyBindings := models.NewDefaultKeyBindings()
|
||||
var defaultKeyBinding *models.KeyBinding
|
||||
for _, kb := range defaultKeyBindings {
|
||||
if kb.ID == id {
|
||||
defaultKeyBinding = &kb
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if defaultKeyBinding == nil {
|
||||
return &KeyBindingError{
|
||||
Operation: "reset_keybinding",
|
||||
KeyID: id,
|
||||
Err: errors.New("default keybinding not found"),
|
||||
}
|
||||
}
|
||||
|
||||
// 获取当前配置
|
||||
config, err := kbs.GetKeyBindingConfig()
|
||||
if err != nil {
|
||||
return &KeyBindingError{Operation: "reset_keybinding", KeyID: id, Err: err}
|
||||
}
|
||||
|
||||
// 查找并重置快捷键
|
||||
found := false
|
||||
for i, kb := range config.KeyBindings {
|
||||
if kb.ID == id {
|
||||
config.KeyBindings[i].Key = defaultKeyBinding.Key
|
||||
config.KeyBindings[i].Enabled = defaultKeyBinding.Enabled
|
||||
config.KeyBindings[i].IsDefault = true
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
return &KeyBindingError{
|
||||
Operation: "reset_keybinding",
|
||||
KeyID: id,
|
||||
Err: errors.New("keybinding not found"),
|
||||
}
|
||||
}
|
||||
|
||||
// 更新时间戳
|
||||
config.Metadata.LastUpdated = time.Now().Format(time.RFC3339)
|
||||
|
||||
// 保存配置
|
||||
if err := kbs.saveConfig(config); err != nil {
|
||||
return &KeyBindingError{Operation: "reset_keybinding", KeyID: id, Err: err}
|
||||
}
|
||||
|
||||
kbs.logger.Info("KeyBinding: Reset keybinding to default", "id", id, "key", defaultKeyBinding.Key)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResetAllKeyBindings 重置所有快捷键到默认值
|
||||
func (kbs *KeyBindingService) ResetAllKeyBindings() error {
|
||||
kbs.mu.Lock()
|
||||
defer kbs.mu.Unlock()
|
||||
|
||||
// 获取默认配置
|
||||
defaultConfig := models.NewDefaultKeyBindingConfig()
|
||||
|
||||
// 保存配置
|
||||
if err := kbs.saveConfig(defaultConfig); err != nil {
|
||||
return &KeyBindingError{Operation: "reset_all_keybindings", Err: err}
|
||||
}
|
||||
|
||||
kbs.logger.Info("KeyBinding: Reset all keybindings to default")
|
||||
return nil
|
||||
}
|
||||
|
||||
// saveConfig 保存配置到文件
|
||||
func (kbs *KeyBindingService) saveConfig(config *models.KeyBindingConfig) error {
|
||||
// 设置快捷键列表到viper
|
||||
kbs.viper.Set("keyBindings", config.KeyBindings)
|
||||
kbs.viper.Set("metadata.lastUpdated", config.Metadata.LastUpdated)
|
||||
|
||||
// 写入配置文件
|
||||
if err := kbs.viper.WriteConfig(); err != nil {
|
||||
return fmt.Errorf("failed to write keybinding config: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateKeyFormat 验证快捷键格式
|
||||
func (kbs *KeyBindingService) validateKeyFormat(key string) error {
|
||||
if key == "" {
|
||||
return errors.New("key cannot be empty")
|
||||
}
|
||||
|
||||
// 基本格式验证
|
||||
// 支持的修饰符: Mod, Ctrl, Shift, Alt, Win
|
||||
// 支持的组合: Mod-f, Ctrl-Shift-p, Alt-ArrowUp 等
|
||||
validModifiers := []string{"Mod", "Ctrl", "Shift", "Alt", "Win"}
|
||||
parts := strings.Split(key, "-")
|
||||
|
||||
if len(parts) == 0 {
|
||||
return errors.New("invalid key format")
|
||||
}
|
||||
|
||||
// 检查修饰符
|
||||
for i := 0; i < len(parts)-1; i++ {
|
||||
modifier := parts[i]
|
||||
valid := false
|
||||
for _, validMod := range validModifiers {
|
||||
if modifier == validMod {
|
||||
valid = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !valid {
|
||||
return fmt.Errorf("invalid modifier: %s", modifier)
|
||||
}
|
||||
}
|
||||
|
||||
// 最后一部分应该是主键
|
||||
mainKey := parts[len(parts)-1]
|
||||
if mainKey == "" {
|
||||
return errors.New("main key cannot be empty")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkKeyConflict 检查快捷键冲突
|
||||
func (kbs *KeyBindingService) checkKeyConflict(excludeID, key string) error {
|
||||
allKeyBindings, err := kbs.GetAllKeyBindings()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, kb := range allKeyBindings {
|
||||
if kb.ID != excludeID && kb.Key == key && kb.Enabled {
|
||||
return fmt.Errorf("key %s is already used by %s", key, kb.ID)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetKeyBindingCategories 获取所有快捷键分类
|
||||
func (kbs *KeyBindingService) GetKeyBindingCategories() []models.KeyBindingCategory {
|
||||
return []models.KeyBindingCategory{
|
||||
models.CategorySearch,
|
||||
models.CategoryEdit,
|
||||
models.CategoryCodeBlock,
|
||||
models.CategoryNavigation,
|
||||
models.CategoryView,
|
||||
models.CategoryFile,
|
||||
models.CategoryApp,
|
||||
}
|
||||
}
|
||||
|
||||
// GetKeyBindingScopes 获取所有快捷键作用域
|
||||
func (kbs *KeyBindingService) GetKeyBindingScopes() []models.KeyBindingScope {
|
||||
return []models.KeyBindingScope{
|
||||
models.ScopeGlobal,
|
||||
models.ScopeEditor,
|
||||
models.ScopeSearch,
|
||||
}
|
||||
}
|
||||
|
||||
// ExportKeyBindings 导出快捷键配置
|
||||
func (kbs *KeyBindingService) ExportKeyBindings() ([]models.KeyBinding, error) {
|
||||
kbs.mu.RLock()
|
||||
defer kbs.mu.RUnlock()
|
||||
|
||||
return kbs.GetAllKeyBindings()
|
||||
}
|
||||
|
||||
// ImportKeyBindings 导入快捷键配置
|
||||
func (kbs *KeyBindingService) ImportKeyBindings(keyBindings []models.KeyBinding) error {
|
||||
kbs.mu.Lock()
|
||||
defer kbs.mu.Unlock()
|
||||
|
||||
// 验证导入的快捷键
|
||||
for _, kb := range keyBindings {
|
||||
if err := kbs.validateKeyFormat(kb.Key); err != nil {
|
||||
return &KeyBindingError{
|
||||
Operation: "import_keybindings",
|
||||
KeyID: kb.ID,
|
||||
Err: fmt.Errorf("invalid key format for %s: %v", kb.ID, err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查重复的快捷键
|
||||
keyMap := make(map[string]string)
|
||||
for _, kb := range keyBindings {
|
||||
if kb.Enabled {
|
||||
if existingID, exists := keyMap[kb.Key]; exists {
|
||||
return &KeyBindingError{
|
||||
Operation: "import_keybindings",
|
||||
Err: fmt.Errorf("duplicate key %s found in %s and %s", kb.Key, existingID, kb.ID),
|
||||
}
|
||||
}
|
||||
keyMap[kb.Key] = kb.ID
|
||||
}
|
||||
}
|
||||
|
||||
// 创建新的配置
|
||||
config := &models.KeyBindingConfig{
|
||||
KeyBindings: keyBindings,
|
||||
Metadata: models.KeyBindingMetadata{
|
||||
LastUpdated: time.Now().Format(time.RFC3339),
|
||||
},
|
||||
}
|
||||
|
||||
// 保存配置
|
||||
if err := kbs.saveConfig(config); err != nil {
|
||||
return &KeyBindingError{Operation: "import_keybindings", Err: err}
|
||||
}
|
||||
|
||||
kbs.logger.Info("KeyBinding: Imported keybindings", "count", len(keyBindings))
|
||||
return nil
|
||||
}
|
@@ -9,14 +9,15 @@ import (
|
||||
|
||||
// ServiceManager 服务管理器,负责协调各个服务
|
||||
type ServiceManager struct {
|
||||
configService *ConfigService
|
||||
documentService *DocumentService
|
||||
migrationService *MigrationService
|
||||
systemService *SystemService
|
||||
hotkeyService *HotkeyService
|
||||
dialogService *DialogService
|
||||
trayService *TrayService
|
||||
logger *log.LoggerService
|
||||
configService *ConfigService
|
||||
documentService *DocumentService
|
||||
migrationService *MigrationService
|
||||
systemService *SystemService
|
||||
hotkeyService *HotkeyService
|
||||
dialogService *DialogService
|
||||
trayService *TrayService
|
||||
keyBindingService *KeyBindingService
|
||||
logger *log.LoggerService
|
||||
}
|
||||
|
||||
// NewServiceManager 创建新的服务管理器实例
|
||||
@@ -45,6 +46,9 @@ func NewServiceManager() *ServiceManager {
|
||||
// 初始化托盘服务
|
||||
trayService := NewTrayService(logger, configService)
|
||||
|
||||
// 初始化快捷键服务
|
||||
keyBindingService := NewKeyBindingService(logger)
|
||||
|
||||
// 使用新的配置通知系统设置热键配置变更监听
|
||||
err := configService.SetHotkeyChangeCallback(func(enable bool, hotkey *models.HotkeyCombo) error {
|
||||
return hotkeyService.UpdateHotkey(enable, hotkey)
|
||||
@@ -71,14 +75,15 @@ func NewServiceManager() *ServiceManager {
|
||||
}
|
||||
|
||||
return &ServiceManager{
|
||||
configService: configService,
|
||||
documentService: documentService,
|
||||
migrationService: migrationService,
|
||||
systemService: systemService,
|
||||
hotkeyService: hotkeyService,
|
||||
dialogService: dialogService,
|
||||
trayService: trayService,
|
||||
logger: logger,
|
||||
configService: configService,
|
||||
documentService: documentService,
|
||||
migrationService: migrationService,
|
||||
systemService: systemService,
|
||||
hotkeyService: hotkeyService,
|
||||
dialogService: dialogService,
|
||||
trayService: trayService,
|
||||
keyBindingService: keyBindingService,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,6 +97,7 @@ func (sm *ServiceManager) GetServices() []application.Service {
|
||||
application.NewService(sm.hotkeyService),
|
||||
application.NewService(sm.dialogService),
|
||||
application.NewService(sm.trayService),
|
||||
application.NewService(sm.keyBindingService),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,3 +125,8 @@ func (sm *ServiceManager) GetConfigService() *ConfigService {
|
||||
func (sm *ServiceManager) GetTrayService() *TrayService {
|
||||
return sm.trayService
|
||||
}
|
||||
|
||||
// GetKeyBindingService 获取快捷键服务实例
|
||||
func (sm *ServiceManager) GetKeyBindingService() *KeyBindingService {
|
||||
return sm.keyBindingService
|
||||
}
|
||||
|
Reference in New Issue
Block a user