diff --git a/src/main/ipc-handlers.ts b/src/main/ipc-handlers.ts
index 5d1cfa6..a0e3265 100644
--- a/src/main/ipc-handlers.ts
+++ b/src/main/ipc-handlers.ts
@@ -69,13 +69,11 @@ export function registerIpcHandlers(
fileWatcher.stop()
fileWatcher.setSelfWriting(true)
const result = await saveFileContent(data.filePath, data.content)
+ // start watcher while selfWriting is still true so any immediate 'change'
+ // event from the restart is suppressed — prevents overwriting editor content
+ fileWatcher.start(data.filePath)
fileWatcher.setSelfWriting(false)
state.activeFilePath = data.filePath
- setTimeout(() => {
- if (state.activeFilePath === data.filePath && data.filePath) {
- fileWatcher.start(data.filePath)
- }
- }, 300)
if (win && !win.isDestroyed()) {
win.setTitle(`MarkLite - ${basename(data.filePath)}`)
}
@@ -88,12 +86,12 @@ export function registerIpcHandlers(
if (!saveResult.canceled) {
fileWatcher.setSelfWriting(true)
const result = await saveFileContent(saveResult.filePath, data.content)
- fileWatcher.setSelfWriting(false)
if (result.success) {
state.activeFilePath = saveResult.filePath
fileWatcher.start(saveResult.filePath)
win.setTitle(`MarkLite - ${basename(saveResult.filePath)}`)
}
+ fileWatcher.setSelfWriting(false)
return result
}
return { success: false, canceled: true }
@@ -116,19 +114,14 @@ export function registerIpcHandlers(
filters: [{ name: 'Markdown 文件', extensions: ['md'] }]
})
if (!result.canceled) {
- fileWatcher.stop()
fileWatcher.setSelfWriting(true)
const saveResult = await saveFileContent(result.filePath, data.content)
- fileWatcher.setSelfWriting(false)
if (saveResult.success) {
state.activeFilePath = result.filePath
- setTimeout(() => {
- if (state.activeFilePath === result.filePath) {
- fileWatcher.start(result.filePath)
- }
- }, 300)
+ fileWatcher.start(result.filePath)
win.setTitle(`MarkLite - ${basename(result.filePath)}`)
}
+ fileWatcher.setSelfWriting(false)
return saveResult
}
return { success: false, canceled: true }
diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx
index 893fee0..bb9ced8 100644
--- a/src/renderer/App.tsx
+++ b/src/renderer/App.tsx
@@ -16,6 +16,7 @@ import { useConfirm } from './hooks/useConfirm'
import { Toolbar } from './components/Toolbar/Toolbar'
import { TabBar } from './components/TabBar/TabBar'
import { Editor } from './components/Editor/Editor'
+import { SourceEditor } from './components/SourceEditor/SourceEditor'
import { Preview } from './components/Preview/Preview'
import { Sidebar } from './components/Sidebar/Sidebar'
import { StatusBar } from './components/StatusBar/StatusBar'
@@ -75,10 +76,16 @@ export function App() {
const handleReloadModified = useCallback(async () => {
if (!externallyModified?.filePath || !window.electronAPI) return
+ const tab = tabs.find(t => t.filePath === externallyModified.filePath)
+ // BUG-10: Don't overwrite editor content the user has modified since the last save.
+ // The watcher restart after save can trigger a false 'change' event, and re-reading
+ // the file at that point would replace newer editor content with the just-saved content.
+ if (tab?.isModified) return
+ if (!tab) return
const result = await window.electronAPI.readFile(externallyModified.filePath)
if (result.success && result.content !== undefined) {
- const tab = tabs.find(t => t.filePath === externallyModified.filePath)
- if (tab) { updateTabContent(tab.id, result.content); setModified(tab.id, false) }
+ updateTabContent(tab.id, result.content)
+ setModified(tab.id, false)
}
setExternallyModified(null)
}, [externallyModified, tabs, updateTabContent, setModified, setExternallyModified])
@@ -102,6 +109,7 @@ export function App() {
{tabs.length > 0 ? (
{viewMode === 'editor' &&
}
+ {viewMode === 'source' &&
}
{viewMode === 'preview' &&
}
) : (
diff --git a/src/renderer/components/Icons.tsx b/src/renderer/components/Icons.tsx
index 53e28af..7149de4 100644
--- a/src/renderer/components/Icons.tsx
+++ b/src/renderer/components/Icons.tsx
@@ -78,6 +78,15 @@ export function PreviewMode({ size = defaultProps.size }: IconProps) {
)
}
+export function SourceMode({ size = defaultProps.size }: IconProps) {
+ return (
+
+ )
+}
+
export function Moon({ size = defaultProps.size }: IconProps) {
return (