refactor(core): move database schema ownership (#29068)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
This commit is contained in:
co-authored by
copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
parent
6bcb9cb9bb
commit
7f571d36ea
@@ -1,5 +1,3 @@
|
||||
import { BusEvent } from "@/bus/bus-event"
|
||||
import { Bus } from "@/bus"
|
||||
import path from "path"
|
||||
import { pathToFileURL, fileURLToPath } from "url"
|
||||
import { createMessageConnection, StreamMessageReader, StreamMessageWriter } from "vscode-jsonrpc/node"
|
||||
@@ -11,8 +9,6 @@ import { Effect, Schema } from "effect"
|
||||
import type * as LSPServer from "./server"
|
||||
import { withTimeout } from "../util/timeout"
|
||||
import { Filesystem } from "@/util/filesystem"
|
||||
import { InstanceRef } from "@/effect/instance-ref"
|
||||
import { makeRuntime } from "@/effect/run-service"
|
||||
import type { InstanceContext } from "@/project/instance-context"
|
||||
|
||||
const DIAGNOSTICS_DEBOUNCE_MS = 150
|
||||
@@ -28,8 +24,6 @@ const FILE_CHANGE_CHANGED = 2
|
||||
const TEXT_DOCUMENT_SYNC_INCREMENTAL = 2
|
||||
|
||||
const log = Log.create({ service: "lsp.client" })
|
||||
const busRuntime = makeRuntime(Bus.Service, Bus.layer)
|
||||
|
||||
export type Info = NonNullable<Awaited<ReturnType<typeof create>>>
|
||||
|
||||
export type Diagnostic = VSCodeDiagnostic
|
||||
@@ -39,16 +33,6 @@ export class InitializeError extends Schema.TaggedErrorClass<InitializeError>()(
|
||||
cause: Schema.optional(Schema.Defect),
|
||||
}) {}
|
||||
|
||||
export const Event = {
|
||||
Diagnostics: BusEvent.define(
|
||||
"lsp.client.diagnostics",
|
||||
Schema.Struct({
|
||||
serverID: Schema.String,
|
||||
path: Schema.String,
|
||||
}),
|
||||
),
|
||||
}
|
||||
|
||||
type DocumentDiagnosticReport = {
|
||||
items?: Diagnostic[]
|
||||
relatedDocuments?: Record<string, DocumentDiagnosticReport>
|
||||
@@ -169,15 +153,12 @@ export async function create(input: {
|
||||
const published = new Map<string, { at: number; version?: number }>()
|
||||
const diagnosticRegistrations = new Map<string, CapabilityRegistration>()
|
||||
const registrationListeners = new Set<() => void>()
|
||||
const diagnosticListeners = new Set<(input: { path: string; serverID: string }) => void>()
|
||||
const mergedDiagnostics = (filePath: string) =>
|
||||
dedupeDiagnostics([...(pushDiagnostics.get(filePath) ?? []), ...(pullDiagnostics.get(filePath) ?? [])])
|
||||
const updatePushDiagnostics = (filePath: string, next: Diagnostic[]) => {
|
||||
pushDiagnostics.set(filePath, next)
|
||||
void busRuntime.runPromise((svc) =>
|
||||
svc
|
||||
.publish(Event.Diagnostics, { path: filePath, serverID: input.serverID })
|
||||
.pipe(Effect.provideService(InstanceRef, instance)),
|
||||
)
|
||||
for (const listener of diagnosticListeners) listener({ path: filePath, serverID: input.serverID })
|
||||
}
|
||||
const updatePullDiagnostics = (filePath: string, next: Diagnostic[]) => {
|
||||
pullDiagnostics.set(filePath, next)
|
||||
@@ -525,14 +506,12 @@ export async function create(input: {
|
||||
}
|
||||
|
||||
timeoutTimer = setTimeout(() => finish(false), request.timeout)
|
||||
unsub = busRuntime.runSync((svc) =>
|
||||
svc
|
||||
.subscribeCallback(Event.Diagnostics, (event) => {
|
||||
if (event.properties.path !== request.path || event.properties.serverID !== input.serverID) return
|
||||
schedule()
|
||||
})
|
||||
.pipe(Effect.provideService(InstanceRef, instance)),
|
||||
)
|
||||
const listener = (event: { path: string; serverID: string }) => {
|
||||
if (event.path !== request.path || event.serverID !== input.serverID) return
|
||||
schedule()
|
||||
}
|
||||
diagnosticListeners.add(listener)
|
||||
unsub = () => diagnosticListeners.delete(listener)
|
||||
schedule()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { BusEvent } from "@/bus/bus-event"
|
||||
import { Bus } from "@/bus"
|
||||
import { EventV2Bridge } from "@/event-v2-bridge"
|
||||
import { EventV2 } from "@opencode-ai/core/event"
|
||||
import * as Log from "@opencode-ai/core/util/log"
|
||||
import * as LSPClient from "./client"
|
||||
import path from "path"
|
||||
@@ -17,7 +17,7 @@ import { RuntimeFlags } from "@/effect/runtime-flags"
|
||||
const log = Log.create({ service: "lsp" })
|
||||
|
||||
export const Event = {
|
||||
Updated: BusEvent.define("lsp.updated", Schema.Struct({})),
|
||||
Updated: EventV2.define({ type: "lsp.updated", schema: {} }),
|
||||
}
|
||||
|
||||
const Position = Schema.Struct({
|
||||
@@ -144,6 +144,7 @@ export const layer = Layer.effect(
|
||||
Effect.gen(function* () {
|
||||
const config = yield* Config.Service
|
||||
const flags = yield* RuntimeFlags.Service
|
||||
const events = yield* EventV2Bridge.Service
|
||||
|
||||
const state = yield* InstanceState.make<State>(
|
||||
Effect.fn("LSP.state")(function* (ctx) {
|
||||
@@ -212,9 +213,10 @@ export const layer = Layer.effect(
|
||||
const ctx = yield* InstanceState.context
|
||||
if (!containsPath(file, ctx)) return [] as LSPClient.Info[]
|
||||
const s = yield* InstanceState.get(state)
|
||||
return yield* Effect.promise(async () => {
|
||||
const clients = yield* Effect.promise(async () => {
|
||||
const extension = path.parse(file).ext || file
|
||||
const result: LSPClient.Info[] = []
|
||||
let updated = 0
|
||||
|
||||
async function schedule(server: LSPServer.Info, root: string, key: string) {
|
||||
const handle = await server
|
||||
@@ -291,11 +293,15 @@ export const layer = Layer.effect(
|
||||
if (!client) continue
|
||||
|
||||
result.push(client)
|
||||
await Bus.publish(ctx, Event.Updated, {})
|
||||
updated++
|
||||
}
|
||||
|
||||
return result
|
||||
return { result, updated }
|
||||
})
|
||||
yield* Effect.forEach(Array.from({ length: clients.updated }), () => events.publish(Event.Updated, {}), {
|
||||
discard: true,
|
||||
})
|
||||
return clients.result
|
||||
})
|
||||
|
||||
const run = Effect.fnUntraced(function* <T>(file: string, fn: (client: LSPClient.Info) => Promise<T>) {
|
||||
@@ -500,7 +506,11 @@ export const layer = Layer.effect(
|
||||
}),
|
||||
)
|
||||
|
||||
export const defaultLayer = layer.pipe(Layer.provide(Config.defaultLayer), Layer.provide(RuntimeFlags.defaultLayer))
|
||||
export const defaultLayer = layer.pipe(
|
||||
Layer.provide(Config.defaultLayer),
|
||||
Layer.provide(RuntimeFlags.defaultLayer),
|
||||
Layer.provide(EventV2Bridge.defaultLayer),
|
||||
)
|
||||
|
||||
export * as Diagnostic from "./diagnostic"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user