diff --git a/src/utils/pulledVaultRefresh.test.ts b/src/utils/pulledVaultRefresh.test.ts index 787b430e..76527d5c 100644 --- a/src/utils/pulledVaultRefresh.test.ts +++ b/src/utils/pulledVaultRefresh.test.ts @@ -92,17 +92,29 @@ describe('refreshPulledVaultState', () => { expect(options.closeAllTabs).not.toHaveBeenCalled() }) - it('refreshes the focused active tab when an external watcher update changed that note', async () => { + it('keeps the active tab mounted while focused when an external watcher update changed that note', async () => { const options = makeOptions({ shouldKeepActiveEditorMounted: vi.fn(() => true), }) await refreshPulledVaultState(options) - expect(options.shouldKeepActiveEditorMounted).not.toHaveBeenCalled() + expect(options.shouldKeepActiveEditorMounted).toHaveBeenCalledOnce() expect(options.reloadVault).toHaveBeenCalledOnce() expect(options.reloadFolders).toHaveBeenCalledOnce() expect(options.reloadViews).toHaveBeenCalledOnce() + expect(options.closeAllTabs).not.toHaveBeenCalled() + expect(options.replaceActiveTab).not.toHaveBeenCalled() + }) + + it('refreshes the active tab when focus is outside the editor', async () => { + const options = makeOptions({ + shouldKeepActiveEditorMounted: vi.fn(() => false), + }) + + await refreshPulledVaultState(options) + + expect(options.shouldKeepActiveEditorMounted).toHaveBeenCalledOnce() expect(options.closeAllTabs).toHaveBeenCalledOnce() expect(options.replaceActiveTab).toHaveBeenCalledWith(makeEntry('/vault/active.md', 'Active')) }) diff --git a/src/utils/pulledVaultRefresh.ts b/src/utils/pulledVaultRefresh.ts index 385220bf..79e025bc 100644 --- a/src/utils/pulledVaultRefresh.ts +++ b/src/utils/pulledVaultRefresh.ts @@ -86,6 +86,39 @@ function shouldReplaceActiveEntry(options: { return didPullUpdateActiveNote({ updatedFiles, vaultPath, activeTabPath: activePath }) } +function shouldPreserveFocusedActiveEntry(options: { + movedEntry: VaultEntry | null + shouldKeepActiveEditorMounted?: () => boolean +}): boolean { + const { movedEntry, shouldKeepActiveEditorMounted } = options + if (movedEntry || !shouldKeepActiveEditorMounted) return false + return shouldKeepActiveEditorMounted() +} + +async function applyActiveEntryReplacement(options: { + closeAllTabs: PulledVaultRefreshOptions['closeAllTabs'] + movedEntry: VaultEntry | null + replaceActiveTab: PulledVaultRefreshOptions['replaceActiveTab'] + replacementEntry: VaultEntry | null + shouldKeepActiveEditorMounted?: PulledVaultRefreshOptions['shouldKeepActiveEditorMounted'] + shouldReplace: boolean | null +}): Promise { + const { + closeAllTabs, + movedEntry, + replaceActiveTab, + replacementEntry, + shouldKeepActiveEditorMounted, + shouldReplace, + } = options + if (!replacementEntry || !shouldReplace) return false + if (shouldPreserveFocusedActiveEntry({ movedEntry, shouldKeepActiveEditorMounted })) return true + + closeAllTabs() + await replaceActiveTab(replacementEntry) + return true +} + export function getPulledVaultUpdateOptions(): { preserveFocusedEditor: true } { return { preserveFocusedEditor: true } } @@ -100,6 +133,7 @@ export async function refreshPulledVaultState(options: PulledVaultRefreshOptions reloadVault, reloadViews, replaceActiveTab, + shouldKeepActiveEditorMounted, updatedFiles, vaultPath, } = options @@ -123,17 +157,23 @@ export async function refreshPulledVaultState(options: PulledVaultRefreshOptions }) const replacementEntry = refreshedEntry ?? movedEntry - if (replacementEntry && shouldReplaceActiveEntry({ + const shouldReplace = replacementEntry && shouldReplaceActiveEntry({ activePath, movedEntry, refreshedEntry, updatedFiles, vaultPath, - })) { - closeAllTabs() - await replaceActiveTab(replacementEntry) - return entries - } + }) + + const handledReplacement = await applyActiveEntryReplacement({ + closeAllTabs, + movedEntry, + replaceActiveTab, + replacementEntry, + shouldKeepActiveEditorMounted, + shouldReplace, + }) + if (handledReplacement) return entries if (!replacementEntry) closeAllTabs() return entries