2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-04 03:07:20 +08:00

修复文件编辑器状态栏功能问题 (#1274)

* Initial plan

* 修复文件编辑器语言切换高亮和JSON文件识别问题

Co-authored-by: devhaozi <115467771+devhaozi@users.noreply.github.com>

* 修复行分隔符切换不生效问题

Co-authored-by: devhaozi <115467771+devhaozi@users.noreply.github.com>

* 移除编码切换功能(需要后端支持,范围较大)

Co-authored-by: devhaozi <115467771+devhaozi@users.noreply.github.com>

* 修复行分隔符切换的竞态条件和冗余操作

Co-authored-by: devhaozi <115467771+devhaozi@users.noreply.github.com>

* fix: 编辑器问题

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: devhaozi <115467771+devhaozi@users.noreply.github.com>
Co-authored-by: 耗子 <haozi@loli.email>
This commit is contained in:
Copilot
2026-01-24 05:18:29 +08:00
committed by GitHub
parent acc661050b
commit c70f7d6a79
6 changed files with 59 additions and 54 deletions

View File

@@ -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))
}
)

View File

@@ -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) {
</div>
</n-popselect>
<!-- 编码 -->
<n-popselect
:value="editorStore.activeTab.encoding"
:options="encodings.map((e) => ({ label: e.toUpperCase(), value: e }))"
@update:value="handleEncodingChange"
scrollable
>
<div class="status-item clickable">
{{ $gettext('Encoding') }}: {{ editorStore.activeTab.encoding }}
</div>
</n-popselect>
<!-- 语言 -->
<n-popselect
:value="editorStore.activeTab.language"

View File

@@ -142,7 +142,7 @@ function handleSelect(keys: string[], option: (TreeOption | null)[]) {
editorStore.switchTab(path)
} else {
// 加载文件内容
editorStore.openFile(path, '', 'utf-8')
editorStore.openFile(path, '')
editorStore.setLoading(path, true)
useRequest(file.content(encodeURIComponent(path)))
.onSuccess(({ data }) => {
@@ -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)
}

View File

@@ -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(/(?<!\r)\n/g, '\r\n')
} else {
tab.content = tab.content.replace(/\r\n/g, '\n')
}
tab.modified = tab.content !== tab.originalContent
}
},
// 更新编码
updateEncoding(path: string, encoding: string) {
const tab = this.tabs.find((t) => t.path === path)
if (tab) {
tab.encoding = encoding
}
},

View File

@@ -286,6 +286,8 @@ const languageByPath = (path: string) => {
case 'yaml':
case 'yml': // yaml 扩展名
return 'yaml'
case 'json':
return 'json'
default:
return 'plaintext'
}

View File

@@ -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)))