Files
MarkLite/src/main/file-watcher.ts
T
thzxx 899d2b7914 v0.3.4: Bug修复+性能优化+文档大纲功能
🔴 Bug修复 (6):
- Sidebar反斜杠正则修复 (Windows路径规范化)
- FileWatcher文件删除后自动恢复监听
- SearchReplace replaceAll防过期匹配位置
- openFolderDialog null结果守卫
- 保存异常时空路径保护
- Markdown绝对路径图片拼接修复

🟡 性能优化:
- Editor切换标签时内容比较,相同跳过replaceAll

🔵 代码质量:
- 创建共享常量模块 src/shared/constants.ts,消除双副本

🎯 新增功能:
- 文档大纲 (Table of Contents) — 侧边栏标题导航

🔧 换行符统一: CRLF → LF
2026-06-04 13:24:23 +08:00

116 lines
3.0 KiB
TypeScript

import * as fs from 'fs'
import { BrowserWindow } from 'electron'
export class FileWatcher {
private watcher: fs.FSWatcher | null = null
private currentPath: string | null = null
private isSelfWriting = false
constructor(private getMainWindow: () => BrowserWindow | null) {}
start(filePath: string): void {
this.stop()
if (!filePath) return
try {
this.currentPath = filePath
this.watcher = fs.watch(filePath, (eventType) => {
if (eventType === 'change') {
if (this.isSelfWriting) return
const win = this.getMainWindow()
if (win && !win.isDestroyed()) {
win.webContents.send('file:externallyModified', filePath)
}
}
})
// L-02: 监听 error 事件,文件被删除时显式关闭并清理状态
this.watcher.on('error', () => {
this.stop()
const originalPath = this.currentPath
if (originalPath) {
const pollInterval = setInterval(() => {
try {
if (fs.existsSync(originalPath)) {
clearInterval(pollInterval)
this.start(originalPath)
}
} catch {
clearInterval(pollInterval)
}
}, 2000)
// 最多轮询30秒
setTimeout(() => clearInterval(pollInterval), 30000)
}
})
} catch {
// silently ignore
}
}
stop(): void {
if (this.watcher) {
this.watcher.close()
this.watcher = null
}
this.currentPath = null
}
getCurrentPath(): string | null {
return this.currentPath
}
setSelfWriting(value: boolean): void {
this.isSelfWriting = value
}
}
export class SidebarWatcher {
private watcher: fs.FSWatcher | null = null
private watchPath: string | null = null
private refreshTimer: NodeJS.Timeout | null = null
constructor(private getMainWindow: () => BrowserWindow | null) {}
start(dirPath: string): void {
this.stop()
if (!dirPath) return
try {
this.watchPath = dirPath
this.watcher = fs.watch(dirPath, { recursive: true }, () => {
const win = this.getMainWindow()
if (win && !win.isDestroyed()) {
if (this.refreshTimer) clearTimeout(this.refreshTimer)
this.refreshTimer = setTimeout(() => {
// M-03: 延迟后再次检查窗口状态
const w = this.getMainWindow()
if (w && !w.isDestroyed()) {
w.webContents.send('sidebar:dirChanged')
}
}, 300)
}
})
// L-02: 监听 error 事件,显式关闭
this.watcher.on('error', () => {
if (this.watcher) {
this.watcher.close()
this.watcher = null
}
this.watchPath = null
})
} catch {
// silently ignore
}
}
stop(): void {
if (this.watcher) {
this.watcher.close()
this.watcher = null
}
if (this.refreshTimer) {
clearTimeout(this.refreshTimer)
this.refreshTimer = null
}
this.watchPath = null
}
}