-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathlsp.py
More file actions
152 lines (134 loc) · 4.67 KB
/
lsp.py
File metadata and controls
152 lines (134 loc) · 4.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
import json
import logging
import sys
logger = logging.getLogger(__name__)
def read_message():
"""Read a JSON-RPC message from stdin."""
line = sys.stdin.readline()
if not line:
return None
if not line.startswith("Content-Length: "):
return None
content_length = int(line[16:].strip())
# Read the empty line
sys.stdin.readline()
# Read the body
body = sys.stdin.read(content_length)
return json.loads(body)
def write_message(msg):
"""Write a JSON-RPC message to stdout."""
body = json.dumps(msg)
sys.stdout.write(f"Content-Length: {len(body)}\\r\\n\\r\\n{body}")
sys.stdout.flush()
def handle_initialize(msg_id):
"""Handle the initialize request."""
return {
"jsonrpc": "2.0",
"id": msg_id,
"result": {
"capabilities": {
"textDocumentSync": 1, # Full sync
"completionProvider": {
"resolveProvider": False,
"triggerCharacters": ["."]
},
"hoverProvider": True
},
"serverInfo": {
"name": "gnn-lsp",
"version": "1.0.0"
}
}
}
def handle_hover(msg_id, params):
"""Handle the textDocument/hover request."""
return {
"jsonrpc": "2.0",
"id": msg_id,
"result": {
"contents": {
"kind": "markdown",
"value": "**GNN Identifier**\\n\\nGeneralized Notation Notation construct."
}
}
}
def publish_diagnostics(uri, text):
"""Run basic validation and publish diagnostics."""
diagnostics = []
# Simple syntax check: look for missing closing braces
if "{" in text and "}" not in text:
diagnostics.append({
"range": {
"start": {"line": 0, "character": 0},
"end": {"line": 0, "character": 100}
},
"severity": 1, # Error
"message": "Missing closing brace '}'"
})
write_message({
"jsonrpc": "2.0",
"method": "textDocument/publishDiagnostics",
"params": {
"uri": uri,
"diagnostics": diagnostics
}
})
def start_lsp():
"""Start the Language Server Protocol loop on stdin/stdout."""
# Setup simple logging to a file to avoid corrupting stdout
logging.basicConfig(filename='gnn-lsp.log', level=logging.INFO)
logger.info("Starting GNN LSP Server...")
while True:
try:
msg = read_message()
if not msg:
break
logger.info(f"Received: {msg.get('method')}")
method = msg.get("method")
msg_id = msg.get("id")
if method == "initialize":
write_message(handle_initialize(msg_id))
elif method == "initialized":
pass
elif method == "textDocument/hover":
write_message(handle_hover(msg_id, msg.get("params")))
elif method == "textDocument/didOpen":
params = msg.get("params", {})
doc = params.get("textDocument", {})
uri = doc.get("uri", "")
text = doc.get("text", "")
if uri and text:
publish_diagnostics(uri, text)
elif method == "textDocument/didChange":
params = msg.get("params", {})
doc = params.get("textDocument", {})
uri = doc.get("uri", "")
changes = params.get("contentChanges", [])
if uri and changes:
# Sync sends full text
text = changes[0].get("text", "")
publish_diagnostics(uri, text)
elif method == "shutdown":
write_message({
"jsonrpc": "2.0",
"id": msg_id,
"result": None
})
elif method == "exit":
break
else:
# Ignore unhandled notifications
if msg_id is not None:
# Return method not found if it is a request
write_message({
"jsonrpc": "2.0",
"id": msg_id,
"error": {
"code": -32601,
"message": "Method not found"
}
})
except Exception as e:
logger.error(f"Error handling message: {e}")
break
logger.info("GNN LSP Server shutting down.")