Private
Public Access
1
0

优化:代码质量提升,修复重复逻辑和语法高亮支持

- 简化计算属性,删除重复代码
- 优化文件扩展名获取逻辑
- 新增文件工具函数库 fileHelpers.js
- 增强 CodeEditor 语法高亮(支持 30+ 语言)
- 修复 Office 文档文件服务器访问权限
- 添加特殊文件名支持(Dockerfile、Makefile 等)
This commit is contained in:
2026-01-30 02:24:09 +08:00
parent b849e6cc46
commit eb2cbad17b
15 changed files with 962 additions and 761 deletions

View File

@@ -3,106 +3,91 @@
</template>
<script setup>
import { ref, onMounted, watch, onBeforeUnmount } from 'vue'
import { EditorView, lineNumbers, highlightActiveLineGutter } from '@codemirror/view'
import { ref, onMounted, watch, onBeforeUnmount, computed } from 'vue'
import { EditorView, lineNumbers, highlightActiveLineGutter, keymap } from '@codemirror/view'
import { EditorState } from '@codemirror/state'
import { defaultKeymap, history, historyKeymap } from '@codemirror/commands'
import { javascript } from '@codemirror/lang-javascript'
import { java } from '@codemirror/lang-java'
import { python } from '@codemirror/lang-python'
import { go } from '@codemirror/lang-go'
import { cpp } from '@codemirror/lang-cpp'
import { rust } from '@codemirror/lang-rust'
import { php } from '@codemirror/lang-php'
import { json } from '@codemirror/lang-json'
import { markdown } from '@codemirror/lang-markdown'
import { html } from '@codemirror/lang-html'
import { cpp } from '@codemirror/lang-cpp'
import { css } from '@codemirror/lang-css'
import { go } from '@codemirror/lang-go'
import { html } from '@codemirror/lang-html'
import { java } from '@codemirror/lang-java'
import { markdown } from '@codemirror/lang-markdown'
import { php } from '@codemirror/lang-php'
import { python } from '@codemirror/lang-python'
import { rust } from '@codemirror/lang-rust'
import { sql } from '@codemirror/lang-sql'
import { yaml } from '@codemirror/lang-yaml'
import { oneDark } from '@codemirror/theme-one-dark'
import { keymap } from '@codemirror/view'
import { bracketMatching } from '@codemirror/language'
import { StreamLanguage } from '@codemirror/language'
import { shell } from '@codemirror/legacy-modes/mode/shell'
import { powerShell } from '@codemirror/legacy-modes/mode/powershell'
import { oneDark } from '@codemirror/theme-one-dark'
import { bracketMatching } from '@codemirror/language'
import { useTheme } from '@/composables/useTheme'
// 使用主题系统
const { isDark } = useTheme()
// Legacy modes for languages without dedicated packages
import { csharp, kotlin } from '@codemirror/legacy-modes/mode/clike'
import { swift } from '@codemirror/legacy-modes/mode/swift'
import { ruby } from '@codemirror/legacy-modes/mode/ruby'
import { shell } from '@codemirror/legacy-modes/mode/shell'
import { octave } from '@codemirror/legacy-modes/mode/octave'
import { perl } from '@codemirror/legacy-modes/mode/perl'
import { r } from '@codemirror/legacy-modes/mode/r'
import { properties } from '@codemirror/legacy-modes/mode/properties'
import { dockerFile } from '@codemirror/legacy-modes/mode/dockerfile'
import { stex } from '@codemirror/legacy-modes/mode/stex'
import { xml } from '@codemirror/legacy-modes/mode/xml'
/**
* 文件扩展名到语言的映射
*/
// ==================== Constants ====================
// 文件扩展名到 CodeMirror 语言的映射
const LANGUAGE_MAP = {
// JavaScript/TypeScript
'js': javascript(),
'jsx': javascript({ jsx: true }),
'ts': javascript({ typescript: true }),
'tsx': javascript({ typescript: true, jsx: true }),
'mjs': javascript(),
'cjs': javascript(),
// JavaScript/TypeScript (使用 javascript 包)
javascript: ['js', 'jsx', 'mjs', 'cjs'],
typescript: ['ts', 'tsx'],
// JSON
'json': json(),
// 数据格式
json: ['json'],
yaml: ['yaml', 'yml'],
xml: ['xml', 'xhtml', 'svg'],
// Java
'java': java(),
// Web
html: ['html', 'htm'],
css: ['css', 'scss', 'sass', 'less'],
// Python
'py': python(),
// 系统编程
cpp: ['cpp', 'c', 'cc', 'cxx', 'h', 'hpp'],
rust: ['rs'],
go: ['go'],
// Go
'go': go(),
// 脚本语言
python: ['py', 'pyw'],
php: ['php'],
ruby: ['rb'],
perl: ['pl', 'pm'],
shell: ['sh', 'bash', 'zsh', 'fish', 'cmd', 'bat'],
sql: ['sql'],
// C/C++
'c': cpp(),
'cpp': cpp(),
'cc': cpp(),
'cxx': cpp(),
'h': cpp(),
'hpp': cpp(),
'hxx': cpp(),
// JVM 语言
java: ['java'],
kotlin: ['kt', 'kts'],
csharp: ['cs', 'csx'],
// Rust
'rs': rust(),
// 其他语言
swift: ['swift'],
markdown: ['md', 'markdown'],
r: ['r'],
matlab: ['m'],
latex: ['tex'],
makefile: ['makefile', 'make', 'mk', 'gnumakefile'],
ini: ['ini', 'cfg', 'conf', 'properties'],
dockerfile: ['dockerfile', 'containerfile'],
gitignore: ['gitignore', 'gitignore-global', 'gitattributes'],
// PHP
'php': php(),
// Markdown
'md': markdown(),
'markdown': markdown(),
// HTML
'html': html(),
'htm': html(),
// CSS
'css': css(),
'scss': css(),
'sass': css(),
'less': css(),
// SQL
'sql': sql(),
// YAML
'yml': yaml(),
'yaml': yaml(),
// Shell/Bash
'sh': StreamLanguage.define(shell),
'bash': StreamLanguage.define(shell),
'zsh': StreamLanguage.define(shell),
'fish': StreamLanguage.define(shell),
// Windows Batch/PowerShell
'bat': StreamLanguage.define(powerShell),
'cmd': StreamLanguage.define(powerShell),
'ps1': StreamLanguage.define(powerShell),
// 纯文本(未知类型)
text: ['txt', 'text', 'log', 'csv']
}
// ==================== Props & Emits ====================
const props = defineProps({
modelValue: {
type: String,
@@ -116,10 +101,15 @@ const props = defineProps({
const emit = defineEmits(['update:modelValue'])
// ==================== State ====================
const { isDark } = useTheme()
const editorContainer = ref(null)
let view = null
// 根据主题动态创建编辑器配置
// ==================== Editor Management ====================
/**
* 创建编辑器扩展配置
*/
const createExtensions = () => {
const extensions = [
lineNumbers(),
@@ -155,25 +145,131 @@ const createExtensions = () => {
})
]
// 根据主题添加 One Dark
// 主题
if (isDark.value) {
extensions.push(oneDark)
}
// 添加语言支持
const langSupport = LANGUAGE_MAP[props.fileExtension]
if (langSupport) {
extensions.push(langSupport)
// 语言支持
const ext = props.fileExtension.toLowerCase()
// JavaScript/TypeScript
if (LANGUAGE_MAP.javascript.includes(ext) || LANGUAGE_MAP.typescript.includes(ext)) {
extensions.push(javascript({ jsx: true }))
}
// JSON
else if (LANGUAGE_MAP.json.includes(ext)) {
extensions.push(json())
}
// YAML
else if (LANGUAGE_MAP.yaml.includes(ext)) {
extensions.push(yaml())
}
// HTML
else if (LANGUAGE_MAP.html.includes(ext)) {
extensions.push(html())
}
// CSS (including SCSS, SASS, LESS)
else if (LANGUAGE_MAP.css.includes(ext)) {
extensions.push(css())
}
// C/C++
else if (LANGUAGE_MAP.cpp.includes(ext)) {
extensions.push(cpp())
}
// Rust
else if (LANGUAGE_MAP.rust.includes(ext)) {
extensions.push(rust())
}
// Go
else if (LANGUAGE_MAP.go.includes(ext)) {
extensions.push(go())
}
// Python
else if (LANGUAGE_MAP.python.includes(ext)) {
extensions.push(python())
}
// PHP
else if (LANGUAGE_MAP.php.includes(ext)) {
extensions.push(php())
}
// SQL
else if (LANGUAGE_MAP.sql.includes(ext)) {
extensions.push(sql())
}
// Markdown
else if (LANGUAGE_MAP.markdown.includes(ext)) {
extensions.push(markdown())
}
// Java
else if (LANGUAGE_MAP.java.includes(ext)) {
extensions.push(java())
}
// Ruby
else if (LANGUAGE_MAP.ruby.includes(ext)) {
extensions.push(StreamLanguage.define(ruby))
}
// Shell
else if (LANGUAGE_MAP.shell.includes(ext)) {
extensions.push(StreamLanguage.define(shell))
}
// Kotlin
else if (LANGUAGE_MAP.kotlin.includes(ext)) {
extensions.push(StreamLanguage.define(kotlin))
}
// C#
else if (LANGUAGE_MAP.csharp.includes(ext)) {
extensions.push(StreamLanguage.define(csharp))
}
// Swift
else if (LANGUAGE_MAP.swift.includes(ext)) {
extensions.push(StreamLanguage.define(swift))
}
// R
else if (LANGUAGE_MAP.r.includes(ext)) {
extensions.push(StreamLanguage.define(r))
}
// Perl
else if (LANGUAGE_MAP.perl.includes(ext)) {
extensions.push(StreamLanguage.define(perl))
}
// LaTeX
else if (LANGUAGE_MAP.latex.includes(ext)) {
extensions.push(StreamLanguage.define(stex))
}
// Makefile (使用纯文本legacy-modes 没有专门的 makefile 支持)
else if (LANGUAGE_MAP.makefile.includes(ext)) {
// 纯文本模式,不添加语言扩展
}
// INI/Properties/Dockerfile
else if (LANGUAGE_MAP.ini.includes(ext)) {
extensions.push(StreamLanguage.define(properties))
}
else if (LANGUAGE_MAP.dockerfile.includes(ext)) {
extensions.push(StreamLanguage.define(dockerFile))
}
// XML (包括 SVG)
else if (LANGUAGE_MAP.xml.includes(ext)) {
extensions.push(StreamLanguage.define(xml))
}
// Matlab/Octave
else if (LANGUAGE_MAP.matlab.includes(ext)) {
extensions.push(StreamLanguage.define(octave))
}
// 其他类型(包括 gitignore, dockerfile, txt 等)使用纯文本模式
// 不添加任何语言扩展,保持纯文本
return extensions
}
onMounted(() => {
/**
* 创建编辑器实例
*/
const createEditor = (docContent = '') => {
if (!editorContainer.value) return
const state = EditorState.create({
doc: props.modelValue,
doc: docContent,
extensions: createExtensions()
})
@@ -181,49 +277,21 @@ onMounted(() => {
state,
parent: editorContainer.value
})
})
}
// 监听外部内容变化
watch(() => props.modelValue, (newValue) => {
if (view && newValue !== view.state.doc.toString()) {
view.dispatch({
changes: {
from: 0,
to: view.state.doc.length,
insert: newValue
}
})
}
})
/**
* 重建编辑器(保留内容)
*/
const recreateEditor = () => {
if (!view) return
const currentDoc = view.state.doc.toString()
view.destroy()
createEditor(currentDoc)
}
// 监听主题变化,重新创建编辑器
watch(isDark, () => {
if (view) {
view.destroy()
const state = EditorState.create({
doc: view.state.doc.toString(),
extensions: createExtensions()
})
view = new EditorView({
state,
parent: editorContainer.value
})
}
})
// 监听文件扩展名变化,重新创建编辑器
watch(() => props.fileExtension, () => {
if (view) {
view.destroy()
const state = EditorState.create({
doc: view.state.doc.toString(),
extensions: createExtensions()
})
view = new EditorView({
state,
parent: editorContainer.value
})
}
// ==================== Lifecycle ====================
onMounted(() => {
createEditor(props.modelValue || '')
})
onBeforeUnmount(() => {
@@ -231,80 +299,36 @@ onBeforeUnmount(() => {
view.destroy()
}
})
// ==================== Watchers ====================
// 监听外部内容变化
watch(() => props.modelValue, (newValue) => {
if (view && newValue !== view.state.doc.toString()) {
view.dispatch({
changes: {
from: 0,
to: view.state.doc.length,
insert: newValue || ''
}
})
}
})
// 监听主题或文件扩展名变化,重建编辑器
watch([isDark, () => props.fileExtension], recreateEditor)
</script>
<style>
/* 全局语法高亮样式(适用于亮色主题) */
.cm-editor:not(.cm-theme-dark) .tok-keyword {
color: #d73a49;
font-weight: bold;
}
.cm-editor:not(.cm-theme-dark) .tok-string {
color: #032f62;
}
.cm-editor:not(.cm-theme-dark) .tok-number {
color: #005cc5;
}
.cm-editor:not(.cm-theme-dark) .tok-comment {
color: #6a737d;
font-style: italic;
}
.cm-editor:not(.cm-theme-dark) .tok-function {
color: #6f42c1;
}
.cm-editor:not(.cm-theme-dark) .tok-operator {
color: #d73a49;
}
.cm-editor:not(.cm-theme-dark) .tok-class-name {
color: #22863a;
}
.cm-editor:not(.cm-theme-dark) .tok-property {
color: #e36209;
}
.cm-editor:not(.cm-theme-dark) .tok-tag {
color: #22863a;
}
.cm-editor:not(.cm-theme-dark) .tok-attribute {
color: #6f42c1;
}
.cm-editor:not(.cm-theme-dark) .tok-variableName {
color: #e36209;
}
.cm-editor:not(.cm-theme-dark) .tok-variableName2 {
color: #005cc5;
}
.cm-editor:not(.cm-theme-dark) .tok-def {
color: #6f42c1;
}
</style>
<style scoped>
.codemirror-editor {
height: 100%;
overflow: hidden;
}
:deep(.cm-editor) {
.codemirror-editor :deep(.cm-editor) {
height: 100%;
}
:deep(.cm-scroller) {
.codemirror-editor :deep(.cm-scroller) {
overflow: auto;
}
:deep(.cm-content) {
padding: 8px;
}
</style>