v0.3.5: Bug修复+性能优化+状态栏文档统计

Bug修复:
- BUG-01: Sidebar norm函数正则修复(单反斜杠匹配), Windows路径规范化恢复
- BUG-02: 3处result.content truthy检查改为content !== undefined, 空文件可打开
- BUG-03: TAB_SWITCHED路径校验顺序修复, activeFilePath不在校验前写入

优化:
- OPT-01: Sidebar handleFileClick添加loading状态, 打开文件有视觉反馈

新功能:
- FEAT-01: 状态栏添加行数/单词数/字符数统计
  - useDocStats hook + computeDocStats 纯函数
  - StatusBar右侧显示 行/词/字符 统计信息
  - 12个单元测试覆盖空值/空白/ASCII/UTF-8/Markdown等场景

验证: TS 0错误, ESLint 0错误(1个预存警告), 90/90测试通过
This commit is contained in:
thzxx
2026-06-04 13:43:10 +08:00
parent 899d2b7914
commit a84ccb7353
9 changed files with 157 additions and 13 deletions
+12 -6
View File
@@ -9,7 +9,7 @@ import { useSidebarResize } from '../../hooks/useSidebarResize'
import { useFolderOperations } from '../../hooks/useFolderOperations'
import { useAutoExpandDir } from '../../hooks/useAutoExpandDir'
import { OutlinePanel, parseHeadings } from '../OutlinePanel'
import { getEditorView } from '../../stores/editorStore'
import { getEditorView, useEditorStore } from '../../stores/editorStore'
import { TextSelection } from '@milkdown/prose/state'
const norm = (p: string) => p.replace(/\\/g, '/')
@@ -29,6 +29,7 @@ export const Sidebar = React.memo(function Sidebar() {
const activeFilePath = activeTab?.filePath ?? null
const { sidebarRef, startResize } = useSidebarResize()
const { handleOpenFolder } = useFolderOperations()
const setLoading = useEditorStore(s => s.setLoading)
useAutoExpandDir(activeFilePath)
// Parse headings from active tab content
@@ -56,12 +57,17 @@ export const Sidebar = React.memo(function Sidebar() {
const existing = tabs.find(t => t.filePath === path)
if (existing) { switchToTab(existing.id); return }
if (!window.electronAPI) return
const result = await window.electronAPI.readFile(path)
if (result.success && result.content) {
createTab(path, result.content)
recentFilesRepository.add(path)
setLoading('file-open', true)
try {
const result = await window.electronAPI.readFile(path)
if (result.success && result.content !== undefined) {
createTab(path, result.content)
recentFilesRepository.add(path)
}
} finally {
setLoading('file-open', false)
}
}, [tabs, switchToTab, createTab])
}, [tabs, switchToTab, createTab, setLoading])
const independentFiles = tabs.filter(t => {
if (!t.filePath) return false