oh-my-opencode/src/tools/lsp/lsp-client-wrapper.ts
YeonGyu-Kim 29155ec7bc refactor: wave 1 - extract leaf modules, rename catch-all files, split index.ts hooks
- Split 25+ index.ts files into hook.ts + extracted modules
- Rename all catch-all utils.ts/helpers.ts to domain-specific names
- Split src/tools/lsp/ into ~15 focused modules
- Split src/tools/delegate-task/ into ~18 focused modules
- Separate shared types from implementation
- 155 files changed, 60+ new files created
- All typecheck clean, 61 tests pass
2026-02-08 13:57:26 +09:00

101 lines
2.9 KiB
TypeScript

import { extname, resolve } from "path"
import { fileURLToPath } from "node:url"
import { existsSync } from "fs"
import { LSPClient, lspManager } from "./client"
import { findServerForExtension } from "./config"
import type { ServerLookupResult } from "./types"
export function findWorkspaceRoot(filePath: string): string {
let dir = resolve(filePath)
if (!existsSync(dir) || !require("fs").statSync(dir).isDirectory()) {
dir = require("path").dirname(dir)
}
const markers = [".git", "package.json", "pyproject.toml", "Cargo.toml", "go.mod", "pom.xml", "build.gradle"]
let prevDir = ""
while (dir !== prevDir) {
for (const marker of markers) {
if (existsSync(require("path").join(dir, marker))) {
return dir
}
}
prevDir = dir
dir = require("path").dirname(dir)
}
return require("path").dirname(resolve(filePath))
}
export function uriToPath(uri: string): string {
return fileURLToPath(uri)
}
export function formatServerLookupError(result: Exclude<ServerLookupResult, { status: "found" }>): string {
if (result.status === "not_installed") {
const { server, installHint } = result
return [
`LSP server '${server.id}' is configured but NOT INSTALLED.`,
``,
`Command not found: ${server.command[0]}`,
``,
`To install:`,
` ${installHint}`,
``,
`Supported extensions: ${server.extensions.join(", ")}`,
``,
`After installation, the server will be available automatically.`,
`Run 'LspServers' tool to verify installation status.`,
].join("\n")
}
return [
`No LSP server configured for extension: ${result.extension}`,
``,
`Available servers: ${result.availableServers.slice(0, 10).join(", ")}${result.availableServers.length > 10 ? "..." : ""}`,
``,
`To add a custom server, configure 'lsp' in oh-my-opencode.json:`,
` {`,
` "lsp": {`,
` "my-server": {`,
` "command": ["my-lsp", "--stdio"],`,
` "extensions": ["${result.extension}"]`,
` }`,
` }`,
` }`,
].join("\n")
}
export async function withLspClient<T>(filePath: string, fn: (client: LSPClient) => Promise<T>): Promise<T> {
const absPath = resolve(filePath)
const ext = extname(absPath)
const result = findServerForExtension(ext)
if (result.status !== "found") {
throw new Error(formatServerLookupError(result))
}
const server = result.server
const root = findWorkspaceRoot(absPath)
const client = await lspManager.getClient(root, server)
try {
return await fn(client)
} catch (e) {
if (e instanceof Error && e.message.includes("timeout")) {
const isInitializing = lspManager.isServerInitializing(root, server.id)
if (isInitializing) {
throw new Error(
`LSP server is still initializing. Please retry in a few seconds. ` +
`Original error: ${e.message}`
)
}
}
throw e
} finally {
lspManager.releaseClient(root, server.id)
}
}