diff --git a/frontend/src/components/toolbar/index.vue b/frontend/src/components/toolbar/index.vue index 7253fbc..1adc952 100644 --- a/frontend/src/components/toolbar/index.vue +++ b/frontend/src/components/toolbar/index.vue @@ -18,7 +18,7 @@ const editorStore = useEditorStore();
- + {{ editorStore.fontSize }}px diff --git a/frontend/src/editor/extensions/basicSetup.ts b/frontend/src/editor/extensions/basicSetup.ts new file mode 100644 index 0000000..0cd1c1e --- /dev/null +++ b/frontend/src/editor/extensions/basicSetup.ts @@ -0,0 +1,79 @@ +import {Extension} from '@codemirror/state'; +import { + crosshairCursor, + drawSelection, + dropCursor, + EditorView, + highlightActiveLine, + highlightActiveLineGutter, + highlightSpecialChars, + keymap, + lineNumbers, + rectangularSelection, +} from '@codemirror/view'; +import { + bracketMatching, + defaultHighlightStyle, + foldGutter, + foldKeymap, + indentOnInput, + syntaxHighlighting, +} from '@codemirror/language'; +import { + defaultKeymap, + history, + historyKeymap, +} from '@codemirror/commands'; +import {highlightSelectionMatches, searchKeymap} from '@codemirror/search'; +import {autocompletion, closeBrackets, closeBracketsKeymap, completionKeymap} from '@codemirror/autocomplete'; +import {lintKeymap} from '@codemirror/lint'; +import {baseDark, customHighlightActiveLine} from '@/editor/theme/base-dark'; + +// 基本编辑器设置,包含常用扩展 +export const createBasicSetup = (): Extension[] => { + return [ + // 主题相关 + baseDark, + + // 基础UI + lineNumbers(), + highlightActiveLineGutter(), + highlightSpecialChars(), + dropCursor(), + EditorView.lineWrapping, + + // 历史记录 + history(), + + // 代码折叠 + foldGutter(), + + // 选择与高亮 + drawSelection(), + customHighlightActiveLine, + highlightActiveLine(), + highlightSelectionMatches(), + rectangularSelection(), + crosshairCursor(), + + // 缩进和编辑辅助 + indentOnInput(), + syntaxHighlighting(defaultHighlightStyle, {fallback: true}), + bracketMatching(), + closeBrackets(), + + // 自动完成 + autocompletion(), + + // 键盘映射 + keymap.of([ + ...closeBracketsKeymap, + ...defaultKeymap, + ...searchKeymap, + ...historyKeymap, + ...foldKeymap, + ...completionKeymap, + ...lintKeymap + ]), + ]; +}; \ No newline at end of file diff --git a/frontend/src/editor/extensions/index.ts b/frontend/src/editor/extensions/index.ts new file mode 100644 index 0000000..233c8ce --- /dev/null +++ b/frontend/src/editor/extensions/index.ts @@ -0,0 +1,4 @@ +// 统一导出所有扩展 +export * from './tabExtension'; +export * from './wheelZoomExtension'; +export * from './statsExtension'; \ No newline at end of file diff --git a/frontend/src/editor/extensions/statsExtension.ts b/frontend/src/editor/extensions/statsExtension.ts new file mode 100644 index 0000000..ed71a51 --- /dev/null +++ b/frontend/src/editor/extensions/statsExtension.ts @@ -0,0 +1,42 @@ +import {Extension} from '@codemirror/state'; +import {EditorView} from '@codemirror/view'; +import {DocumentStats} from '@/types/editor'; + +// 更新编辑器文档统计信息 +export const updateStats = ( + view: EditorView, + updateDocumentStats: (stats: DocumentStats) => void +) => { + if (!view) return; + + const state = view.state; + const doc = state.doc; + const text = doc.toString(); + + // 计算选中的字符数 + let selectedChars = 0; + const selections = state.selection; + if (selections) { + for (let i = 0; i < selections.ranges.length; i++) { + const range = selections.ranges[i]; + selectedChars += range.to - range.from; + } + } + + updateDocumentStats({ + lines: doc.lines, + characters: text.length, + selectedCharacters: selectedChars + }); +}; + +// 创建统计信息更新监听器扩展 +export const createStatsUpdateExtension = ( + updateDocumentStats: (stats: DocumentStats) => void +): Extension => { + return EditorView.updateListener.of(update => { + if (update.docChanged || update.selectionSet) { + updateStats(update.view, updateDocumentStats); + } + }); +}; \ No newline at end of file diff --git a/frontend/src/editor/extensions/tabExtension.ts b/frontend/src/editor/extensions/tabExtension.ts new file mode 100644 index 0000000..abccd63 --- /dev/null +++ b/frontend/src/editor/extensions/tabExtension.ts @@ -0,0 +1,74 @@ +import {Compartment, Extension} from '@codemirror/state'; +import {EditorView, keymap} from '@codemirror/view'; +import {indentSelection} from '@codemirror/commands'; +import {indentUnit} from '@codemirror/language'; + +// Tab设置相关的compartment +export const tabSizeCompartment = new Compartment(); +export const tabKeyCompartment = new Compartment(); + +// 自定义Tab键处理函数 +export const tabHandler = (view: EditorView, tabSize: number): boolean => { + // 如果有选中文本,使用indentSelection + if (!view.state.selection.main.empty) { + return indentSelection(view); + } + + // 创建相应数量的空格 + const spaces = ' '.repeat(tabSize); + + // 在光标位置插入空格 + const {state, dispatch} = view; + dispatch(state.update(state.replaceSelection(spaces), {scrollIntoView: true})); + return true; +}; + +// 获取Tab相关的扩展 +export const getTabExtensions = (tabSize: number, enableTabIndent: boolean): Extension[] => { + const extensions: Extension[] = []; + + // 设置缩进单位 + extensions.push(tabSizeCompartment.of(indentUnit.of(' '.repeat(tabSize)))); + + // 如果启用了Tab缩进,添加自定义Tab键映射 + if (enableTabIndent) { + extensions.push( + tabKeyCompartment.of( + keymap.of([{ + key: "Tab", + run: (view) => tabHandler(view, tabSize) + }]) + ) + ); + } else { + extensions.push(tabKeyCompartment.of([])); + } + + return extensions; +}; + +// 更新Tab配置 +export const updateTabConfig = ( + view: EditorView | null, + tabSize: number, + enableTabIndent: boolean +) => { + if (!view) return; + + // 更新indentUnit配置 + view.dispatch({ + effects: tabSizeCompartment.reconfigure(indentUnit.of(' '.repeat(tabSize))) + }); + + // 更新Tab键映射 + const tabKeymap = enableTabIndent + ? keymap.of([{ + key: "Tab", + run: (view) => tabHandler(view, tabSize) + }]) + : []; + + view.dispatch({ + effects: tabKeyCompartment.reconfigure(tabKeymap) + }); +}; \ No newline at end of file diff --git a/frontend/src/editor/extensions/wheelZoomExtension.ts b/frontend/src/editor/extensions/wheelZoomExtension.ts new file mode 100644 index 0000000..92b674c --- /dev/null +++ b/frontend/src/editor/extensions/wheelZoomExtension.ts @@ -0,0 +1,35 @@ +import {EditorView} from '@codemirror/view'; + +// 处理滚轮缩放字体的事件处理函数 +export const createWheelZoomHandler = ( + increaseFontSize: () => void, + decreaseFontSize: () => void +) => { + return (event: WheelEvent) => { + // 检查是否按住了Ctrl键 + if (event.ctrlKey) { + // 阻止默认行为(防止页面缩放) + event.preventDefault(); + + // 根据滚轮方向增大或减小字体 + if (event.deltaY < 0) { + // 向上滚动,增大字体 + increaseFontSize(); + } else { + // 向下滚动,减小字体 + decreaseFontSize(); + } + } + }; +}; + +// 应用字体大小到编辑器 +export const applyFontSize = (view: EditorView, fontSize: number) => { + if (!view) return; + + // 更新编辑器的字体大小 + const editorDOM = view.dom; + if (editorDOM) { + editorDOM.style.fontSize = `${fontSize}px`; + } +}; \ No newline at end of file diff --git a/frontend/src/editor/font/font.ts b/frontend/src/editor/font/font.ts deleted file mode 100644 index 312174b..0000000 --- a/frontend/src/editor/font/font.ts +++ /dev/null @@ -1,8 +0,0 @@ -import {EditorView} from '@codemirror/view' - -export const fontTheme = EditorView.theme({ - '&': { - fontFamily: '"Microsoft YaHei", "PingFang SC", "Hiragino Sans GB", "Noto Sans SC", Arial, sans-serif', - fontSize: '12px' - } -}) \ No newline at end of file diff --git a/frontend/src/editor/index.vue b/frontend/src/editor/index.vue index 23530bc..8e33632 100644 --- a/frontend/src/editor/index.vue +++ b/frontend/src/editor/index.vue @@ -1,34 +1,17 @@