Browse Source

fix(app): update tab file contents on change

Adam 2 weeks ago
parent
commit
30f0d3b394

+ 4 - 0
packages/app/src/context/file.tsx

@@ -7,6 +7,7 @@ import { getFilename } from "@opencode-ai/util/path"
 import { useSDK } from "./sdk"
 import { useSDK } from "./sdk"
 import { useSync } from "./sync"
 import { useSync } from "./sync"
 import { useLanguage } from "@/context/language"
 import { useLanguage } from "@/context/language"
+import { useLayout } from "@/context/layout"
 import { createPathHelpers } from "./file/path"
 import { createPathHelpers } from "./file/path"
 import {
 import {
   approxBytes,
   approxBytes,
@@ -50,9 +51,11 @@ export const { use: useFile, provider: FileProvider } = createSimpleContext({
     useSync()
     useSync()
     const params = useParams()
     const params = useParams()
     const language = useLanguage()
     const language = useLanguage()
+    const layout = useLayout()
 
 
     const scope = createMemo(() => sdk.directory)
     const scope = createMemo(() => sdk.directory)
     const path = createPathHelpers(scope)
     const path = createPathHelpers(scope)
+    const tabs = layout.tabs(() => `${params.dir}${params.id ? "/" + params.id : ""}`)
 
 
     const inflight = new Map<string, Promise<void>>()
     const inflight = new Map<string, Promise<void>>()
     const [store, setStore] = createStore<{
     const [store, setStore] = createStore<{
@@ -183,6 +186,7 @@ export const { use: useFile, provider: FileProvider } = createSimpleContext({
       invalidateFromWatcher(e.details, {
       invalidateFromWatcher(e.details, {
         normalize: path.normalize,
         normalize: path.normalize,
         hasFile: (file) => Boolean(store.file[file]),
         hasFile: (file) => Boolean(store.file[file]),
+        isOpen: (file) => tabs.all().some((tab) => path.pathFromTab(tab) === file),
         loadFile: (file) => {
         loadFile: (file) => {
           void load(file, { force: true })
           void load(file, { force: true })
         },
         },

+ 31 - 0
packages/app/src/context/file/watcher.test.ts

@@ -27,6 +27,37 @@ describe("file watcher invalidation", () => {
     expect(refresh).toEqual(["src"])
     expect(refresh).toEqual(["src"])
   })
   })
 
 
+  test("reloads files that are open in tabs", () => {
+    const loads: string[] = []
+
+    invalidateFromWatcher(
+      {
+        type: "file.watcher.updated",
+        properties: {
+          file: "src/open.ts",
+          event: "change",
+        },
+      },
+      {
+        normalize: (input) => input,
+        hasFile: () => false,
+        isOpen: (path) => path === "src/open.ts",
+        loadFile: (path) => loads.push(path),
+        node: () => ({
+          path: "src/open.ts",
+          type: "file",
+          name: "open.ts",
+          absolute: "/repo/src/open.ts",
+          ignored: false,
+        }),
+        isDirLoaded: () => false,
+        refreshDir: () => {},
+      },
+    )
+
+    expect(loads).toEqual(["src/open.ts"])
+  })
+
   test("refreshes only changed loaded directory nodes", () => {
   test("refreshes only changed loaded directory nodes", () => {
     const refresh: string[] = []
     const refresh: string[] = []
 
 

+ 2 - 1
packages/app/src/context/file/watcher.ts

@@ -8,6 +8,7 @@ type WatcherEvent = {
 type WatcherOps = {
 type WatcherOps = {
   normalize: (input: string) => string
   normalize: (input: string) => string
   hasFile: (path: string) => boolean
   hasFile: (path: string) => boolean
+  isOpen?: (path: string) => boolean
   loadFile: (path: string) => void
   loadFile: (path: string) => void
   node: (path: string) => FileNode | undefined
   node: (path: string) => FileNode | undefined
   isDirLoaded: (path: string) => boolean
   isDirLoaded: (path: string) => boolean
@@ -27,7 +28,7 @@ export function invalidateFromWatcher(event: WatcherEvent, ops: WatcherOps) {
   if (!path) return
   if (!path) return
   if (path.startsWith(".git/")) return
   if (path.startsWith(".git/")) return
 
 
-  if (ops.hasFile(path)) {
+  if (ops.hasFile(path) || ops.isOpen?.(path)) {
     ops.loadFile(path)
     ops.loadFile(path)
   }
   }