diff --git a/web/src/components/file-editor/EditorPane.vue b/web/src/components/file-editor/EditorPane.vue index 99d234a1..58effa86 100644 --- a/web/src/components/file-editor/EditorPane.vue +++ b/web/src/components/file-editor/EditorPane.vue @@ -28,6 +28,11 @@ function handleTabsWheel(e: WheelEvent) { } } +// 获取编辑器主题(nginx 特殊处理) +function getEditorTheme(language: string) { + return (language === 'nginx' ? 'nginx-theme' : 'vs') + (themeStore.darkMode ? '-dark' : '') +} + // 初始化编辑器 async function initEditor() { if (!containerRef.value) return @@ -105,11 +110,7 @@ function updateEditorContent() { if (model) { const language = languageByPath(tab.path) monacoRef.value.editor.setModelLanguage(model, language) - - // 更新主题(nginx 特殊处理) - const theme = - (language === 'nginx' ? 'nginx-theme' : 'vs') + (themeStore.darkMode ? '-dark' : '') - monacoRef.value.editor.setTheme(theme) + monacoRef.value.editor.setTheme(getEditorTheme(language)) } } @@ -269,6 +270,35 @@ watch( } ) +// 监听语言变化(用户手动切换语言时更新 Monaco 高亮) +watch( + () => editorStore.activeTab?.language, + (newLanguage) => { + if (!editorRef.value || !monacoRef.value || !newLanguage) return + const model = editorRef.value.getModel() + if (model) { + monacoRef.value.editor.setModelLanguage(model, newLanguage) + monacoRef.value.editor.setTheme(getEditorTheme(newLanguage)) + } + } +) + +// 监听行分隔符变化(用户手动切换行分隔符时更新 Monaco) +watch( + () => editorStore.activeTab?.lineEnding, + (newLineEnding) => { + if (!editorRef.value || !monacoRef.value || !newLineEnding) return + const model = editorRef.value.getModel() + if (model) { + const eol = + newLineEnding === 'CRLF' + ? monacoRef.value.editor.EndOfLineSequence.CRLF + : monacoRef.value.editor.EndOfLineSequence.LF + model.setEOL(eol) + } + } +) + // 监听当前标签页内容变化(外部更新) watch( () => editorStore.activeTab?.content, @@ -287,9 +317,7 @@ watch( () => { if (!monacoRef.value || !editorStore.activeTab) return const language = languageByPath(editorStore.activeTab.path) - const theme = - (language === 'nginx' ? 'nginx-theme' : 'vs') + (themeStore.darkMode ? '-dark' : '') - monacoRef.value.editor.setTheme(theme) + monacoRef.value.editor.setTheme(getEditorTheme(language)) } ) diff --git a/web/src/components/file-editor/EditorStatusBar.vue b/web/src/components/file-editor/EditorStatusBar.vue index 79d78e50..958761e3 100644 --- a/web/src/components/file-editor/EditorStatusBar.vue +++ b/web/src/components/file-editor/EditorStatusBar.vue @@ -35,9 +35,6 @@ const languages = [ 'dockerfile' ] -// 支持的编码列表 -const encodings = ['utf-8', 'gbk', 'gb2312', 'iso-8859-1', 'utf-16', 'utf-16le', 'utf-16be'] - // 缩进选项 const indentOptions = computed(() => [ { label: `${$gettext('Spaces')}: 2`, value: '2-spaces' }, @@ -59,13 +56,6 @@ function handleLineEndingChange(value: 'LF' | 'CRLF') { } } -// 更新编码 -function handleEncodingChange(value: string) { - if (editorStore.activeTab) { - editorStore.updateEncoding(editorStore.activeTab.path, value) - } -} - // 更新语言 function handleLanguageChange(value: string) { if (editorStore.activeTab) { @@ -121,18 +111,6 @@ function handleIndentChange(value: string) { - - -
- {{ $gettext('Encoding') }}: {{ editorStore.activeTab.encoding }} -
-
- { @@ -302,7 +302,7 @@ async function confirmInlineCreate() { // 如果是文件,自动打开 if (!isDir) { - editorStore.openFile(createdPath, '', 'utf-8') + editorStore.openFile(createdPath, '') } }) .onError(() => { @@ -568,7 +568,7 @@ function confirmInlineRename() { const tab = editorStore.tabs.find((t) => t.path === oldPath) if (tab) { editorStore.closeTab(oldPath) - editorStore.openFile(newPath, tab.content, tab.encoding) + editorStore.openFile(newPath, tab.content) if (!tab.modified) { editorStore.markSaved(newPath) } diff --git a/web/src/store/modules/editor/index.ts b/web/src/store/modules/editor/index.ts index d1c255d8..cebcb353 100644 --- a/web/src/store/modules/editor/index.ts +++ b/web/src/store/modules/editor/index.ts @@ -9,7 +9,6 @@ export interface EditorTab { language: string // 语言类型 modified: boolean // 是否已修改 loading: boolean // 是否正在加载 - encoding: string // 文件编码 lineEnding: 'LF' | 'CRLF' // 行分隔符 cursorLine: number // 光标行 cursorColumn: number // 光标列 @@ -48,7 +47,18 @@ const defaultSettings: EditorSettings = { insertSpaces: true, wordWrap: 'on', fontSize: 14, - minimap: true + minimap: true, + lineNumbers: 'on', + renderWhitespace: 'selection', + cursorBlinking: 'blink', + cursorStyle: 'line', + smoothScrolling: true, + mouseWheelZoom: true, + bracketPairColorization: true, + guides: true, + folding: true, + formatOnPaste: false, + formatOnType: false } export const useEditorStore = defineStore('editor', { @@ -85,7 +95,7 @@ export const useEditorStore = defineStore('editor', { actions: { // 打开文件(添加标签页) - openFile(path: string, content: string = '', encoding: string = 'utf-8') { + openFile(path: string, content: string = '') { const existingTab = this.tabs.find((tab) => tab.path === path) if (existingTab) { // 文件已打开,切换到该标签页 @@ -105,7 +115,6 @@ export const useEditorStore = defineStore('editor', { language: languageByPath(path), modified: false, loading: false, - encoding, lineEnding, cursorLine: 1, cursorColumn: 1 @@ -169,7 +178,10 @@ export const useEditorStore = defineStore('editor', { const tab = this.tabs.find((t) => t.path === path) if (tab) { tab.content = content - tab.modified = content !== tab.originalContent + // 将内容规范化为 LF 后比较,避免行分隔符差异影响修改状态判断 + const normalizedContent = content.replace(/\r\n/g, '\n') + const normalizedOriginal = tab.originalContent.replace(/\r\n/g, '\n') + tab.modified = normalizedContent !== normalizedOriginal } }, @@ -196,21 +208,6 @@ export const useEditorStore = defineStore('editor', { const tab = this.tabs.find((t) => t.path === path) if (tab && tab.lineEnding !== lineEnding) { tab.lineEnding = lineEnding - // 转换内容中的行分隔符 - if (lineEnding === 'CRLF') { - tab.content = tab.content.replace(/(? t.path === path) - if (tab) { - tab.encoding = encoding } }, diff --git a/web/src/utils/file/index.ts b/web/src/utils/file/index.ts index c3d8115e..7037152c 100644 --- a/web/src/utils/file/index.ts +++ b/web/src/utils/file/index.ts @@ -286,6 +286,8 @@ const languageByPath = (path: string) => { case 'yaml': case 'yml': // yaml 扩展名 return 'yaml' + case 'json': + return 'json' default: return 'plaintext' } diff --git a/web/src/views/file/EditModal.vue b/web/src/views/file/EditModal.vue index 99c95bc4..74d14e8e 100644 --- a/web/src/views/file/EditModal.vue +++ b/web/src/views/file/EditModal.vue @@ -38,7 +38,7 @@ function loadFile(path: string) { } // 打开新文件 - editorStore.openFile(path, '', 'utf-8') + editorStore.openFile(path, '') editorStore.setLoading(path, true) useRequest(file.content(encodeURIComponent(path)))