Bläddra i källkod

refactor: use Effect debounce for LSP cleanup

Kit Langton 5 dagar sedan
förälder
incheckning
06c6babb1b
1 ändrade filer med 16 tillägg och 14 borttagningar
  1. 16 14
      packages/opencode/src/lsp/index.ts

+ 16 - 14
packages/opencode/src/lsp/index.ts

@@ -12,7 +12,7 @@ import { Instance } from "../project/instance"
 import { Flag } from "@/flag/flag"
 import { Process } from "../util/process"
 import { spawn as lspspawn } from "./launch"
-import { Effect, Layer, Context } from "effect"
+import { Effect, Layer, Context, PubSub, Stream } from "effect"
 import { InstanceState } from "@/effect/instance-state"
 import { Filesystem } from "@/util/filesystem"
 
@@ -139,10 +139,10 @@ export namespace LSP {
     clients: LSPClient.Info[]
     servers: Record<string, LSPServer.Info>
     broken: Set<string>
+    pulse: PubSub.PubSub<void>
     pruning: Promise<void> | undefined
     spawning: Map<string, Promise<LSPClient.Info | undefined>>
     subs: Map<string, { sub: FSWatcher; names: Set<string> }>
-    timer: ReturnType<typeof setTimeout> | undefined
   }
 
   export interface Interface {
@@ -217,19 +217,25 @@ export namespace LSP {
             clients: [],
             servers,
             broken: new Set(),
+            pulse: yield* PubSub.unbounded<void>(),
             pruning: undefined,
             spawning: new Map(),
             subs: new Map(),
-            timer: undefined,
           }
 
+          yield* Stream.fromPubSub(s.pulse).pipe(
+            Stream.debounce("50 millis"),
+            Stream.runForEach(() => Effect.promise(() => scan(s))),
+            Effect.forkScoped,
+          )
+
           yield* Effect.addFinalizer(() =>
-            Effect.promise(async () => {
-              if (s.timer) clearTimeout(s.timer)
+            Effect.gen(function* () {
+              yield* PubSub.shutdown(s.pulse).pipe(Effect.ignore)
               for (const item of s.subs.values()) {
                 item.sub.close()
               }
-              await Promise.all(s.clients.map((client) => client.shutdown()))
+              yield* Effect.promise(() => Promise.all(s.clients.map((client) => client.shutdown())))
             }),
           )
 
@@ -363,7 +369,7 @@ export namespace LSP {
                   const name = String(file)
                   if (!s.subs.get(dir)?.names.has(name)) return
                 }
-                kick(s)
+                fire(s)
               }),
             )
             sub.on(
@@ -372,7 +378,7 @@ export namespace LSP {
                 if (s.subs.get(dir)?.sub !== sub) return
                 s.subs.delete(dir)
                 sub.close()
-                kick(s)
+                fire(s)
               }),
             )
             s.subs.set(dir, { sub, names })
@@ -380,12 +386,8 @@ export namespace LSP {
         }
       }
 
-      function kick(s: State) {
-        if (s.timer) clearTimeout(s.timer)
-        s.timer = setTimeout(() => {
-          s.timer = undefined
-          void scan(s)
-        }, 50)
+      function fire(s: State) {
+        Effect.runFork(PubSub.publish(s.pulse, undefined).pipe(Effect.ignore))
       }
 
       async function scan(s: State) {