summaryrefslogtreecommitdiffhomepage
path: root/packages
diff options
context:
space:
mode:
authorAdam <[email protected]>2026-02-09 07:22:40 -0600
committerAdam <[email protected]>2026-02-09 07:38:06 -0600
commit30f0d3b3941f5c01826e9903cc4ebcb791704dec (patch)
tree5b7ca5e1e9cf81cd8a9ffd9939f07bb02f5f366c /packages
parent03f3029dc697f520a0e154c31f8188743113deb4 (diff)
downloadopencode-30f0d3b3941f5c01826e9903cc4ebcb791704dec.tar.gz
opencode-30f0d3b3941f5c01826e9903cc4ebcb791704dec.zip
fix(app): update tab file contents on change
Diffstat (limited to 'packages')
-rw-r--r--packages/app/src/context/file.tsx4
-rw-r--r--packages/app/src/context/file/watcher.test.ts31
-rw-r--r--packages/app/src/context/file/watcher.ts3
3 files changed, 37 insertions, 1 deletions
diff --git a/packages/app/src/context/file.tsx b/packages/app/src/context/file.tsx
index 996ea2aaf..88b70cd41 100644
--- a/packages/app/src/context/file.tsx
+++ b/packages/app/src/context/file.tsx
@@ -7,6 +7,7 @@ import { getFilename } from "@opencode-ai/util/path"
import { useSDK } from "./sdk"
import { useSync } from "./sync"
import { useLanguage } from "@/context/language"
+import { useLayout } from "@/context/layout"
import { createPathHelpers } from "./file/path"
import {
approxBytes,
@@ -50,9 +51,11 @@ export const { use: useFile, provider: FileProvider } = createSimpleContext({
useSync()
const params = useParams()
const language = useLanguage()
+ const layout = useLayout()
const scope = createMemo(() => sdk.directory)
const path = createPathHelpers(scope)
+ const tabs = layout.tabs(() => `${params.dir}${params.id ? "/" + params.id : ""}`)
const inflight = new Map<string, Promise<void>>()
const [store, setStore] = createStore<{
@@ -183,6 +186,7 @@ export const { use: useFile, provider: FileProvider } = createSimpleContext({
invalidateFromWatcher(e.details, {
normalize: path.normalize,
hasFile: (file) => Boolean(store.file[file]),
+ isOpen: (file) => tabs.all().some((tab) => path.pathFromTab(tab) === file),
loadFile: (file) => {
void load(file, { force: true })
},
diff --git a/packages/app/src/context/file/watcher.test.ts b/packages/app/src/context/file/watcher.test.ts
index 653e0aa75..9536b5253 100644
--- a/packages/app/src/context/file/watcher.test.ts
+++ b/packages/app/src/context/file/watcher.test.ts
@@ -27,6 +27,37 @@ describe("file watcher invalidation", () => {
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", () => {
const refresh: string[] = []
diff --git a/packages/app/src/context/file/watcher.ts b/packages/app/src/context/file/watcher.ts
index a3a98eae4..fbf719927 100644
--- a/packages/app/src/context/file/watcher.ts
+++ b/packages/app/src/context/file/watcher.ts
@@ -8,6 +8,7 @@ type WatcherEvent = {
type WatcherOps = {
normalize: (input: string) => string
hasFile: (path: string) => boolean
+ isOpen?: (path: string) => boolean
loadFile: (path: string) => void
node: (path: string) => FileNode | undefined
isDirLoaded: (path: string) => boolean
@@ -27,7 +28,7 @@ export function invalidateFromWatcher(event: WatcherEvent, ops: WatcherOps) {
if (!path) return
if (path.startsWith(".git/")) return
- if (ops.hasFile(path)) {
+ if (ops.hasFile(path) || ops.isOpen?.(path)) {
ops.loadFile(path)
}