Unified management of keymap

This commit is contained in:
2025-06-21 00:28:06 +08:00
parent cb3d369aef
commit 6acab678d0
21 changed files with 1536 additions and 990 deletions

View File

@@ -456,18 +456,13 @@ export class KeyBinding {
/**
* 快捷键动作
*/
"action": KeyBindingAction;
"command": KeyBindingCommand;
/**
* 快捷键分类
*/
"category": KeyBindingCategory;
/**
* 快捷键作用域
*/
"scope": KeyBindingScope;
/**
* 快捷键组合(如 "Mod-f", "Ctrl-Shift-p"
*/
@@ -485,15 +480,12 @@ export class KeyBinding {
/** Creates a new KeyBinding instance. */
constructor($$source: Partial<KeyBinding> = {}) {
if (!("action" in $$source)) {
this["action"] = ("" as KeyBindingAction);
if (!("command" in $$source)) {
this["command"] = ("" as KeyBindingCommand);
}
if (!("category" in $$source)) {
this["category"] = ("" as KeyBindingCategory);
}
if (!("scope" in $$source)) {
this["scope"] = ("" as KeyBindingScope);
}
if (!("key" in $$source)) {
this["key"] = "";
}
@@ -516,212 +508,6 @@ export class KeyBinding {
}
}
/**
* KeyBindingAction 快捷键动作类型
*/
export enum KeyBindingAction {
/**
* The Go zero value for the underlying type of the enum.
*/
$zero = "",
/**
* 搜索相关
* 显示搜索
*/
ActionShowSearch = "showSearch",
/**
* 隐藏搜索
*/
ActionHideSearch = "hideSearch",
/**
* 查找下一个
*/
ActionFindNext = "findNext",
/**
* 查找上一个
*/
ActionFindPrevious = "findPrevious",
/**
* 显示替换
*/
ActionShowReplace = "showReplace",
/**
* 替换下一个
*/
ActionReplaceNext = "replaceNext",
/**
* 替换全部
*/
ActionReplaceAll = "replaceAll",
/**
* 切换大小写匹配
*/
ActionToggleCase = "toggleCase",
/**
* 切换全词匹配
*/
ActionToggleWholeWord = "toggleWholeWord",
/**
* 切换正则表达式
*/
ActionToggleRegex = "toggleRegex",
/**
* 编辑相关
* 全选
*/
ActionSelectAll = "selectAll",
/**
* 复制
*/
ActionCopy = "copy",
/**
* 剪切
*/
ActionCut = "cut",
/**
* 粘贴
*/
ActionPaste = "paste",
/**
* 撤销
*/
ActionUndo = "undo",
/**
* 重做
*/
ActionRedo = "redo",
/**
* 复制行
*/
ActionDuplicateLine = "duplicateLine",
/**
* 删除行
*/
ActionDeleteLine = "deleteLine",
/**
* 上移行
*/
ActionMoveLineUp = "moveLineUp",
/**
* 下移行
*/
ActionMoveLineDown = "moveLineDown",
/**
* 切换注释
*/
ActionToggleComment = "toggleComment",
/**
* 缩进
*/
ActionIndent = "indent",
/**
* 取消缩进
*/
ActionOutdent = "outdent",
/**
* 代码块相关
* 新建代码块
*/
ActionNewCodeBlock = "newCodeBlock",
/**
* 删除代码块
*/
ActionDeleteCodeBlock = "deleteCodeBlock",
/**
* 选择代码块
*/
ActionSelectCodeBlock = "selectCodeBlock",
/**
* 格式化代码
*/
ActionFormatCode = "formatCode",
/**
* 更改语言
*/
ActionChangeLanguage = "changeLanguage",
/**
* 导航相关
* 跳转到行
*/
ActionGoToLine = "goToLine",
/**
* 折叠所有
*/
ActionFoldAll = "foldAll",
/**
* 展开所有
*/
ActionUnfoldAll = "unfoldAll",
/**
* 切换折叠
*/
ActionToggleFold = "toggleFold",
/**
* 视图相关
* 放大
*/
ActionZoomIn = "zoomIn",
/**
* 缩小
*/
ActionZoomOut = "zoomOut",
/**
* 重置缩放
*/
ActionResetZoom = "resetZoom",
/**
* 切换小地图
*/
ActionToggleMinimap = "toggleMinimap",
/**
* 切换行号
*/
ActionToggleLineNumbers = "toggleLineNumbers",
/**
* 文件相关
* 保存
*/
ActionSave = "save",
};
/**
* KeyBindingCategory 快捷键分类
*/
@@ -744,27 +530,302 @@ export enum KeyBindingCategory {
/**
* 代码块相关
*/
CategoryCodeBlock = "codeblock",
CategoryCodeBlock = "block",
/**
* 导航相关
* 历史记录相关
*/
CategoryNavigation = "navigation",
CategoryHistory = "history",
/**
* 视图相关
* 代码折叠相关
*/
CategoryView = "view",
CategoryFold = "fold",
};
/**
* KeyBindingCommand 快捷键命令
*/
export enum KeyBindingCommand {
/**
* The Go zero value for the underlying type of the enum.
*/
$zero = "",
/**
* 文件相关
* 搜索相关
* 显示搜索
*/
CategoryFile = "file",
ShowSearchCommand = "showSearch",
/**
* 应用相关
* 隐藏搜索
*/
CategoryApp = "app",
HideSearchCommand = "hideSearch",
/**
* 搜索切换大小写
*/
SearchToggleCaseCommand = "searchToggleCase",
/**
* 搜索切换整词
*/
SearchToggleWordCommand = "searchToggleWord",
/**
* 搜索切换正则
*/
SearchToggleRegexCommand = "searchToggleRegex",
/**
* 显示替换
*/
SearchShowReplaceCommand = "searchShowReplace",
/**
* 替换全部
*/
SearchReplaceAllCommand = "searchReplaceAll",
/**
* 代码块相关
* 块内选择全部
*/
BlockSelectAllCommand = "blockSelectAll",
/**
* 在当前块后添加新块
*/
BlockAddAfterCurrentCommand = "blockAddAfterCurrent",
/**
* 在最后添加新块
*/
BlockAddAfterLastCommand = "blockAddAfterLast",
/**
* 在当前块前添加新块
*/
BlockAddBeforeCurrentCommand = "blockAddBeforeCurrent",
/**
* 跳转到上一个块
*/
BlockGotoPreviousCommand = "blockGotoPrevious",
/**
* 跳转到下一个块
*/
BlockGotoNextCommand = "blockGotoNext",
/**
* 选择上一个块
*/
BlockSelectPreviousCommand = "blockSelectPrevious",
/**
* 选择下一个块
*/
BlockSelectNextCommand = "blockSelectNext",
/**
* 删除当前块
*/
BlockDeleteCommand = "blockDelete",
/**
* 向上移动当前块
*/
BlockMoveUpCommand = "blockMoveUp",
/**
* 向下移动当前块
*/
BlockMoveDownCommand = "blockMoveDown",
/**
* 删除行
*/
BlockDeleteLineCommand = "blockDeleteLine",
/**
* 向上移动行
*/
BlockMoveLineUpCommand = "blockMoveLineUp",
/**
* 向下移动行
*/
BlockMoveLineDownCommand = "blockMoveLineDown",
/**
* 字符转置
*/
BlockTransposeCharsCommand = "blockTransposeChars",
/**
* 格式化代码块
*/
BlockFormatCommand = "blockFormat",
/**
* 复制
*/
BlockCopyCommand = "blockCopy",
/**
* 剪切
*/
BlockCutCommand = "blockCut",
/**
* 粘贴
*/
BlockPasteCommand = "blockPaste",
/**
* 历史记录相关
* 撤销
*/
HistoryUndoCommand = "historyUndo",
/**
* 重做
*/
HistoryRedoCommand = "historyRedo",
/**
* 撤销选择
*/
HistoryUndoSelectionCommand = "historyUndoSelection",
/**
* 重做选择
*/
HistoryRedoSelectionCommand = "historyRedoSelection",
/**
* 代码折叠相关
* 折叠代码
*/
FoldCodeCommand = "foldCode",
/**
* 展开代码
*/
UnfoldCodeCommand = "unfoldCode",
/**
* 折叠全部
*/
FoldAllCommand = "foldAll",
/**
* 展开全部
*/
UnfoldAllCommand = "unfoldAll",
/**
* 编辑相关
* 光标按语法左移
*/
CursorSyntaxLeftCommand = "cursorSyntaxLeft",
/**
* 光标按语法右移
*/
CursorSyntaxRightCommand = "cursorSyntaxRight",
/**
* 按语法选择左侧
*/
SelectSyntaxLeftCommand = "selectSyntaxLeft",
/**
* 按语法选择右侧
*/
SelectSyntaxRightCommand = "selectSyntaxRight",
/**
* 向上复制行
*/
CopyLineUpCommand = "copyLineUp",
/**
* 向下复制行
*/
CopyLineDownCommand = "copyLineDown",
/**
* 插入空行
*/
InsertBlankLineCommand = "insertBlankLine",
/**
* 选择行
*/
SelectLineCommand = "selectLine",
/**
* 选择父级语法
*/
SelectParentSyntaxCommand = "selectParentSyntax",
/**
* 减少缩进
*/
IndentLessCommand = "indentLess",
/**
* 增加缩进
*/
IndentMoreCommand = "indentMore",
/**
* 缩进选择
*/
IndentSelectionCommand = "indentSelection",
/**
* 光标到匹配括号
*/
CursorMatchingBracketCommand = "cursorMatchingBracket",
/**
* 切换注释
*/
ToggleCommentCommand = "toggleComment",
/**
* 切换块注释
*/
ToggleBlockCommentCommand = "toggleBlockComment",
/**
* 插入新行并缩进
*/
InsertNewlineAndIndentCommand = "insertNewlineAndIndent",
/**
* 向后删除字符
*/
DeleteCharBackwardCommand = "deleteCharBackward",
/**
* 向前删除字符
*/
DeleteCharForwardCommand = "deleteCharForward",
/**
* 向后删除组
*/
DeleteGroupBackwardCommand = "deleteGroupBackward",
/**
* 向前删除组
*/
DeleteGroupForwardCommand = "deleteGroupForward",
};
/**
@@ -837,31 +898,6 @@ export class KeyBindingMetadata {
}
}
/**
* KeyBindingScope 快捷键作用域
*/
export enum KeyBindingScope {
/**
* The Go zero value for the underlying type of the enum.
*/
$zero = "",
/**
* 全局作用域
*/
ScopeGlobal = "global",
/**
* 编辑器作用域
*/
ScopeEditor = "editor",
/**
* 搜索面板作用域
*/
ScopeSearch = "search",
};
/**
* LanguageType 语言类型定义
*/

View File

@@ -17,16 +17,16 @@ import * as models$0 from "../models/models.js";
/**
* DisableKeyBinding 禁用快捷键
*/
export function DisableKeyBinding(action: models$0.KeyBindingAction): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(1594003006, action) as any;
export function DisableKeyBinding(command: models$0.KeyBindingCommand): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(1594003006, command) as any;
return $resultPromise;
}
/**
* EnableKeyBinding 启用快捷键
*/
export function EnableKeyBinding(action: models$0.KeyBindingAction): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(1462644129, action) as any;
export function EnableKeyBinding(command: models$0.KeyBindingCommand): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(1462644129, command) as any;
return $resultPromise;
}
@@ -55,10 +55,10 @@ export function GetAllKeyBindings(): Promise<models$0.KeyBinding[]> & { cancel()
}
/**
* GetKeyBindingByAction 根据动作获取快捷键
* GetKeyBindingByCommand 根据命令获取快捷键
*/
export function GetKeyBindingByAction(action: models$0.KeyBindingAction): Promise<models$0.KeyBinding | null> & { cancel(): void } {
let $resultPromise = $Call.ByID(752637777, action) as any;
export function GetKeyBindingByCommand(command: models$0.KeyBindingCommand): Promise<models$0.KeyBinding | null> & { cancel(): void } {
let $resultPromise = $Call.ByID(3066982544, command) as any;
let $typingPromise = $resultPromise.then(($result: any) => {
return $$createType2($result);
}) as any;
@@ -90,18 +90,6 @@ export function GetKeyBindingConfig(): Promise<models$0.KeyBindingConfig | null>
return $typingPromise;
}
/**
* GetKeyBindingScopes 获取所有快捷键作用域
*/
export function GetKeyBindingScopes(): Promise<models$0.KeyBindingScope[]> & { cancel(): void } {
let $resultPromise = $Call.ByID(2984736455) as any;
let $typingPromise = $resultPromise.then(($result: any) => {
return $$createType6($result);
}) as any;
$typingPromise.cancel = $resultPromise.cancel.bind($resultPromise);
return $typingPromise;
}
/**
* GetKeyBindingsByCategory 根据分类获取快捷键
*/
@@ -114,18 +102,6 @@ export function GetKeyBindingsByCategory(category: models$0.KeyBindingCategory):
return $typingPromise;
}
/**
* GetKeyBindingsByScope 根据作用域获取快捷键
*/
export function GetKeyBindingsByScope(scope: models$0.KeyBindingScope): Promise<models$0.KeyBinding[]> & { cancel(): void } {
let $resultPromise = $Call.ByID(1179712594, scope) as any;
let $typingPromise = $resultPromise.then(($result: any) => {
return $$createType1($result);
}) as any;
$typingPromise.cancel = $resultPromise.cancel.bind($resultPromise);
return $typingPromise;
}
/**
* ImportKeyBindings 导入快捷键配置
*/
@@ -145,16 +121,16 @@ export function ResetAllKeyBindings(): Promise<void> & { cancel(): void } {
/**
* ResetKeyBinding 重置快捷键到默认值
*/
export function ResetKeyBinding(action: models$0.KeyBindingAction): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(3466323405, action) as any;
export function ResetKeyBinding(command: models$0.KeyBindingCommand): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(3466323405, command) as any;
return $resultPromise;
}
/**
* UpdateKeyBinding 更新快捷键
*/
export function UpdateKeyBinding(action: models$0.KeyBindingAction, newKey: string): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(1469368983, action, newKey) as any;
export function UpdateKeyBinding(command: models$0.KeyBindingCommand, newKey: string): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(1469368983, command, newKey) as any;
return $resultPromise;
}
@@ -165,4 +141,3 @@ const $$createType2 = $Create.Nullable($$createType0);
const $$createType3 = $Create.Array($Create.Any);
const $$createType4 = models$0.KeyBindingConfig.createFrom;
const $$createType5 = $Create.Nullable($$createType4);
const $$createType6 = $Create.Array($Create.Any);

