mirror of
https://github.com/AstrBotDevs/AstrBot
synced 2026-07-16 01:40:15 +08:00
122 lines
3.6 KiB
Python
122 lines
3.6 KiB
Python
"""
|
|
Echo LSP Server - Simple LSP server for testing.
|
|
|
|
This server responds to LSP protocol requests over stdio with Content-Length headers:
|
|
- initialize: Initialize the connection and report capabilities
|
|
- initialized: Notification (no response)
|
|
- shutdown: Graceful shutdown request
|
|
- textDocument/didOpen: Document open notification
|
|
- other requests: Echoed back with result
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import sys
|
|
|
|
|
|
def write_message(message: dict) -> None:
|
|
"""Write a JSON-RPC message to stdout with Content-Length header."""
|
|
content = json.dumps(message)
|
|
headers = f"Content-Length: {len(content)}\r\n\r\n"
|
|
sys.stdout.write(headers + content)
|
|
sys.stdout.flush()
|
|
|
|
|
|
def read_message() -> dict | None:
|
|
"""Read a single JSON-RPC message from stdin using LSP stdio protocol."""
|
|
# Read headers until we get \r\n\r\n
|
|
header_bytes = b""
|
|
while True:
|
|
ch = sys.stdin.buffer.read(1)
|
|
if not ch:
|
|
return None
|
|
header_bytes += ch
|
|
if header_bytes.endswith(b"\r\n\r\n"):
|
|
break
|
|
|
|
# Parse Content-Length from headers
|
|
header_text = header_bytes.decode("utf-8")
|
|
content_length = 0
|
|
for line in header_text.split("\r\n"):
|
|
if line.startswith("Content-Length:"):
|
|
content_length = int(line.split(":")[1].strip())
|
|
|
|
if content_length == 0:
|
|
return None
|
|
|
|
# Read the content body
|
|
content = sys.stdin.buffer.read(content_length)
|
|
if not content:
|
|
return None
|
|
|
|
return json.loads(content.decode("utf-8"))
|
|
|
|
|
|
def main() -> None:
|
|
"""Main loop - read requests from stdin and respond."""
|
|
while True:
|
|
try:
|
|
request = read_message()
|
|
if request is None:
|
|
break
|
|
|
|
method = request.get("method", "")
|
|
req_id = request.get("id")
|
|
|
|
# Handle initialize request
|
|
if method == "initialize":
|
|
response = {
|
|
"jsonrpc": "2.0",
|
|
"id": req_id,
|
|
"result": {
|
|
"capabilities": {
|
|
"textDocumentSync": 1,
|
|
"hoverProvider": True,
|
|
"completionProvider": {"resolveProvider": False},
|
|
}
|
|
},
|
|
"serverInfo": {
|
|
"name": "echo-lsp-server",
|
|
"version": "1.0.0",
|
|
},
|
|
}
|
|
write_message(response)
|
|
|
|
# Handle initialized notification (no response needed)
|
|
elif method == "initialized":
|
|
continue
|
|
|
|
# Handle shutdown request
|
|
elif method == "shutdown":
|
|
response = {
|
|
"jsonrpc": "2.0",
|
|
"id": req_id,
|
|
"result": None,
|
|
}
|
|
write_message(response)
|
|
|
|
# Handle textDocument/didOpen notification (no response needed)
|
|
elif method == "textDocument/didOpen":
|
|
continue
|
|
|
|
# Echo any other request back with the same id
|
|
elif req_id is not None:
|
|
response = {
|
|
"jsonrpc": "2.0",
|
|
"id": req_id,
|
|
"result": {"echoed": True, "method": method},
|
|
}
|
|
write_message(response)
|
|
|
|
except Exception as e:
|
|
error_response = {
|
|
"jsonrpc": "2.0",
|
|
"id": None,
|
|
"error": {"code": -32603, "message": str(e)},
|
|
}
|
|
write_message(error_response)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main() |