#!/usr/bin/env python3
from __future__ import annotations
import argparse
import asyncio
from pathlib import Path
from typing import Any
from codex_lsp_bridge.config import load_config
from codex_lsp_bridge.lsp_manager import LSPManager
def _summarize(result: Any) -> str:
if result is None:
return "null"
if isinstance(result, list):
return f"list(len={len(result)})"
if isinstance(result, dict):
keys = ", ".join(list(result.keys())[:6])
return f"dict(keys=[{keys}])"
return str(type(result))
async def main() -> None:
parser = argparse.ArgumentParser(description="LSP bridge smoke test (no file changes).")
parser.add_argument("--file", required=True, help="Absolute path to a file in the workspace.")
parser.add_argument("--line", type=int, default=0, help="0-indexed line.")
parser.add_argument("--column", type=int, default=0, help="0-indexed column.")
parser.add_argument("--config", default=str(Path("config/default.toml")), help="Bridge config path.")
parser.add_argument("--workspace-root", default=None, help="Optional workspace root override.")
parser.add_argument("--timeout", type=float, default=10.0, help="Per-request timeout seconds.")
parser.add_argument("--call-hierarchy", action="store_true", help="Also test call hierarchy.")
args = parser.parse_args()
mgr = LSPManager(load_config(args.config))
try:
client, uri, language_id = await mgr.sync_file(
args.file, workspace_root=args.workspace_root
)
print(f"language_id={language_id}")
print(f"uri={uri}")
async def run(label: str, coro: Any) -> None:
try:
res = await asyncio.wait_for(coro, timeout=args.timeout)
print(f"{label}: ok {_summarize(res)}")
except Exception as exc:
print(f"{label}: error {type(exc).__name__}: {exc}")
await run("hover", client.hover(uri=uri, line=args.line, character=args.column))
await run("definition", client.definition(uri=uri, line=args.line, character=args.column))
await run("type_definition", client.type_definition(uri=uri, line=args.line, character=args.column))
await run("signature_help", client.signature_help(uri=uri, line=args.line, character=args.column))
await run("document_symbols", client.document_symbols(uri=uri))
await run("code_action", client.code_action(
uri=uri,
start_line=args.line,
start_character=args.column,
end_line=args.line,
end_character=args.column,
only=None,
))
await run(
"format_document",
client.format_document(
uri=uri,
options={
"tabSize": 2,
"insertSpaces": True,
"trimTrailingWhitespace": True,
"insertFinalNewline": True,
"trimFinalNewlines": True,
},
),
)
if args.call_hierarchy:
items = await asyncio.wait_for(
client.prepare_call_hierarchy(
uri=uri, line=args.line, character=args.column
),
timeout=args.timeout,
)
print(f"prepare_call_hierarchy: ok {_summarize(items)}")
if isinstance(items, list) and items:
item = items[0]
await run("call_hierarchy_incoming", client.call_hierarchy_incoming(item=item))
await run("call_hierarchy_outgoing", client.call_hierarchy_outgoing(item=item))
finally:
await mgr.shutdown()
if __name__ == "__main__":
asyncio.run(main())