(input: {
serverID: string
server: LSPServer.Handle
root: string
directory: string
instance: InstanceContext
})
| 121 | } |
| 122 | |
| 123 | export async function create(input: { |
| 124 | serverID: string |
| 125 | server: LSPServer.Handle |
| 126 | root: string |
| 127 | directory: string |
| 128 | instance: InstanceContext |
| 129 | }) { |
| 130 | const instance = input.instance |
| 131 | |
| 132 | const connection = createMessageConnection( |
| 133 | new StreamMessageReader(input.server.process.stdout as any), |
| 134 | new StreamMessageWriter(input.server.process.stdin as any), |
| 135 | ) |
| 136 | input.server.process.stderr?.resume() |
| 137 | // --- Connection state --- |
| 138 | |
| 139 | const pushDiagnostics = new Map<string, Diagnostic[]>() |
| 140 | const pullDiagnostics = new Map<string, Diagnostic[]>() |
| 141 | const published = new Map<string, { at: number; version?: number }>() |
| 142 | const diagnosticRegistrations = new Map<string, CapabilityRegistration>() |
| 143 | const registrationListeners = new Set<() => void>() |
| 144 | const diagnosticListeners = new Set<(input: { path: string; serverID: string }) => void>() |
| 145 | const mergedDiagnostics = (filePath: string) => |
| 146 | dedupeDiagnostics([...(pushDiagnostics.get(filePath) ?? []), ...(pullDiagnostics.get(filePath) ?? [])]) |
| 147 | const updatePushDiagnostics = (filePath: string, next: Diagnostic[]) => { |
| 148 | pushDiagnostics.set(filePath, next) |
| 149 | for (const listener of diagnosticListeners) listener({ path: filePath, serverID: input.serverID }) |
| 150 | } |
| 151 | const updatePullDiagnostics = (filePath: string, next: Diagnostic[]) => { |
| 152 | pullDiagnostics.set(filePath, next) |
| 153 | } |
| 154 | const emitRegistrationChange = () => { |
| 155 | for (const listener of [...registrationListeners]) listener() |
| 156 | } |
| 157 | |
| 158 | // --- LSP connection handlers --- |
| 159 | |
| 160 | connection.onNotification("textDocument/publishDiagnostics", (params) => { |
| 161 | const filePath = getFilePath(params.uri) |
| 162 | if (!filePath) return |
| 163 | published.set(filePath, { |
| 164 | at: Date.now(), |
| 165 | version: typeof params.version === "number" ? params.version : undefined, |
| 166 | }) |
| 167 | if (shouldSeedDiagnosticsOnFirstPush(input.serverID) && !pushDiagnostics.has(filePath)) { |
| 168 | pushDiagnostics.set(filePath, params.diagnostics) |
| 169 | return |
| 170 | } |
| 171 | updatePushDiagnostics(filePath, params.diagnostics) |
| 172 | }) |
| 173 | connection.onRequest("window/workDoneProgress/create", (params) => { |
| 174 | return null |
| 175 | }) |
| 176 | connection.onRequest("workspace/configuration", async (params) => { |
| 177 | const items = (params as { items?: { section?: string }[] }).items ?? [] |
| 178 | return items.map((item) => configurationValue(input.server.initialization, item.section)) |
| 179 | }) |
| 180 | connection.onRequest("client/registerCapability", async (params) => { |
nothing calls this directly
no test coverage detected