View File

@@ -2,17 +2,20 @@
import { onMounted } from 'vue';
import { useConfigStore } from '@/stores/configStore';
import { useSystemStore } from '@/stores/systemStore';
import { useKeybindingStore } from '@/stores/keybindingStore';
import WindowTitleBar from '@/components/titlebar/WindowTitleBar.vue';
const configStore = useConfigStore();
const systemStore = useSystemStore();
const keybindingStore = useKeybindingStore();
// 应用启动时加载配置和初始化系统信息
onMounted(async () => {
// 并行初始化配置系统信息
// 并行初始化配置系统信息和快捷键配置
await Promise.all([
configStore.initConfig(),
systemStore.initializeSystemInfo(),
keybindingStore.loadKeyBindings(),
]);
await configStore.initializeLanguage();

View File

@@ -73,6 +73,73 @@ export default {
completed: 'Migration Completed',
failed: 'Migration Failed'
},
keybindings: {
headers: {
shortcut: 'Shortcut',
category: 'Category',
description: 'Description'
},
commands: {
showSearch: 'Show search panel',
hideSearch: 'Hide search panel',
searchToggleCase: 'Toggle case-sensitive matching',
searchToggleWord: 'Toggle whole word matching',
searchToggleRegex: 'Toggle regular expression matching',
searchShowReplace: 'Show replace functionality',
searchFindNext: 'Find next match',
searchFindPrev: 'Find previous match',
searchReplaceAll: 'Replace all matches',
searchSelectAll: 'Select all content',
blockSelectAll: 'Select all in block',
blockAddAfterCurrent: 'Add new block after current',
blockAddAfterLast: 'Add new block at end',
blockAddBeforeCurrent: 'Add new block before current',
blockGotoPrevious: 'Go to previous block',
blockGotoNext: 'Go to next block',
blockSelectPrevious: 'Select previous block',
blockSelectNext: 'Select next block',
blockDelete: 'Delete current block',
blockMoveUp: 'Move current block up',
blockMoveDown: 'Move current block down',
blockDeleteLine: 'Delete line',
blockMoveLineUp: 'Move line up',
blockMoveLineDown: 'Move line down',
blockTransposeChars: 'Transpose characters',
blockFormat: 'Format code block',
blockCopy: 'Copy',
blockCut: 'Cut',
blockPaste: 'Paste',
historyUndo: 'Undo',
historyRedo: 'Redo',
historyUndoSelection: 'Undo selection',
historyRedoSelection: 'Redo selection',
foldCode: 'Fold code',
unfoldCode: 'Unfold code',
foldAll: 'Fold all',
unfoldAll: 'Unfold all',
cursorSyntaxLeft: 'Cursor syntax left',
cursorSyntaxRight: 'Cursor syntax right',
selectSyntaxLeft: 'Select syntax left',
selectSyntaxRight: 'Select syntax right',
copyLineUp: 'Copy line up',
copyLineDown: 'Copy line down',
simplifySelection: 'Simplify selection',
insertBlankLine: 'Insert blank line',
selectLine: 'Select line',
selectParentSyntax: 'Select parent syntax',
indentLess: 'Indent less',
indentMore: 'Indent more',
indentSelection: 'Indent selection',
cursorMatchingBracket: 'Cursor matching bracket',
toggleComment: 'Toggle comment',
toggleBlockComment: 'Toggle block comment',
insertNewlineAndIndent: 'Insert newline and indent',
deleteCharBackward: 'Delete character backward',
deleteCharForward: 'Delete character forward',
deleteGroupBackward: 'Delete group backward',
deleteGroupForward: 'Delete group forward',
}
},
settings: {
title: 'Settings',
backToEditor: 'Back to Editor',

View File

@@ -73,6 +73,73 @@ export default {
completed: '迁移已完成',
failed: '迁移失败'
},
keybindings: {
headers: {
shortcut: '快捷键',
category: '分类',
description: '描述'
},
commands: {
showSearch: '显示搜索面板',
hideSearch: '隐藏搜索面板',
searchToggleCase: '切换大小写敏感匹配',
searchToggleWord: '切换整词匹配',
searchToggleRegex: '切换正则表达式匹配',
searchShowReplace: '显示替换功能',
searchFindNext: '查找下一个匹配项',
searchFindPrev: '查找上一个匹配项',
searchReplaceAll: '替换全部匹配项',
searchSelectAll: '选择全部内容',
blockSelectAll: '块内选择全部',
blockAddAfterCurrent: '在当前块后添加新块',
blockAddAfterLast: '在最后添加新块',
blockAddBeforeCurrent: '在当前块前添加新块',
blockGotoPrevious: '跳转到上一个块',
blockGotoNext: '跳转到下一个块',
blockSelectPrevious: '选择上一个块',
blockSelectNext: '选择下一个块',
blockDelete: '删除当前块',
blockMoveUp: '向上移动当前块',
blockMoveDown: '向下移动当前块',
blockDeleteLine: '删除行',
blockMoveLineUp: '向上移动行',
blockMoveLineDown: '向下移动行',
blockTransposeChars: '字符转置',
blockFormat: '格式化代码块',
blockCopy: '复制',
blockCut: '剪切',
blockPaste: '粘贴',
historyUndo: '撤销',
historyRedo: '重做',
historyUndoSelection: '撤销选择',
historyRedoSelection: '重做选择',
foldCode: '折叠代码',
unfoldCode: '展开代码',
foldAll: '折叠全部',
unfoldAll: '展开全部',
cursorSyntaxLeft: '光标按语法左移',
cursorSyntaxRight: '光标按语法右移',
selectSyntaxLeft: '按语法选择左侧',
selectSyntaxRight: '按语法选择右侧',
copyLineUp: '向上复制行',
copyLineDown: '向下复制行',
simplifySelection: '简化选择',
insertBlankLine: '插入空行',
selectLine: '选择行',
selectParentSyntax: '选择父级语法',
indentLess: '减少缩进',
indentMore: '增加缩进',
indentSelection: '缩进选择',
cursorMatchingBracket: '光标到匹配括号',
toggleComment: '切换注释',
toggleBlockComment: '切换块注释',
insertNewlineAndIndent: '插入新行并缩进',
deleteCharBackward: '向后删除字符',
deleteCharForward: '向前删除字符',
deleteGroupBackward: '向后删除组',
deleteGroupForward: '向前删除组',
}
},
settings: {
title: '设置',
backToEditor: '返回编辑器',

View File

@@ -15,6 +15,7 @@ import {
createSaveShortcutPlugin,
createFontExtensionFromBackend,
updateFontConfig,
createDynamicKeymapExtension,
} from '@/views/editor/extensions';
import { createThemeExtension, updateEditorTheme } from '@/views/editor/extensions/themeExtension';
import { useThemeStore } from './themeStore';
@@ -169,8 +170,12 @@ export const useEditorStore = defineStore('editor', () => {
}
});
// 创建动态快捷键扩展
const keymapExtension = await createDynamicKeymapExtension();
// 组合所有扩展
const extensions: Extension[] = [
keymapExtension,
themeExtension,
...basicExtensions,
...tabExtensions,

View File

@@ -0,0 +1,52 @@
import {defineStore} from 'pinia'
import {computed, ref} from 'vue'
import {KeyBinding, KeyBindingCommand} from '@/../bindings/voidraft/internal/models/models'
import {GetAllKeyBindings} from '@/../bindings/voidraft/internal/services/keybindingservice'
export const useKeybindingStore = defineStore('keybinding', () => {
// 快捷键配置数据
const keyBindings = ref<KeyBinding[]>([])
// 获取启用的快捷键
const enabledKeyBindings = computed(() =>
keyBindings.value.filter(kb => kb.enabled)
)
// 按命令获取快捷键
const getKeyBindingByCommand = computed(() =>
(command: KeyBindingCommand) =>
keyBindings.value.find(kb => kb.command === command)
)
/**
* 从后端加载快捷键配置
*/
const loadKeyBindings = async (): Promise<void> => {
try {
keyBindings.value = await GetAllKeyBindings()
} catch (err) {
console.error(err)
}
}
/**
* 检查是否存在指定命令的快捷键
*/
const hasCommand = (command: KeyBindingCommand): boolean => {
return keyBindings.value.some(kb => kb.command === command && kb.enabled)
}
return {
// 状态
keyBindings,
enabledKeyBindings,
// 计算属性
getKeyBindingByCommand,
// 方法
loadKeyBindings,
hasCommand
}
})

View File

@@ -15,15 +15,13 @@ import {
bracketMatching,
defaultHighlightStyle,
foldGutter,
foldKeymap,
indentOnInput,
syntaxHighlighting,
} from '@codemirror/language';
import {defaultKeymap, history, historyKeymap,} from '@codemirror/commands';
import {history} from '@codemirror/commands';
import {highlightSelectionMatches} from '@codemirror/search';
import {autocompletion, closeBrackets, closeBracketsKeymap, completionKeymap} from '@codemirror/autocomplete';
import {lintKeymap} from '@codemirror/lint';
import {customSearchKeymap, searchVisibilityField, vscodeSearch} from './vscodeSearch';
import {autocompletion, closeBrackets, closeBracketsKeymap} from '@codemirror/autocomplete';
import {searchVisibilityField, vscodeSearch} from './vscodeSearch';
import {hyperLink} from './hyperlink';
import {color} from './colorSelector';
@@ -91,13 +89,7 @@ export const createBasicSetup = (): Extension[] => {
// 键盘映射
keymap.of([
...customSearchKeymap,
...closeBracketsKeymap,
...defaultKeymap,
...historyKeymap,
...foldKeymap,
...completionKeymap,
...lintKeymap
]),
];
};

View File

@@ -209,26 +209,3 @@ export function getCopyPasteExtensions() {
codeBlockCopyCut,
];
}
/**
* 获取复制粘贴键盘映射
*/
export function getCopyPasteKeymap() {
return [
{
key: 'Mod-c',
run: copyCommand,
preventDefault: true
},
{
key: 'Mod-x',
run: cutCommand,
preventDefault: true
},
{
key: 'Mod-v',
run: pasteCommand,
preventDefault: true
}
];
}

View File

@@ -13,17 +13,14 @@
*/
import {Extension} from '@codemirror/state';
import {keymap, lineNumbers} from '@codemirror/view';
import {lineNumbers} from '@codemirror/view';
// 导入核心模块
import {blockState} from './state';
import {getBlockDecorationExtensions} from './decorations';
import * as commands from './commands';
import {getBlockSelectExtensions, selectAll} from './selectAll';
import {getCopyPasteExtensions, getCopyPasteKeymap} from './copyPaste';
import {deleteLineCommand} from './deleteLine';
import {getBlockSelectExtensions} from './selectAll';
import {getCopyPasteExtensions} from './copyPaste';
import {moveLineDown, moveLineUp} from './moveLines';
import {transposeChars} from './transposeChars';
import {getCodeBlockLanguageExtension} from './lang-parser';
import {createLanguageDetection} from './language-detection';
import {EditorOptions, SupportedLanguage} from './types';
@@ -92,13 +89,7 @@ export function createCodeBlockExtension(options: CodeBlockOptions = {}): Extens
defaultAutoDetect = true,
} = options;
// 将简化的配置转换为内部使用的EditorOptions
const editorOptions: EditorOptions = {
defaultBlockToken: defaultLanguage,
defaultBlockAutoDetect: defaultAutoDetect,
};
const extensions: Extension[] = [
return [
// 核心状态管理
blockState,
@@ -126,105 +117,7 @@ export function createCodeBlockExtension(options: CodeBlockOptions = {}): Extens
// 复制粘贴功能
...getCopyPasteExtensions(),
// 键盘映射
keymap.of([
// 复制粘贴命令
...getCopyPasteKeymap(),
// 块隔离选择命令
{
key: 'Mod-a',
run: selectAll,
preventDefault: true
},
// 块创建命令
{
key: 'Mod-Enter',
run: commands.addNewBlockAfterCurrent(editorOptions),
preventDefault: true
},
{
key: 'Mod-Shift-Enter',
run: commands.addNewBlockAfterLast(editorOptions),
preventDefault: true
},
{
key: 'Alt-Enter',
run: commands.addNewBlockBeforeCurrent(editorOptions),
preventDefault: true
},
// 块导航命令
{
key: 'Mod-ArrowUp',
run: commands.gotoPreviousBlock,
preventDefault: true
},
{
key: 'Mod-ArrowDown',
run: commands.gotoNextBlock,
preventDefault: true
},
{
key: 'Mod-Shift-ArrowUp',
run: commands.selectPreviousBlock,
preventDefault: true
},
{
key: 'Mod-Shift-ArrowDown',
run: commands.selectNextBlock,
preventDefault: true
},
// 块编辑命令
{
key: 'Mod-Shift-d',
run: commands.deleteBlock(editorOptions),
preventDefault: true
},
{
key: 'Alt-Mod-ArrowUp',
run: commands.moveCurrentBlockUp,
preventDefault: true
},
{
key: 'Alt-Mod-ArrowDown',
run: commands.moveCurrentBlockDown,
preventDefault: true
},
// 行编辑命令
{
key: 'Mod-Shift-k', // 删除行
run: deleteLineCommand,
preventDefault: true
},
{
key: 'Alt-ArrowUp', // 向上移动行
run: moveLineUp,
preventDefault: true
},
{
key: 'Alt-ArrowDown', // 向下移动行
run: moveLineDown,
preventDefault: true
},
{
key: 'Ctrl-t', // 字符转置
run: transposeChars,
preventDefault: true
},
// 代码格式化命令
{
key: 'Mod-Shift-f', // 格式化代码
run: commands.formatCurrentBlock,
preventDefault: true
},
])
];
return extensions;
}
@@ -271,7 +164,6 @@ export {
cutCommand,
pasteCommand,
getCopyPasteExtensions,
getCopyPasteKeymap
} from './copyPaste';
// 删除行功能

View File

@@ -218,7 +218,5 @@ function isInDelimiter(state: any, pos: number) {
export function getBlockSelectExtensions() {
return [
emptyBlockSelected,
// 禁用块边界检查以避免递归更新问题
// blockAwareSelection,
];
}

View File

@@ -7,3 +7,4 @@ export * from './fontExtension';
export * from './themeExtension';
export * from './codeblast';
export * from './codeblock';
export * from './keymap';

View File

@@ -0,0 +1,298 @@
import {KeyBindingCommand} from '@/../bindings/voidraft/internal/models/models'
import {
hideSearchVisibilityCommand,
searchReplaceAll,
searchShowReplace,
searchToggleCase,
searchToggleRegex,
searchToggleWholeWord,
showSearchVisibilityCommand
} from '../vscodeSearch/commands'
import {
addNewBlockAfterCurrent,
addNewBlockAfterLast,
addNewBlockBeforeCurrent,
deleteBlock,
formatCurrentBlock,
gotoNextBlock,
gotoPreviousBlock,
moveCurrentBlockDown,
moveCurrentBlockUp,
selectNextBlock,
selectPreviousBlock
} from '../codeblock/commands'
import { selectAll } from '../codeblock/selectAll'
import { deleteLineCommand } from '../codeblock/deleteLine'
import { moveLineUp, moveLineDown } from '../codeblock/moveLines'
import { transposeChars } from '@/views/editor/extensions'
import { copyCommand, cutCommand, pasteCommand } from '../codeblock/copyPaste'
import { undo, redo, undoSelection, redoSelection, cursorSyntaxLeft, cursorSyntaxRight, selectSyntaxLeft, selectSyntaxRight, copyLineUp, copyLineDown, insertBlankLine, selectLine, selectParentSyntax, indentLess, indentMore, indentSelection, cursorMatchingBracket, toggleComment, toggleBlockComment, insertNewlineAndIndent, deleteCharBackward, deleteCharForward, deleteGroupBackward, deleteGroupForward } from '@codemirror/commands'
import { foldCode, unfoldCode, foldAll, unfoldAll } from '@codemirror/language'
import i18n from '@/i18n'
// 默认编辑器选项
const defaultEditorOptions = {
defaultBlockToken: 'text',
defaultBlockAutoDetect: true,
}
/**
* 前端命令注册表
* 将后端定义的command字段映射到具体的前端方法和翻译键
*/
export const commandRegistry = {
[KeyBindingCommand.ShowSearchCommand]: {
handler: showSearchVisibilityCommand,
descriptionKey: 'keybindings.commands.showSearch'
},
[KeyBindingCommand.HideSearchCommand]: {
handler: hideSearchVisibilityCommand,
descriptionKey: 'keybindings.commands.hideSearch'
},
[KeyBindingCommand.SearchToggleCaseCommand]: {
handler: searchToggleCase,
descriptionKey: 'keybindings.commands.searchToggleCase'
},
[KeyBindingCommand.SearchToggleWordCommand]: {
handler: searchToggleWholeWord,
descriptionKey: 'keybindings.commands.searchToggleWord'
},
[KeyBindingCommand.SearchToggleRegexCommand]: {
handler: searchToggleRegex,
descriptionKey: 'keybindings.commands.searchToggleRegex'
},
[KeyBindingCommand.SearchShowReplaceCommand]: {
handler: searchShowReplace,
descriptionKey: 'keybindings.commands.searchShowReplace'
},
[KeyBindingCommand.SearchReplaceAllCommand]: {
handler: searchReplaceAll,
descriptionKey: 'keybindings.commands.searchReplaceAll'
},
// 代码块操作命令
[KeyBindingCommand.BlockSelectAllCommand]: {
handler: selectAll,
descriptionKey: 'keybindings.commands.blockSelectAll'
},
[KeyBindingCommand.BlockAddAfterCurrentCommand]: {
handler: addNewBlockAfterCurrent(defaultEditorOptions),
descriptionKey: 'keybindings.commands.blockAddAfterCurrent'
},
[KeyBindingCommand.BlockAddAfterLastCommand]: {
handler: addNewBlockAfterLast(defaultEditorOptions),
descriptionKey: 'keybindings.commands.blockAddAfterLast'
},
[KeyBindingCommand.BlockAddBeforeCurrentCommand]: {
handler: addNewBlockBeforeCurrent(defaultEditorOptions),
descriptionKey: 'keybindings.commands.blockAddBeforeCurrent'
},
[KeyBindingCommand.BlockGotoPreviousCommand]: {
handler: gotoPreviousBlock,
descriptionKey: 'keybindings.commands.blockGotoPrevious'
},
[KeyBindingCommand.BlockGotoNextCommand]: {
handler: gotoNextBlock,
descriptionKey: 'keybindings.commands.blockGotoNext'
},
[KeyBindingCommand.BlockSelectPreviousCommand]: {
handler: selectPreviousBlock,
descriptionKey: 'keybindings.commands.blockSelectPrevious'
},
[KeyBindingCommand.BlockSelectNextCommand]: {
handler: selectNextBlock,
descriptionKey: 'keybindings.commands.blockSelectNext'
},
[KeyBindingCommand.BlockDeleteCommand]: {
handler: deleteBlock(defaultEditorOptions),
descriptionKey: 'keybindings.commands.blockDelete'
},
[KeyBindingCommand.BlockMoveUpCommand]: {
handler: moveCurrentBlockUp,
descriptionKey: 'keybindings.commands.blockMoveUp'
},
[KeyBindingCommand.BlockMoveDownCommand]: {
handler: moveCurrentBlockDown,
descriptionKey: 'keybindings.commands.blockMoveDown'
},
[KeyBindingCommand.BlockDeleteLineCommand]: {
handler: deleteLineCommand,
descriptionKey: 'keybindings.commands.blockDeleteLine'
},
[KeyBindingCommand.BlockMoveLineUpCommand]: {
handler: moveLineUp,
descriptionKey: 'keybindings.commands.blockMoveLineUp'
},
[KeyBindingCommand.BlockMoveLineDownCommand]: {
handler: moveLineDown,
descriptionKey: 'keybindings.commands.blockMoveLineDown'
},
[KeyBindingCommand.BlockTransposeCharsCommand]: {
handler: transposeChars,
descriptionKey: 'keybindings.commands.blockTransposeChars'
},
[KeyBindingCommand.BlockFormatCommand]: {
handler: formatCurrentBlock,
descriptionKey: 'keybindings.commands.blockFormat'
},
[KeyBindingCommand.BlockCopyCommand]: {
handler: copyCommand,
descriptionKey: 'keybindings.commands.blockCopy'
},
[KeyBindingCommand.BlockCutCommand]: {
handler: cutCommand,
descriptionKey: 'keybindings.commands.blockCut'
},
[KeyBindingCommand.BlockPasteCommand]: {
handler: pasteCommand,
descriptionKey: 'keybindings.commands.blockPaste'
},
[KeyBindingCommand.HistoryUndoCommand]: {
handler: undo,
descriptionKey: 'keybindings.commands.historyUndo'
},
[KeyBindingCommand.HistoryRedoCommand]: {
handler: redo,
descriptionKey: 'keybindings.commands.historyRedo'
},
[KeyBindingCommand.HistoryUndoSelectionCommand]: {
handler: undoSelection,
descriptionKey: 'keybindings.commands.historyUndoSelection'
},
[KeyBindingCommand.HistoryRedoSelectionCommand]: {
handler: redoSelection,
descriptionKey: 'keybindings.commands.historyRedoSelection'
},
[KeyBindingCommand.FoldCodeCommand]: {
handler: foldCode,
descriptionKey: 'keybindings.commands.foldCode'
},
[KeyBindingCommand.UnfoldCodeCommand]: {
handler: unfoldCode,
descriptionKey: 'keybindings.commands.unfoldCode'
},
[KeyBindingCommand.FoldAllCommand]: {
handler: foldAll,
descriptionKey: 'keybindings.commands.foldAll'
},
[KeyBindingCommand.UnfoldAllCommand]: {
handler: unfoldAll,
descriptionKey: 'keybindings.commands.unfoldAll'
},
[KeyBindingCommand.CursorSyntaxLeftCommand]: {
handler: cursorSyntaxLeft,
descriptionKey: 'keybindings.commands.cursorSyntaxLeft'
},
[KeyBindingCommand.CursorSyntaxRightCommand]: {
handler: cursorSyntaxRight,
descriptionKey: 'keybindings.commands.cursorSyntaxRight'
},
[KeyBindingCommand.SelectSyntaxLeftCommand]: {
handler: selectSyntaxLeft,
descriptionKey: 'keybindings.commands.selectSyntaxLeft'
},
[KeyBindingCommand.SelectSyntaxRightCommand]: {
handler: selectSyntaxRight,
descriptionKey: 'keybindings.commands.selectSyntaxRight'
},
[KeyBindingCommand.CopyLineUpCommand]: {
handler: copyLineUp,
descriptionKey: 'keybindings.commands.copyLineUp'
},
[KeyBindingCommand.CopyLineDownCommand]: {
handler: copyLineDown,
descriptionKey: 'keybindings.commands.copyLineDown'
},
[KeyBindingCommand.InsertBlankLineCommand]: {
handler: insertBlankLine,
descriptionKey: 'keybindings.commands.insertBlankLine'
},
[KeyBindingCommand.SelectLineCommand]: {
handler: selectLine,
descriptionKey: 'keybindings.commands.selectLine'
},
[KeyBindingCommand.SelectParentSyntaxCommand]: {
handler: selectParentSyntax,
descriptionKey: 'keybindings.commands.selectParentSyntax'
},
[KeyBindingCommand.IndentLessCommand]: {
handler: indentLess,
descriptionKey: 'keybindings.commands.indentLess'
},
[KeyBindingCommand.IndentMoreCommand]: {
handler: indentMore,
descriptionKey: 'keybindings.commands.indentMore'
},
[KeyBindingCommand.IndentSelectionCommand]: {
handler: indentSelection,
descriptionKey: 'keybindings.commands.indentSelection'
},
[KeyBindingCommand.CursorMatchingBracketCommand]: {
handler: cursorMatchingBracket,
descriptionKey: 'keybindings.commands.cursorMatchingBracket'
},
[KeyBindingCommand.ToggleCommentCommand]: {
handler: toggleComment,
descriptionKey: 'keybindings.commands.toggleComment'
},
[KeyBindingCommand.ToggleBlockCommentCommand]: {
handler: toggleBlockComment,
descriptionKey: 'keybindings.commands.toggleBlockComment'
},
[KeyBindingCommand.InsertNewlineAndIndentCommand]: {
handler: insertNewlineAndIndent,
descriptionKey: 'keybindings.commands.insertNewlineAndIndent'
},
[KeyBindingCommand.DeleteCharBackwardCommand]: {
handler: deleteCharBackward,
descriptionKey: 'keybindings.commands.deleteCharBackward'
},
[KeyBindingCommand.DeleteCharForwardCommand]: {
handler: deleteCharForward,
descriptionKey: 'keybindings.commands.deleteCharForward'
},
[KeyBindingCommand.DeleteGroupBackwardCommand]: {
handler: deleteGroupBackward,
descriptionKey: 'keybindings.commands.deleteGroupBackward'
},
[KeyBindingCommand.DeleteGroupForwardCommand]: {
handler: deleteGroupForward,
descriptionKey: 'keybindings.commands.deleteGroupForward'
},
} as const
/**
* 获取命令处理函数
* @param command 命令名称
* @returns 对应的处理函数,如果不存在则返回 undefined
*/
export const getCommandHandler = (command: KeyBindingCommand) => {
return commandRegistry[command]?.handler
}
/**
* 获取命令描述
* @param command 命令名称
* @returns 对应的描述,如果不存在则返回 undefined
*/
export const getCommandDescription = (command: KeyBindingCommand) => {
const descriptionKey = commandRegistry[command]?.descriptionKey
return descriptionKey ? i18n.global.t(descriptionKey) : undefined
}
/**
* 检查命令是否已注册
* @param command 命令名称
* @returns 是否已注册
*/
export const isCommandRegistered = (command: KeyBindingCommand): boolean => {
return command in commandRegistry
}
/**
* 获取所有已注册的命令
* @returns 已注册的命令列表
*/
export const getRegisteredCommands = (): KeyBindingCommand[] => {
return Object.keys(commandRegistry) as KeyBindingCommand[]
}

View File

@@ -0,0 +1,23 @@
import { Extension } from '@codemirror/state'
import { useKeybindingStore } from '@/stores/keybindingStore'
import { KeymapManager } from './keymapManager'
/**
* 异步创建快捷键扩展
* 确保快捷键配置已加载
*/
export const createDynamicKeymapExtension = async (): Promise<Extension> => {
const keybindingStore = useKeybindingStore()
// 确保快捷键配置已加载
if (keybindingStore.keyBindings.length === 0) {
await keybindingStore.loadKeyBindings()
}
return KeymapManager.createKeymapExtension(keybindingStore.enabledKeyBindings)
}
// 导出相关模块
export { KeymapManager } from './keymapManager'
export { commandRegistry, getCommandHandler, getCommandDescription, isCommandRegistered, getRegisteredCommands } from './commandRegistry'
export type { KeyBinding, CommandHandler, CommandDefinition, KeymapResult } from './types'

View File

@@ -0,0 +1,84 @@
import {keymap} from '@codemirror/view'
import {Extension} from '@codemirror/state'
import {KeyBinding as KeyBindingConfig} from '@/../bindings/voidraft/internal/models/models'
import {KeyBinding, KeymapResult} from './types'
import {getCommandHandler, isCommandRegistered} from './commandRegistry'
/**
* 快捷键管理器
* 负责将后端配置转换为CodeMirror快捷键扩展
*/
export class KeymapManager {
/**
* 将后端快捷键配置转换为CodeMirror快捷键绑定
* @param keyBindings 后端快捷键配置列表
* @returns 转换结果
*/
static convertToKeyBindings(keyBindings: KeyBindingConfig[]): KeymapResult {
const result: KeyBinding[] = []
for (const binding of keyBindings) {
// 跳过禁用的快捷键
if (!binding.enabled) {
continue
}
// 检查命令是否已注册
if (!isCommandRegistered(binding.command)) {
continue
}
// 获取命令处理函数
const handler = getCommandHandler(binding.command)
if (!handler) {
continue
}
// 转换为CodeMirror快捷键格式
const keyBinding: KeyBinding = {
key: binding.key,
run: handler,
preventDefault: true
}
result.push(keyBinding)
}
return {keyBindings: result}
}
/**
* 创建CodeMirror快捷键扩展
* @param keyBindings 后端快捷键配置列表
* @returns CodeMirror扩展
*/
static createKeymapExtension(keyBindings: KeyBindingConfig[]): Extension {
const {keyBindings: cmKeyBindings} =
this.convertToKeyBindings(keyBindings)
return keymap.of(cmKeyBindings)
}
/**
* 验证快捷键配置
* @param keyBindings 快捷键配置列表
* @returns 验证结果
*/
static validateKeyBindings(keyBindings: KeyBindingConfig[]): {
valid: KeyBindingConfig[]
invalid: KeyBindingConfig[]
} {
const valid: KeyBindingConfig[] = []
const invalid: KeyBindingConfig[] = []
for (const binding of keyBindings) {
if (binding.enabled && binding.key && isCommandRegistered(binding.command)) {
valid.push(binding)
} else {
invalid.push(binding)
}
}
return {valid, invalid}
}
}

View File

@@ -0,0 +1,30 @@
import {Command} from '@codemirror/view'
/**
* CodeMirror快捷键绑定格式
*/
export interface KeyBinding {
key: string
run: Command
preventDefault?: boolean
}
/**
* 命令处理函数类型
*/
export type CommandHandler = Command
/**
* 命令定义接口
*/
export interface CommandDefinition {
handler: CommandHandler
descriptionKey: string // 翻译键
}
/**
* 快捷键转换结果
*/
export interface KeymapResult {
keyBindings: KeyBinding[]
}

View File

@@ -1,5 +1,4 @@
export { VSCodeSearch, vscodeSearch} from "./plugin";
export { searchVisibilityField, SearchVisibilityEffect } from "./state";
export { customSearchKeymap } from "./keymap";
export { searchBaseTheme } from "./theme"
export * from "./commands"

View File

@@ -1,81 +0,0 @@
import { KeyBinding } from "@codemirror/view";
import { deleteCharacterBackwards, deleteCharacterFowards, hideSearchVisibilityCommand, searchFindPrevious, searchFindReplaceMatch, searchMoveCursorLeft, searchMoveCursorRight, searchReplaceAll, searchShowReplace, searchToggleCase, searchToggleRegex, searchToggleWholeWord, selectAllCommand, showSearchVisibilityCommand } from "./commands";
export const customSearchKeymap: KeyBinding[] = [
// 全局快捷键 - 不需要 scope 限制
{
key: 'Mod-f',
run: showSearchVisibilityCommand,
},
// 添加备用快捷键绑定,确保兼容性
{
key: 'Ctrl-f',
run: showSearchVisibilityCommand,
},
// 搜索面板内的快捷键 - 需要 scope 限制
{
key: 'Mod-a',
run: selectAllCommand,
scope: 'search'
},
{
key: 'Escape',
run: hideSearchVisibilityCommand,
scope: 'search'
},
{
key: 'Alt-c',
run: searchToggleCase,
scope: 'search'
},
{
key: 'Alt-w',
run: searchToggleWholeWord,
scope: 'search'
},
{
key: 'Alt-r',
run: searchToggleRegex,
scope: 'search'
},
{
key: 'Mod-h',
run: searchShowReplace,
scope: 'search'
},
{
key: 'Enter',
run: searchFindReplaceMatch,
scope: 'search'
},
{
key: 'Shift-Enter',
run: searchFindPrevious,
scope: 'search'
},
{
key: 'Mod-Alt-Enter',
run: searchReplaceAll,
scope: 'search'
},
{
key: 'Backspace',
run: deleteCharacterBackwards,
scope: 'search'
},
{
key: 'Delete',
run: deleteCharacterFowards,
scope: 'search'
},
{
key: "ArrowLeft",
run: searchMoveCursorLeft,
scope: 'search'
},
{
key: "ArrowRight",
run: searchMoveCursorRight,
scope: 'search'
},
];

View File

@@ -1,74 +1,196 @@
<script setup lang="ts">
import { useI18n } from 'vue-i18n';
import { ref } from 'vue';
import { onMounted, computed } from 'vue';
import SettingSection from '../components/SettingSection.vue';
import { useKeybindingStore } from '@/stores/keybindingStore';
import { useSystemStore } from '@/stores/systemStore';
import { getCommandDescription } from '@/views/editor/extensions/keymap/commandRegistry';
import {KeyBindingCommand} from "@/../bindings/voidraft/internal/models";
const { t } = useI18n();
const keybindingStore = useKeybindingStore();
const systemStore = useSystemStore();
interface KeyBinding {
id: string;
name: string;
keys: string[];
isEditing: boolean;
}
// 示例快捷键列表(仅用于界面展示)
const keyBindings = ref<KeyBinding[]>([
{ id: 'save', name: '保存文档', keys: ['Ctrl', 'S'], isEditing: false },
{ id: 'new', name: '新建文档', keys: ['Ctrl', 'N'], isEditing: false },
{ id: 'open', name: '打开文档', keys: ['Ctrl', 'O'], isEditing: false },
{ id: 'find', name: '查找', keys: ['Ctrl', 'F'], isEditing: false },
{ id: 'replace', name: '替换', keys: ['Ctrl', 'H'], isEditing: false },
]);
// 从store中获取快捷键数据并转换为显示格式
const keyBindings = computed(() => {
return keybindingStore.keyBindings
.filter(kb => kb.enabled)
.map(kb => ({
id: kb.command,
keys: parseKeyBinding(kb.key, kb.command),
category: kb.category,
description: getCommandDescription(kb.command) || kb.command
}));
});
// 切换编辑状态
const toggleEdit = (binding: KeyBinding) => {
// 先关闭其他所有编辑中的项
keyBindings.value.forEach(item => {
if (item.id !== binding.id) {
item.isEditing = false;
}
});
// 解析快捷键字符串为显示数组
const parseKeyBinding = (keyStr: string, command?: string): string[] => {
if (!keyStr) return [];
// 切换当前项
binding.isEditing = !binding.isEditing;
};
// 编辑模式下按键事件处理
const handleKeyDown = (event: KeyboardEvent, binding: KeyBinding) => {
if (!binding.isEditing) return;
event.preventDefault();
event.stopPropagation();
const newKeys: string[] = [];
if (event.ctrlKey) newKeys.push('Ctrl');
if (event.shiftKey) newKeys.push('Shift');
if (event.altKey) newKeys.push('Alt');
// 获取按键
let keyName = event.key;
if (keyName === ' ') keyName = 'Space';
if (keyName.length === 1) keyName = keyName.toUpperCase();
// 如果有修饰键,就添加主键
if (event.ctrlKey || event.shiftKey || event.altKey) {
if (!['Control', 'Shift', 'Alt'].includes(keyName)) {
newKeys.push(keyName);
}
// 特殊处理重做快捷键的操作系统差异
if (command === KeyBindingCommand.HistoryRedoCommand && keyStr === 'Mod-Shift-z') {
if (systemStore.isMacOS) {
return ['⌘', '⇧', 'Z']; // macOS: Cmd+Shift+Z
} else {
// 没有修饰键,直接使用主键
newKeys.push(keyName);
return ['Ctrl', 'Y']; // Windows/Linux: Ctrl+Y
}
}
// 唯一按键,不增加空字段
if (newKeys.length > 0) {
binding.keys = [...new Set(newKeys)];
// 特殊处理重做选择快捷键的操作系统差异
if (command === KeyBindingCommand.HistoryRedoSelectionCommand && keyStr === 'Mod-Shift-u') {
if (systemStore.isMacOS) {
return ['⌘', '⇧', 'U']; // macOS: Cmd+Shift+U
} else {
return ['Alt', 'U']; // Windows/Linux: Alt+U
}
}
// 完成编辑
binding.isEditing = false;
// 特殊处理代码折叠快捷键的操作系统差异
if (command === KeyBindingCommand.FoldCodeCommand && keyStr === 'Ctrl-Shift-[') {
if (systemStore.isMacOS) {
return ['⌘', '⌥', '[']; // macOS: Cmd+Alt+[
} else {
return ['Ctrl', '⇧', '[']; // Windows/Linux: Ctrl+Shift+[
}
}
if (command === KeyBindingCommand.UnfoldCodeCommand && keyStr === 'Ctrl-Shift-]') {
if (systemStore.isMacOS) {
return ['⌘', '⌥', ']']; // macOS: Cmd+Alt+]
} else {
return ['Ctrl', '⇧', ']']; // Windows/Linux: Ctrl+Shift+]
}
}
// 特殊处理编辑快捷键的操作系统差异
if (command === KeyBindingCommand.CursorSyntaxLeftCommand && keyStr === 'Alt-ArrowLeft') {
if (systemStore.isMacOS) {
return ['Ctrl', '←']; // macOS: Ctrl+ArrowLeft
} else {
return ['Alt', '←']; // Windows/Linux: Alt+ArrowLeft
}
}
if (command === KeyBindingCommand.CursorSyntaxRightCommand && keyStr === 'Alt-ArrowRight') {
if (systemStore.isMacOS) {
return ['Ctrl', '→']; // macOS: Ctrl+ArrowRight
} else {
return ['Alt', '→']; // Windows/Linux: Alt+ArrowRight
}
}
if (command === KeyBindingCommand.InsertBlankLineCommand && keyStr === 'Ctrl-Enter') {
if (systemStore.isMacOS) {
return ['⌘', 'Enter']; // macOS: Cmd+Enter
} else {
return ['Ctrl', 'Enter']; // Windows/Linux: Ctrl+Enter
}
}
if (command === KeyBindingCommand.SelectLineCommand && keyStr === 'Alt-l') {
if (systemStore.isMacOS) {
return ['Ctrl', 'L']; // macOS: Ctrl+l
} else {
return ['Alt', 'L']; // Windows/Linux: Alt+l
}
}
if (command === KeyBindingCommand.SelectParentSyntaxCommand && keyStr === 'Ctrl-i') {
if (systemStore.isMacOS) {
return ['⌘', 'I']; // macOS: Cmd+i
} else {
return ['Ctrl', 'I']; // Windows/Linux: Ctrl+i
}
}
if (command === KeyBindingCommand.IndentLessCommand && keyStr === 'Ctrl-[') {
if (systemStore.isMacOS) {
return ['⌘', '[']; // macOS: Cmd+[
} else {
return ['Ctrl', '[']; // Windows/Linux: Ctrl+[
}
}
if (command === KeyBindingCommand.IndentMoreCommand && keyStr === 'Ctrl-]') {
if (systemStore.isMacOS) {
return ['⌘', ']']; // macOS: Cmd+]
} else {
return ['Ctrl', ']']; // Windows/Linux: Ctrl+]
}
}
if (command === KeyBindingCommand.IndentSelectionCommand && keyStr === 'Ctrl-Alt-\\') {
if (systemStore.isMacOS) {
return ['⌘', '⌥', '\\']; // macOS: Cmd+Alt+\
} else {
return ['Ctrl', 'Alt', '\\']; // Windows/Linux: Ctrl+Alt+\
}
}
if (command === KeyBindingCommand.CursorMatchingBracketCommand && keyStr === 'Shift-Ctrl-\\') {
if (systemStore.isMacOS) {
return ['⇧', '⌘', '\\']; // macOS: Shift+Cmd+\
} else {
return ['⇧', 'Ctrl', '\\']; // Windows/Linux: Shift+Ctrl+\
}
}
if (command === KeyBindingCommand.ToggleCommentCommand && keyStr === 'Ctrl-/') {
if (systemStore.isMacOS) {
return ['⌘', '/']; // macOS: Cmd+/
} else {
return ['Ctrl', '/']; // Windows/Linux: Ctrl+/
}
}
// 特殊处理删除快捷键的操作系统差异
if (command === KeyBindingCommand.DeleteGroupBackwardCommand && keyStr === 'Ctrl-Backspace') {
if (systemStore.isMacOS) {
return ['⌘', 'Backspace']; // macOS: Cmd+Backspace
} else {
return ['Ctrl', 'Backspace']; // Windows/Linux: Ctrl+Backspace
}
}
if (command === KeyBindingCommand.DeleteGroupForwardCommand && keyStr === 'Ctrl-Delete') {
if (systemStore.isMacOS) {
return ['⌘', 'Delete']; // macOS: Cmd+Delete
} else {
return ['Ctrl', 'Delete']; // Windows/Linux: Ctrl+Delete
}
}
// 处理常见的快捷键格式
const parts = keyStr.split(/[-+]/);
return parts.map(part => {
// 根据操作系统将 Mod 替换为相应的键
if (part === 'Mod') {
if (systemStore.isMacOS) {
return '⌘'; // macOS 使用 Command 键符号
} else {
return 'Ctrl'; // Windows/Linux 使用 Ctrl
}
}
// 处理其他键名的操作系统差异
if (part === 'Alt' && systemStore.isMacOS) {
return '⌥'; // macOS 使用 Option 键符号
}
if (part === 'Shift') {
return systemStore.isMacOS ? '⇧' : 'Shift'; // macOS 使用符号
}
// 首字母大写
return part.charAt(0).toUpperCase() + part.slice(1).toLowerCase();
}).filter(part => part.length > 0);
};
// 组件挂载时加载快捷键数据
onMounted(async () => {
await keybindingStore.loadKeyBindings();
});
</script>
<template>
@@ -76,25 +198,17 @@ const handleKeyDown = (event: KeyboardEvent, binding: KeyBinding) => {
<SettingSection :title="t('settings.keyBindings')">
<div class="key-bindings-container">
<div class="key-bindings-header">
<div class="command-col">命令</div>
<div class="keybinding-col">快捷键</div>
<div class="action-col">操作</div>
<div class="keybinding-col">{{ t('keybindings.headers.shortcut') }}</div>
<div class="category-col">{{ t('keybindings.headers.category') }}</div>
<div class="description-col">{{ t('keybindings.headers.description') }}</div>
</div>
<div
v-for="binding in keyBindings"
:key="binding.id"
class="key-binding-row"
:class="{ 'is-editing': binding.isEditing }"
@keydown="(e) => handleKeyDown(e, binding)"
tabindex="0"
>
<div class="command-col">{{ binding.name }}</div>
<div class="keybinding-col" :class="{ 'is-editing': binding.isEditing }">
<template v-if="binding.isEditing">
按下快捷键...
</template>
<template v-else>
<div class="keybinding-col">
<span
v-for="(key, index) in binding.keys"
:key="index"
@@ -102,16 +216,9 @@ const handleKeyDown = (event: KeyboardEvent, binding: KeyBinding) => {
>
{{ key }}
</span>
</template>
</div>
<div class="action-col">
<button
class="edit-button"
@click="toggleEdit(binding)"
>
{{ binding.isEditing ? '取消' : '编辑' }}
</button>
</div>
<div class="category-col">{{ binding.category }}</div>
<div class="description-col">{{ binding.description }}</div>
</div>
</div>
</SettingSection>
@@ -143,36 +250,17 @@ const handleKeyDown = (event: KeyboardEvent, binding: KeyBinding) => {
align-items: center;
transition: background-color 0.2s ease;
&:focus {
outline: none;
}
&:hover {
background-color: var(--settings-hover);
}
&.is-editing {
background-color: rgba(74, 158, 255, 0.1);
}
}
.command-col {
flex: 1;
padding-right: 10px;
font-size: 13px;
color: var(--settings-text);
}
.keybinding-col {
width: 200px;
width: 150px;
display: flex;
gap: 5px;
padding: 0 10px;
&.is-editing {
font-style: italic;
color: var(--text-muted);
}
padding: 0 10px 0 0;
color: var(--settings-text);
.key-badge {
background-color: var(--settings-input-bg);
@@ -184,29 +272,18 @@ const handleKeyDown = (event: KeyboardEvent, binding: KeyBinding) => {
}
}
.action-col {
.category-col {
width: 80px;
text-align: right;
.edit-button {
padding: 5px 10px;
background-color: var(--settings-input-bg);
border: 1px solid var(--settings-input-border);
border-radius: 4px;
padding: 0 10px 0 0;
font-size: 13px;
color: var(--settings-text);
cursor: pointer;
font-size: 12px;
transition: all 0.2s ease;
&:hover {
background-color: var(--settings-hover);
border-color: var(--settings-border);
text-transform: capitalize;
}
&:active {
transform: translateY(1px);
}
}
.description-col {
flex: 1;
font-size: 13px;
color: var(--settings-text);
}
}

View File

@@ -4,9 +4,8 @@ import "time"
// KeyBinding 单个快捷键绑定
type KeyBinding struct {
Action KeyBindingAction `json:"action"` // 快捷键动作
Command KeyBindingCommand `json:"command"` // 快捷键动作
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"` // 是否为默认快捷键
@@ -18,75 +17,78 @@ 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" // 应用相关
CategoryCodeBlock KeyBindingCategory = "block" // 代码块相关
CategoryHistory KeyBindingCategory = "history" // 历史记录相关
CategoryFold KeyBindingCategory = "fold" // 代码折叠相关
)
// KeyBindingScope 快捷键作用域
type KeyBindingScope string
const (
ScopeGlobal KeyBindingScope = "global" // 全局作用域
ScopeEditor KeyBindingScope = "editor" // 编辑器作用域
ScopeSearch KeyBindingScope = "search" // 搜索面板作用域
)
// KeyBindingAction 快捷键动作类型
type KeyBindingAction string
// KeyBindingCommand 快捷键命令
type KeyBindingCommand 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" // 取消缩进
ShowSearchCommand KeyBindingCommand = "showSearch" // 显示搜索
HideSearchCommand KeyBindingCommand = "hideSearch" // 隐藏搜索
SearchToggleCaseCommand KeyBindingCommand = "searchToggleCase" // 搜索切换大小写
SearchToggleWordCommand KeyBindingCommand = "searchToggleWord" // 搜索切换整词
SearchToggleRegexCommand KeyBindingCommand = "searchToggleRegex" // 搜索切换正则
SearchShowReplaceCommand KeyBindingCommand = "searchShowReplace" // 显示替换
SearchReplaceAllCommand KeyBindingCommand = "searchReplaceAll" // 替换全部
// 代码块相关
ActionNewCodeBlock KeyBindingAction = "newCodeBlock" // 新建代码
ActionDeleteCodeBlock KeyBindingAction = "deleteCodeBlock" // 删除代码
ActionSelectCodeBlock KeyBindingAction = "selectCodeBlock" // 选择代码
ActionFormatCode KeyBindingAction = "formatCode" // 格式化代码
ActionChangeLanguage KeyBindingAction = "changeLanguage" // 更改语言
BlockSelectAllCommand KeyBindingCommand = "blockSelectAll" // 块内选择全部
BlockAddAfterCurrentCommand KeyBindingCommand = "blockAddAfterCurrent" // 在当前块后添加新
BlockAddAfterLastCommand KeyBindingCommand = "blockAddAfterLast" // 在最后添加新
BlockAddBeforeCurrentCommand KeyBindingCommand = "blockAddBeforeCurrent" // 在当前块前添加新块
BlockGotoPreviousCommand KeyBindingCommand = "blockGotoPrevious" // 跳转到上一个块
BlockGotoNextCommand KeyBindingCommand = "blockGotoNext" // 跳转到下一个块
BlockSelectPreviousCommand KeyBindingCommand = "blockSelectPrevious" // 选择上一个块
BlockSelectNextCommand KeyBindingCommand = "blockSelectNext" // 选择下一个块
BlockDeleteCommand KeyBindingCommand = "blockDelete" // 删除当前块
BlockMoveUpCommand KeyBindingCommand = "blockMoveUp" // 向上移动当前块
BlockMoveDownCommand KeyBindingCommand = "blockMoveDown" // 向下移动当前块
BlockDeleteLineCommand KeyBindingCommand = "blockDeleteLine" // 删除行
BlockMoveLineUpCommand KeyBindingCommand = "blockMoveLineUp" // 向上移动行
BlockMoveLineDownCommand KeyBindingCommand = "blockMoveLineDown" // 向下移动行
BlockTransposeCharsCommand KeyBindingCommand = "blockTransposeChars" // 字符转置
BlockFormatCommand KeyBindingCommand = "blockFormat" // 格式化代码块
BlockCopyCommand KeyBindingCommand = "blockCopy" // 复制
BlockCutCommand KeyBindingCommand = "blockCut" // 剪切
BlockPasteCommand KeyBindingCommand = "blockPaste" // 粘贴
// 导航相关
ActionGoToLine KeyBindingAction = "goToLine" // 跳转到行
ActionFoldAll KeyBindingAction = "foldAll" // 折叠所有
ActionUnfoldAll KeyBindingAction = "unfoldAll" // 展开所有
ActionToggleFold KeyBindingAction = "toggleFold" // 切换折叠
// 历史记录相关
HistoryUndoCommand KeyBindingCommand = "historyUndo" // 撤销
HistoryRedoCommand KeyBindingCommand = "historyRedo" // 重做
HistoryUndoSelectionCommand KeyBindingCommand = "historyUndoSelection" // 撤销选择
HistoryRedoSelectionCommand KeyBindingCommand = "historyRedoSelection" // 重做选择
// 视图相关
ActionZoomIn KeyBindingAction = "zoomIn" // 放大
ActionZoomOut KeyBindingAction = "zoomOut" // 缩小
ActionResetZoom KeyBindingAction = "resetZoom" // 重置缩放
ActionToggleMinimap KeyBindingAction = "toggleMinimap" // 切换小地图
ActionToggleLineNumbers KeyBindingAction = "toggleLineNumbers" // 切换行号
// 代码折叠相关
FoldCodeCommand KeyBindingCommand = "foldCode" // 折叠代码
UnfoldCodeCommand KeyBindingCommand = "unfoldCode" // 展开代码
FoldAllCommand KeyBindingCommand = "foldAll" // 折叠全部
UnfoldAllCommand KeyBindingCommand = "unfoldAll" // 展开全部
// 文件相关
ActionSave KeyBindingAction = "save" // 保存
// 编辑相关
CursorSyntaxLeftCommand KeyBindingCommand = "cursorSyntaxLeft" // 光标按语法左移
CursorSyntaxRightCommand KeyBindingCommand = "cursorSyntaxRight" // 光标按语法右移
SelectSyntaxLeftCommand KeyBindingCommand = "selectSyntaxLeft" // 按语法选择左侧
SelectSyntaxRightCommand KeyBindingCommand = "selectSyntaxRight" // 按语法选择右侧
CopyLineUpCommand KeyBindingCommand = "copyLineUp" // 向上复制行
CopyLineDownCommand KeyBindingCommand = "copyLineDown" // 向下复制行
InsertBlankLineCommand KeyBindingCommand = "insertBlankLine" // 插入空行
SelectLineCommand KeyBindingCommand = "selectLine" // 选择行
SelectParentSyntaxCommand KeyBindingCommand = "selectParentSyntax" // 选择父级语法
IndentLessCommand KeyBindingCommand = "indentLess" // 减少缩进
IndentMoreCommand KeyBindingCommand = "indentMore" // 增加缩进
IndentSelectionCommand KeyBindingCommand = "indentSelection" // 缩进选择
CursorMatchingBracketCommand KeyBindingCommand = "cursorMatchingBracket" // 光标到匹配括号
ToggleCommentCommand KeyBindingCommand = "toggleComment" // 切换注释
ToggleBlockCommentCommand KeyBindingCommand = "toggleBlockComment" // 切换块注释
InsertNewlineAndIndentCommand KeyBindingCommand = "insertNewlineAndIndent" // 插入新行并缩进
DeleteCharBackwardCommand KeyBindingCommand = "deleteCharBackward" // 向后删除字符
DeleteCharForwardCommand KeyBindingCommand = "deleteCharForward" // 向前删除字符
DeleteGroupBackwardCommand KeyBindingCommand = "deleteGroupBackward" // 向后删除组
DeleteGroupForwardCommand KeyBindingCommand = "deleteGroupForward" // 向前删除组
)
// KeyBindingMetadata 快捷键配置元数据
@@ -115,308 +117,388 @@ func NewDefaultKeyBindings() []KeyBinding {
return []KeyBinding{
// 搜索相关快捷键
{
Action: ActionShowSearch,
Command: ShowSearchCommand,
Category: CategorySearch,
Scope: ScopeGlobal,
Key: "Mod-f",
Enabled: true,
IsDefault: true,
},
{
Action: ActionHideSearch,
Command: HideSearchCommand,
Category: CategorySearch,
Scope: ScopeSearch,
Key: "Escape",
Enabled: true,
IsDefault: true,
},
{
Action: ActionFindNext,
Command: SearchToggleCaseCommand,
Category: CategorySearch,
Scope: ScopeSearch,
Key: "Enter",
Enabled: true,
IsDefault: true,
},
{
Action: ActionFindPrevious,
Category: CategorySearch,
Scope: ScopeSearch,
Key: "Shift-Enter",
Enabled: true,
IsDefault: true,
},
{
Action: ActionShowReplace,
Category: CategorySearch,
Scope: ScopeSearch,
Key: "Mod-h",
Enabled: true,
IsDefault: true,
},
{
Action: ActionReplaceAll,
Category: CategorySearch,
Scope: ScopeSearch,
Key: "Mod-Alt-Enter",
Enabled: true,
IsDefault: true,
},
{
Action: ActionToggleCase,
Category: CategorySearch,
Scope: ScopeSearch,
Key: "Alt-c",
Enabled: true,
IsDefault: true,
},
{
Action: ActionToggleWholeWord,
Command: SearchToggleWordCommand,
Category: CategorySearch,
Scope: ScopeSearch,
Key: "Alt-w",
Enabled: true,
IsDefault: true,
},
{
Action: ActionToggleRegex,
Command: SearchToggleRegexCommand,
Category: CategorySearch,
Scope: ScopeSearch,
Key: "Alt-r",
Enabled: true,
IsDefault: true,
},
// 编辑相关快捷键
{
Action: ActionSelectAll,
Category: CategoryEdit,
Scope: ScopeEditor,
Key: "Mod-a",
Command: SearchShowReplaceCommand,
Category: CategorySearch,
Key: "Mod-h",
Enabled: true,
IsDefault: true,
},
{
Action: ActionCopy,
Category: CategoryEdit,
Scope: ScopeEditor,
Key: "Mod-c",
Enabled: true,
IsDefault: true,
},
{
Action: ActionCut,
Category: CategoryEdit,
Scope: ScopeEditor,
Key: "Mod-x",
Enabled: true,
IsDefault: true,
},
{
Action: ActionPaste,
Category: CategoryEdit,
Scope: ScopeEditor,
Key: "Mod-v",
Enabled: true,
IsDefault: true,
},
{
Action: ActionUndo,
Category: CategoryEdit,
Scope: ScopeEditor,
Key: "Mod-z",
Enabled: true,
IsDefault: true,
},
{
Action: ActionRedo,
Category: CategoryEdit,
Scope: ScopeEditor,
Key: "Mod-y",
Enabled: true,
IsDefault: true,
},
{
Action: ActionDuplicateLine,
Category: CategoryEdit,
Scope: ScopeEditor,
Key: "Mod-d",
Enabled: true,
IsDefault: true,
},
{
Action: ActionDeleteLine,
Category: CategoryEdit,
Scope: ScopeEditor,
Key: "Mod-Shift-k",
Enabled: true,
IsDefault: true,
},
{
Action: ActionMoveLineUp,
Category: CategoryEdit,
Scope: ScopeEditor,
Key: "Alt-ArrowUp",
Enabled: true,
IsDefault: true,
},
{
Action: ActionMoveLineDown,
Category: CategoryEdit,
Scope: ScopeEditor,
Key: "Alt-ArrowDown",
Enabled: true,
IsDefault: true,
},
{
Action: ActionToggleComment,
Category: CategoryEdit,
Scope: ScopeEditor,
Key: "Mod-/",
Enabled: true,
IsDefault: true,
},
{
Action: ActionIndent,
Category: CategoryEdit,
Scope: ScopeEditor,
Key: "Tab",
Enabled: true,
IsDefault: true,
},
{
Action: ActionOutdent,
Category: CategoryEdit,
Scope: ScopeEditor,
Key: "Shift-Tab",
Command: SearchReplaceAllCommand,
Category: CategorySearch,
Key: "Mod-Alt-Enter",
Enabled: true,
IsDefault: true,
},
// 代码块相关快捷键
{
Action: ActionNewCodeBlock,
Command: BlockSelectAllCommand,
Category: CategoryCodeBlock,
Scope: ScopeEditor,
Key: "Mod-Alt-n",
Key: "Mod-a",
Enabled: true,
IsDefault: true,
},
{
Action: ActionDeleteCodeBlock,
Command: BlockAddAfterCurrentCommand,
Category: CategoryCodeBlock,
Scope: ScopeEditor,
Key: "Mod-Alt-d",
Key: "Mod-Enter",
Enabled: true,
IsDefault: true,
},
{
Action: ActionSelectCodeBlock,
Command: BlockAddAfterLastCommand,
Category: CategoryCodeBlock,
Scope: ScopeEditor,
Key: "Mod-Alt-a",
Key: "Mod-Shift-Enter",
Enabled: true,
IsDefault: true,
},
{
Action: ActionFormatCode,
Command: BlockAddBeforeCurrentCommand,
Category: CategoryCodeBlock,
Scope: ScopeEditor,
Key: "Mod-Alt-f",
Key: "Alt-Enter",
Enabled: true,
IsDefault: true,
},
{
Action: ActionChangeLanguage,
Command: BlockGotoPreviousCommand,
Category: CategoryCodeBlock,
Scope: ScopeEditor,
Key: "Mod-Alt-l",
Key: "Mod-ArrowUp",
Enabled: true,
IsDefault: true,
},
{
Command: BlockGotoNextCommand,
Category: CategoryCodeBlock,
Key: "Mod-ArrowDown",
Enabled: true,
IsDefault: true,
},
{
Command: BlockSelectPreviousCommand,
Category: CategoryCodeBlock,
Key: "Mod-Shift-ArrowUp",
Enabled: true,
IsDefault: true,
},
{
Command: BlockSelectNextCommand,
Category: CategoryCodeBlock,
Key: "Mod-Shift-ArrowDown",
Enabled: true,
IsDefault: true,
},
{
Command: BlockDeleteCommand,
Category: CategoryCodeBlock,
Key: "Mod-Shift-d",
Enabled: true,
IsDefault: true,
},
{
Command: BlockMoveUpCommand,
Category: CategoryCodeBlock,
Key: "Alt-Mod-ArrowUp",
Enabled: true,
IsDefault: true,
},
{
Command: BlockMoveDownCommand,
Category: CategoryCodeBlock,
Key: "Alt-Mod-ArrowDown",
Enabled: true,
IsDefault: true,
},
{
Command: BlockDeleteLineCommand,
Category: CategoryCodeBlock,
Key: "Mod-Shift-k",
Enabled: true,
IsDefault: true,
},
{
Command: BlockMoveLineUpCommand,
Category: CategoryCodeBlock,
Key: "Alt-ArrowUp",
Enabled: true,
IsDefault: true,
},
{
Command: BlockMoveLineDownCommand,
Category: CategoryCodeBlock,
Key: "Alt-ArrowDown",
Enabled: true,
IsDefault: true,
},
{
Command: BlockTransposeCharsCommand,
Category: CategoryCodeBlock,
Key: "Ctrl-t",
Enabled: true,
IsDefault: true,
},
{
Command: BlockFormatCommand,
Category: CategoryCodeBlock,
Key: "Mod-Shift-f",
Enabled: true,
IsDefault: true,
},
{
Command: BlockCopyCommand,
Category: CategoryCodeBlock,
Key: "Mod-c",
Enabled: true,
IsDefault: true,
},
{
Command: BlockCutCommand,
Category: CategoryCodeBlock,
Key: "Mod-x",
Enabled: true,
IsDefault: true,
},
{
Command: BlockPasteCommand,
Category: CategoryCodeBlock,
Key: "Mod-v",
Enabled: true,
IsDefault: true,
},
// 导航相关快捷键
// 历史记录相关快捷键
{
Action: ActionGoToLine,
Category: CategoryNavigation,
Scope: ScopeEditor,
Key: "Mod-g",
Command: HistoryUndoCommand,
Category: CategoryHistory,
Key: "Mod-z",
Enabled: true,
IsDefault: true,
},
{
Action: ActionFoldAll,
Category: CategoryNavigation,
Scope: ScopeEditor,
Key: "Mod-k Mod-0",
Command: HistoryRedoCommand,
Category: CategoryHistory,
Key: "Mod-Shift-z",
Enabled: true,
IsDefault: true,
},
{
Action: ActionUnfoldAll,
Category: CategoryNavigation,
Scope: ScopeEditor,
Key: "Mod-k Mod-j",
Command: HistoryUndoSelectionCommand,
Category: CategoryHistory,
Key: "Mod-u",
Enabled: true,
IsDefault: true,
},
{
Action: ActionToggleFold,
Category: CategoryNavigation,
Scope: ScopeEditor,
Key: "Mod-k Mod-l",
Command: HistoryRedoSelectionCommand,
Category: CategoryHistory,
Key: "Mod-Shift-u",
Enabled: true,
IsDefault: true,
},
// 视图相关快捷键
// 代码折叠相关快捷键
{
Action: ActionZoomIn,
Category: CategoryView,
Scope: ScopeGlobal,
Key: "Mod-=",
Command: FoldCodeCommand,
Category: CategoryFold,
Key: "Ctrl-Shift-[",
Enabled: true,
IsDefault: true,
},
{
Action: ActionZoomOut,
Category: CategoryView,
Scope: ScopeGlobal,
Key: "Mod--",
Command: UnfoldCodeCommand,
Category: CategoryFold,
Key: "Ctrl-Shift-]",
Enabled: true,
IsDefault: true,
},
{
Action: ActionResetZoom,
Category: CategoryView,
Scope: ScopeGlobal,
Key: "Mod-0",
Command: FoldAllCommand,
Category: CategoryFold,
Key: "Ctrl-Alt-[",
Enabled: true,
IsDefault: true,
},
{
Action: ActionToggleMinimap,
Category: CategoryView,
Scope: ScopeGlobal,
Key: "Mod-m",
Enabled: true,
IsDefault: true,
},
{
Action: ActionToggleLineNumbers,
Category: CategoryView,
Scope: ScopeGlobal,
Key: "Mod-l",
Command: UnfoldAllCommand,
Category: CategoryFold,
Key: "Ctrl-Alt-]",
Enabled: true,
IsDefault: true,
},
// 文件相关快捷键
// 编辑相关快捷键 (避免冲突的快捷键)
{
Action: ActionSave,
Category: CategoryFile,
Scope: ScopeGlobal,
Key: "Mod-s",
Command: CursorSyntaxLeftCommand,
Category: CategoryEdit,
Key: "Alt-ArrowLeft",
Enabled: true,
IsDefault: true,
},
{
Command: CursorSyntaxRightCommand,
Category: CategoryEdit,
Key: "Alt-ArrowRight",
Enabled: true,
IsDefault: true,
},
{
Command: SelectSyntaxLeftCommand,
Category: CategoryEdit,
Key: "Shift-Alt-ArrowLeft",
Enabled: true,
IsDefault: true,
},
{
Command: SelectSyntaxRightCommand,
Category: CategoryEdit,
Key: "Shift-Alt-ArrowRight",
Enabled: true,
IsDefault: true,
},
{
Command: CopyLineUpCommand,
Category: CategoryEdit,
Key: "Shift-Alt-ArrowUp",
Enabled: true,
IsDefault: true,
},
{
Command: CopyLineDownCommand,
Category: CategoryEdit,
Key: "Shift-Alt-ArrowDown",
Enabled: true,
IsDefault: true,
},
{
Command: InsertBlankLineCommand,
Category: CategoryEdit,
Key: "Ctrl-Enter",
Enabled: true,
IsDefault: true,
},
{
Command: SelectLineCommand,
Category: CategoryEdit,
Key: "Alt-l",
Enabled: true,
IsDefault: true,
},
{
Command: SelectParentSyntaxCommand,
Category: CategoryEdit,
Key: "Ctrl-i",
Enabled: true,
IsDefault: true,
},
{
Command: IndentLessCommand,
Category: CategoryEdit,
Key: "Ctrl-[",
Enabled: true,
IsDefault: true,
},
{
Command: IndentMoreCommand,
Category: CategoryEdit,
Key: "Ctrl-]",
Enabled: true,
IsDefault: true,
},
{
Command: IndentSelectionCommand,
Category: CategoryEdit,
Key: "Ctrl-Alt-\\",
Enabled: true,
IsDefault: true,
},
{
Command: CursorMatchingBracketCommand,
Category: CategoryEdit,
Key: "Shift-Ctrl-\\",
Enabled: true,
IsDefault: true,
},
{
Command: ToggleCommentCommand,
Category: CategoryEdit,
Key: "Ctrl-/",
Enabled: true,
IsDefault: true,
},
{
Command: ToggleBlockCommentCommand,
Category: CategoryEdit,
Key: "Shift-Alt-a",
Enabled: true,
IsDefault: true,
},
{
Command: InsertNewlineAndIndentCommand,
Category: CategoryEdit,
Key: "Enter",
Enabled: true,
IsDefault: true,
},
{
Command: DeleteCharBackwardCommand,
Category: CategoryEdit,
Key: "Backspace",
Enabled: true,
IsDefault: true,
},
{
Command: DeleteCharForwardCommand,
Category: CategoryEdit,
Key: "Delete",
Enabled: true,
IsDefault: true,
},
{
Command: DeleteGroupBackwardCommand,
Category: CategoryEdit,
Key: "Ctrl-Backspace",
Enabled: true,
IsDefault: true,
},
{
Command: DeleteGroupForwardCommand,
Category: CategoryEdit,
Key: "Ctrl-Delete",
Enabled: true,
IsDefault: true,
},

View File

@@ -26,14 +26,14 @@ type KeyBindingService struct {
// KeyBindingError 快捷键错误
type KeyBindingError struct {
Operation string // 操作名称
Action string // 快捷键Action
Command string // 快捷键Command
Err error // 原始错误
}
// Error 实现error接口
func (e *KeyBindingError) Error() string {
if e.Action != "" {
return fmt.Sprintf("keybinding error during %s for action %s: %v", e.Operation, e.Action, e.Err)
if e.Command != "" {
return fmt.Sprintf("keybinding error during %s for command %s: %v", e.Operation, e.Command, e.Err)
}
return fmt.Sprintf("keybinding error during %s: %v", e.Operation, e.Err)
}
@@ -225,28 +225,8 @@ func (kbs *KeyBindingService) GetKeyBindingsByCategory(category models.KeyBindin
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
}
// GetKeyBindingByAction 根据动作获取快捷键
func (kbs *KeyBindingService) GetKeyBindingByAction(action models.KeyBindingAction) (*models.KeyBinding, error) {
// GetKeyBindingByCommand 根据命令获取快捷键
func (kbs *KeyBindingService) GetKeyBindingByCommand(command models.KeyBindingCommand) (*models.KeyBinding, error) {
kbs.mu.RLock()
defer kbs.mu.RUnlock()
@@ -256,19 +236,19 @@ func (kbs *KeyBindingService) GetKeyBindingByAction(action models.KeyBindingActi
}
for _, kb := range allKeyBindings {
if kb.Action == action && kb.Enabled {
if kb.Command == command && kb.Enabled {
return &kb, nil
}
}
return nil, &KeyBindingError{
Operation: "get_keybinding_by_action",
Err: fmt.Errorf("keybinding for action %s not found", action),
Operation: "get_keybinding_by_command",
Err: fmt.Errorf("keybinding for command %s not found", command),
}
}
// UpdateKeyBinding 更新快捷键
func (kbs *KeyBindingService) UpdateKeyBinding(action models.KeyBindingAction, newKey string) error {
func (kbs *KeyBindingService) UpdateKeyBinding(command models.KeyBindingCommand, newKey string) error {
kbs.mu.Lock()
defer kbs.mu.Unlock()
@@ -276,16 +256,16 @@ func (kbs *KeyBindingService) UpdateKeyBinding(action models.KeyBindingAction, n
if err := kbs.validateKeyFormat(newKey); err != nil {
return &KeyBindingError{
Operation: "update_keybinding",
Action: string(action),
Command: string(command),
Err: fmt.Errorf("invalid key format: %v", err),
}
}
// 检查快捷键冲突
if err := kbs.checkKeyConflict(action, newKey); err != nil {
if err := kbs.checkKeyConflict(command, newKey); err != nil {
return &KeyBindingError{
Operation: "update_keybinding",
Action: string(action),
Command: string(command),
Err: fmt.Errorf("key conflict: %v", err),
}
}
@@ -293,13 +273,13 @@ func (kbs *KeyBindingService) UpdateKeyBinding(action models.KeyBindingAction, n
// 获取当前配置
config, err := kbs.GetKeyBindingConfig()
if err != nil {
return &KeyBindingError{Operation: "update_keybinding", Action: string(action), Err: err}
return &KeyBindingError{Operation: "update_keybinding", Command: string(command), Err: err}
}
// 查找并更新快捷键
found := false
for i, kb := range config.KeyBindings {
if kb.Action == action {
if kb.Command == command {
config.KeyBindings[i].Key = newKey
config.KeyBindings[i].IsDefault = false // 标记为非默认
found = true
@@ -310,7 +290,7 @@ func (kbs *KeyBindingService) UpdateKeyBinding(action models.KeyBindingAction, n
if !found {
return &KeyBindingError{
Operation: "update_keybinding",
Action: string(action),
Command: string(command),
Err: errors.New("keybinding not found"),
}
}
@@ -320,38 +300,38 @@ func (kbs *KeyBindingService) UpdateKeyBinding(action models.KeyBindingAction, n
// 保存配置
if err := kbs.saveConfig(config); err != nil {
return &KeyBindingError{Operation: "update_keybinding", Action: string(action), Err: err}
return &KeyBindingError{Operation: "update_keybinding", Command: string(command), Err: err}
}
kbs.logger.Info("KeyBinding: Updated keybinding", "action", action, "newKey", newKey)
kbs.logger.Info("KeyBinding: Updated keybinding", "command", command, "newKey", newKey)
return nil
}
// EnableKeyBinding 启用快捷键
func (kbs *KeyBindingService) EnableKeyBinding(action models.KeyBindingAction) error {
return kbs.setKeyBindingEnabled(action, true)
func (kbs *KeyBindingService) EnableKeyBinding(command models.KeyBindingCommand) error {
return kbs.setKeyBindingEnabled(command, true)
}
// DisableKeyBinding 禁用快捷键
func (kbs *KeyBindingService) DisableKeyBinding(action models.KeyBindingAction) error {
return kbs.setKeyBindingEnabled(action, false)
func (kbs *KeyBindingService) DisableKeyBinding(command models.KeyBindingCommand) error {
return kbs.setKeyBindingEnabled(command, false)
}
// setKeyBindingEnabled 设置快捷键启用状态
func (kbs *KeyBindingService) setKeyBindingEnabled(action models.KeyBindingAction, enabled bool) error {
func (kbs *KeyBindingService) setKeyBindingEnabled(command models.KeyBindingCommand, enabled bool) error {
kbs.mu.Lock()
defer kbs.mu.Unlock()
// 获取当前配置
config, err := kbs.GetKeyBindingConfig()
if err != nil {
return &KeyBindingError{Operation: "set_keybinding_enabled", Action: string(action), Err: err}
return &KeyBindingError{Operation: "set_keybinding_enabled", Command: string(command), Err: err}
}
// 查找并更新快捷键
found := false
for i, kb := range config.KeyBindings {
if kb.Action == action {
if kb.Command == command {
config.KeyBindings[i].Enabled = enabled
found = true
break
@@ -361,7 +341,7 @@ func (kbs *KeyBindingService) setKeyBindingEnabled(action models.KeyBindingActio
if !found {
return &KeyBindingError{
Operation: "set_keybinding_enabled",
Action: string(action),
Command: string(command),
Err: errors.New("keybinding not found"),
}
}
@@ -371,19 +351,19 @@ func (kbs *KeyBindingService) setKeyBindingEnabled(action models.KeyBindingActio
// 保存配置
if err := kbs.saveConfig(config); err != nil {
return &KeyBindingError{Operation: "set_keybinding_enabled", Action: string(action), Err: err}
return &KeyBindingError{Operation: "set_keybinding_enabled", Command: string(command), Err: err}
}
status := "enabled"
if !enabled {
status = "disabled"
}
kbs.logger.Info("KeyBinding: "+status+" keybinding", "action", action)
kbs.logger.Info("KeyBinding: "+status+" keybinding", "command", command)
return nil
}
// ResetKeyBinding 重置快捷键到默认值
func (kbs *KeyBindingService) ResetKeyBinding(action models.KeyBindingAction) error {
func (kbs *KeyBindingService) ResetKeyBinding(command models.KeyBindingCommand) error {
kbs.mu.Lock()
defer kbs.mu.Unlock()
@@ -391,7 +371,7 @@ func (kbs *KeyBindingService) ResetKeyBinding(action models.KeyBindingAction) er
defaultKeyBindings := models.NewDefaultKeyBindings()
var defaultKeyBinding *models.KeyBinding
for _, kb := range defaultKeyBindings {
if kb.Action == action {
if kb.Command == command {
defaultKeyBinding = &kb
break
}
@@ -400,7 +380,7 @@ func (kbs *KeyBindingService) ResetKeyBinding(action models.KeyBindingAction) er
if defaultKeyBinding == nil {
return &KeyBindingError{
Operation: "reset_keybinding",
Action: string(action),
Command: string(command),
Err: errors.New("default keybinding not found"),
}
}
@@ -408,13 +388,13 @@ func (kbs *KeyBindingService) ResetKeyBinding(action models.KeyBindingAction) er
// 获取当前配置
config, err := kbs.GetKeyBindingConfig()
if err != nil {
return &KeyBindingError{Operation: "reset_keybinding", Action: string(action), Err: err}
return &KeyBindingError{Operation: "reset_keybinding", Command: string(command), Err: err}
}
// 查找并重置快捷键
found := false
for i, kb := range config.KeyBindings {
if kb.Action == action {
if kb.Command == command {
config.KeyBindings[i].Key = defaultKeyBinding.Key
config.KeyBindings[i].Enabled = defaultKeyBinding.Enabled
config.KeyBindings[i].IsDefault = true
@@ -426,7 +406,7 @@ func (kbs *KeyBindingService) ResetKeyBinding(action models.KeyBindingAction) er
if !found {
return &KeyBindingError{
Operation: "reset_keybinding",
Action: string(action),
Command: string(command),
Err: errors.New("keybinding not found"),
}
}
@@ -436,10 +416,10 @@ func (kbs *KeyBindingService) ResetKeyBinding(action models.KeyBindingAction) er
// 保存配置
if err := kbs.saveConfig(config); err != nil {
return &KeyBindingError{Operation: "reset_keybinding", Action: string(action), Err: err}
return &KeyBindingError{Operation: "reset_keybinding", Command: string(command), Err: err}
}
kbs.logger.Info("KeyBinding: Reset keybinding to default", "action", action, "key", defaultKeyBinding.Key)
kbs.logger.Info("KeyBinding: Reset keybinding to default", "command", command, "key", defaultKeyBinding.Key)
return nil
}
@@ -515,15 +495,15 @@ func (kbs *KeyBindingService) validateKeyFormat(key string) error {
}
// checkKeyConflict 检查快捷键冲突
func (kbs *KeyBindingService) checkKeyConflict(excludeAction models.KeyBindingAction, key string) error {
func (kbs *KeyBindingService) checkKeyConflict(excludeCommand models.KeyBindingCommand, key string) error {
allKeyBindings, err := kbs.GetAllKeyBindings()
if err != nil {
return err
}
for _, kb := range allKeyBindings {
if kb.Action != excludeAction && kb.Key == key && kb.Enabled {
return fmt.Errorf("key %s is already used by %s", key, kb.Action)
if kb.Command != excludeCommand && kb.Key == key && kb.Enabled {
return fmt.Errorf("key %s is already used by %s", key, kb.Command)
}
}
@@ -536,19 +516,8 @@ func (kbs *KeyBindingService) GetKeyBindingCategories() []models.KeyBindingCateg
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,
models.CategoryHistory,
models.CategoryFold,
}
}
@@ -570,23 +539,23 @@ func (kbs *KeyBindingService) ImportKeyBindings(keyBindings []models.KeyBinding)
if err := kbs.validateKeyFormat(kb.Key); err != nil {
return &KeyBindingError{
Operation: "import_keybindings",
Action: string(kb.Action),
Err: fmt.Errorf("invalid key format for %s: %v", kb.Action, err),
Command: string(kb.Command),
Err: fmt.Errorf("invalid key format for %s: %v", kb.Command, err),
}
}
}
// 检查重复的快捷键
keyMap := make(map[string]models.KeyBindingAction)
keyMap := make(map[string]models.KeyBindingCommand)
for _, kb := range keyBindings {
if kb.Enabled {
if existingAction, exists := keyMap[kb.Key]; exists {
if existingCommand, exists := keyMap[kb.Key]; exists {
return &KeyBindingError{
Operation: "import_keybindings",
Err: fmt.Errorf("duplicate key %s found in %s and %s", kb.Key, existingAction, kb.Action),
Err: fmt.Errorf("duplicate key %s found in %s and %s", kb.Key, existingCommand, kb.Command),
}
}
keyMap[kb.Key] = kb.Action
keyMap[kb.Key] = kb.Command
}
}