import { useEffect, useRef, useState, useCallback } from 'react' import { useTabStore } from '../stores/tabStore' import { useAutoSaveStore } from '../stores/autoSaveStore' import { logError } from '../lib/errorHandler' /** Debounce delay for auto-save (ms) */ const AUTO_SAVE_DELAY = 2000 /** 模块级 ref — 状态栏等外部组件通过此函数切换自动保存 */ let _toggleAutoSave: (() => void) | null = null export function toggleAutoSaveExternal(): void { _toggleAutoSave?.() } /** * Auto-save hook: subscribes to Zustand tab store, debounces content changes * and saves automatically after a pause in editing for file-backed tabs. * * Uses `useTabStore.getState()` and `.subscribe()` so it doesn't need to * re-render on every keystroke — the effect is triggered once and runs * reactively via the store subscription. * * Captures the tabId at debounce start so the timeout always saves the * correct tab even if the user switches tabs during the debounce window. */ export function useAutoSave(): { isAutoSaving: boolean; autoSaveEnabled: boolean; toggleAutoSave: () => void } { const [isAutoSaving, setIsAutoSaving] = useState(false) const [autoSaveEnabled, setAutoSaveEnabled] = useState(true) const timerRef = useRef | null>(null) const isSavingRef = useRef(false) const enabledRef = useRef(true) const mountedRef = useRef(true) const toggleAutoSave = useCallback(() => { setAutoSaveEnabled(prev => { const next = !prev enabledRef.current = next if (!next && timerRef.current) { clearTimeout(timerRef.current) timerRef.current = null } return next }) }, []) // 暴露给外部(状态栏按钮) _toggleAutoSave = toggleAutoSave useEffect(() => { mountedRef.current = true // Subscribe to Zustand store — fires on every state change const unsub = useTabStore.subscribe((state) => { if (!enabledRef.current) return const tab = state.getActiveTab() if (!tab || !tab.filePath || !tab.isModified) return // Capture the tabId so the timeout saves the correct tab const tabIdToSave = tab.id // Debounce: clear previous timer, start new one if (timerRef.current) { clearTimeout(timerRef.current) } timerRef.current = setTimeout(async () => { if (isSavingRef.current) return // Re-read latest state; verify the captured tab still exists and is modified const currentState = useTabStore.getState() const tabToSave = currentState.tabs.find(t => t.id === tabIdToSave) if (!tabToSave || !tabToSave.filePath || !tabToSave.isModified) return isSavingRef.current = true if (mountedRef.current) setIsAutoSaving(true) try { if (!window.electronAPI) return const result = await window.electronAPI.saveFile({ filePath: tabToSave.filePath, content: tabToSave.content }) if (result.success && mountedRef.current) { currentState.setModified(tabToSave.id, false) } } catch (error) { logError('自动保存失败', error) } finally { if (mountedRef.current) setIsAutoSaving(false) isSavingRef.current = false } }, AUTO_SAVE_DELAY) }) return () => { mountedRef.current = false unsub() if (timerRef.current) { clearTimeout(timerRef.current) timerRef.current = null } } }, []) // 同步 autoSaveEnabled / isAutoSaving 到 autoSaveStore(供状态栏读取) useEffect(() => { useAutoSaveStore.getState().setState({ autoSaveEnabled }) }, [autoSaveEnabled]) useEffect(() => { useAutoSaveStore.getState().setState({ isAutoSaving }) }, [isAutoSaving]) return { isAutoSaving, autoSaveEnabled, toggleAutoSave } }