fix(watcher): filter ignored paths before publishing events, handle worktree git dirs
The parcel/watcher callback was shared and published all filesystem events
without re-filtering through FileIgnore. Build artifacts and lock files in
ignored directories (out/, .turbo/, etc.) fired watcher events that drove
repeated refreshVcs() calls and made the review panel flicker.
Also fixes the frontend listener to handle absolute .git/worktrees/... paths
produced by git worktrees, which bypassed the old startsWith('.git/') check.
Fixes #21452
pull/21453/head
parent
ae614d919f
commit
036a100f2a
|
|
@ -931,7 +931,11 @@ export default function Page() {
|
|||
? (evt.details.properties as Record<string, unknown>)
|
||||
: undefined
|
||||
const file = typeof props?.file === "string" ? props.file : undefined
|
||||
if (!file || file.startsWith(".git/")) return
|
||||
if (!file) return
|
||||
const path = file.replaceAll("\\", "/")
|
||||
// Worktree watcher events can arrive as absolute .git/worktrees/... paths.
|
||||
const git = path.startsWith(".git/") || path.includes("/.git/")
|
||||
if (git) return
|
||||
refreshVcs()
|
||||
})
|
||||
onCleanup(stopVcs)
|
||||
|
|
|
|||
|
|
@ -59,6 +59,13 @@ export namespace FileWatcher {
|
|||
})
|
||||
}
|
||||
|
||||
function rel(dir: string, file: string) {
|
||||
const next = path.relative(dir, file).replaceAll("\\", "/")
|
||||
if (path.isAbsolute(next)) return
|
||||
if (next === ".." || next.startsWith("../")) return
|
||||
return next
|
||||
}
|
||||
|
||||
export const hasNativeBinding = () => !!watcher()
|
||||
|
||||
export interface Interface {
|
||||
|
|
@ -95,16 +102,24 @@ export namespace FileWatcher {
|
|||
Effect.promise(() => Promise.allSettled(subs.map((sub) => sub.unsubscribe()))),
|
||||
)
|
||||
|
||||
const cb: ParcelWatcher.SubscribeCallback = Instance.bind((err, evts) => {
|
||||
if (err) return
|
||||
for (const evt of evts) {
|
||||
if (evt.type === "create") Bus.publish(Event.Updated, { file: evt.path, event: "add" })
|
||||
if (evt.type === "update") Bus.publish(Event.Updated, { file: evt.path, event: "change" })
|
||||
if (evt.type === "delete") Bus.publish(Event.Updated, { file: evt.path, event: "unlink" })
|
||||
}
|
||||
})
|
||||
const subscribe = (dir: string, ignore: string[], git = false) => {
|
||||
const cb: ParcelWatcher.SubscribeCallback = Instance.bind((err, evts) => {
|
||||
if (err) return
|
||||
for (const evt of evts) {
|
||||
const file = rel(dir, evt.path)
|
||||
if (file === undefined) continue
|
||||
if (git) {
|
||||
if (file !== "HEAD") continue
|
||||
} else if (FileIgnore.match(file, { extra: cfgIgnores })) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (evt.type === "create") Bus.publish(Event.Updated, { file: evt.path, event: "add" })
|
||||
if (evt.type === "update") Bus.publish(Event.Updated, { file: evt.path, event: "change" })
|
||||
if (evt.type === "delete") Bus.publish(Event.Updated, { file: evt.path, event: "unlink" })
|
||||
}
|
||||
})
|
||||
|
||||
const subscribe = (dir: string, ignore: string[]) => {
|
||||
const pending = w.subscribe(dir, cb, { ignore, backend })
|
||||
return Effect.gen(function* () {
|
||||
const sub = yield* Effect.promise(() => pending)
|
||||
|
|
@ -142,7 +157,7 @@ export namespace FileWatcher {
|
|||
const ignore = (yield* Effect.promise(() => readdir(vcsDir).catch(() => []))).filter(
|
||||
(entry) => entry !== "HEAD",
|
||||
)
|
||||
yield* subscribe(vcsDir, ignore)
|
||||
yield* subscribe(vcsDir, ignore, true)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in New Issue