cleanup
This commit is contained in:
@@ -99,12 +99,36 @@ pub const Server = struct {
|
||||
stderr.writeStreamingAll(self.io, msg) catch {};
|
||||
}
|
||||
|
||||
const RequestContext = struct {
|
||||
id_json: []const u8,
|
||||
uri: []const u8,
|
||||
};
|
||||
|
||||
fn extractRequest(self: *Server, id: ?std.json.Value, params: std.json.Value) !?RequestContext {
|
||||
const req_id = id orelse return null;
|
||||
const id_json = try lsp.valueToJson(self.allocator, req_id);
|
||||
const td = jsonGet(params, "textDocument") orelse return null;
|
||||
const uri = jsonStr(jsonGet(td, "uri") orelse return null) orelse return null;
|
||||
return .{ .id_json = id_json, .uri = uri };
|
||||
}
|
||||
|
||||
fn extractPosition(params: std.json.Value) ?struct { line: u32, character: u32 } {
|
||||
const position = jsonGet(params, "position") orelse return null;
|
||||
const line = std.math.cast(u32, jsonInt(jsonGet(position, "line") orelse return null) orelse return null) orelse return null;
|
||||
const character = std.math.cast(u32, jsonInt(jsonGet(position, "character") orelse return null) orelse return null) orelse return null;
|
||||
return .{ .line = line, .character = character };
|
||||
}
|
||||
|
||||
fn sendResponse(self: *Server, id_json: []const u8, result_json: []const u8) !void {
|
||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, result_json);
|
||||
try self.transport.writeMessage(resp);
|
||||
}
|
||||
|
||||
fn handleInitialize(self: *Server, id: ?std.json.Value) !void {
|
||||
const req_id = id orelse return;
|
||||
const id_json = try lsp.valueToJson(self.allocator, req_id);
|
||||
const result_json = try lsp.initializeResultJson(self.allocator);
|
||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, result_json);
|
||||
try self.transport.writeMessage(resp);
|
||||
try self.sendResponse(id_json, result_json);
|
||||
}
|
||||
|
||||
fn handleDidOpen(self: *Server, params: std.json.Value) !void {
|
||||
@@ -142,25 +166,17 @@ pub const Server = struct {
|
||||
}
|
||||
|
||||
fn handleDefinition(self: *Server, id: ?std.json.Value, params: std.json.Value) !void {
|
||||
const req_id = id orelse return;
|
||||
const id_json = try lsp.valueToJson(self.allocator, req_id);
|
||||
|
||||
const td = jsonGet(params, "textDocument") orelse return;
|
||||
const uri = jsonStr(jsonGet(td, "uri") orelse return) orelse return;
|
||||
const position = jsonGet(params, "position") orelse return;
|
||||
const line = std.math.cast(u32, jsonInt(jsonGet(position, "line") orelse return) orelse return) orelse return;
|
||||
const character = std.math.cast(u32, jsonInt(jsonGet(position, "character") orelse return) orelse return) orelse return;
|
||||
const ctx = try self.extractRequest(id, params) orelse return;
|
||||
const pos = extractPosition(params) orelse return;
|
||||
const id_json = ctx.id_json;
|
||||
const uri = ctx.uri;
|
||||
|
||||
const analysis = self.sema_cache.get(uri) orelse {
|
||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, "null");
|
||||
try self.transport.writeMessage(resp);
|
||||
return;
|
||||
return try self.sendResponse(id_json, "null");
|
||||
};
|
||||
|
||||
const offset = positionToOffset(analysis.source, line, character) orelse {
|
||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, "null");
|
||||
try self.transport.writeMessage(resp);
|
||||
return;
|
||||
const offset = positionToOffset(analysis.source, pos.line, pos.character) orelse {
|
||||
return try self.sendResponse(id_json, "null");
|
||||
};
|
||||
|
||||
// Check if cursor is on a qualified name (e.g. "std.print" or UFCS "list.append")
|
||||
@@ -206,8 +222,7 @@ pub const Server = struct {
|
||||
.end = .{ .line = 0, .character = 0 },
|
||||
};
|
||||
const loc_json = try lsp.locationJson(self.allocator, target_uri, range);
|
||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, loc_json);
|
||||
try self.transport.writeMessage(resp);
|
||||
try self.sendResponse(id_json, loc_json);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -223,30 +238,20 @@ pub const Server = struct {
|
||||
}
|
||||
}
|
||||
|
||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, "null");
|
||||
try self.transport.writeMessage(resp);
|
||||
try self.sendResponse(id_json, "null");
|
||||
}
|
||||
|
||||
fn handleHover(self: *Server, id: ?std.json.Value, params: std.json.Value) !void {
|
||||
const req_id = id orelse return;
|
||||
const id_json = try lsp.valueToJson(self.allocator, req_id);
|
||||
const ctx = try self.extractRequest(id, params) orelse return;
|
||||
const pos = extractPosition(params) orelse return;
|
||||
const id_json = ctx.id_json;
|
||||
|
||||
const td = jsonGet(params, "textDocument") orelse return;
|
||||
const uri = jsonStr(jsonGet(td, "uri") orelse return) orelse return;
|
||||
const position = jsonGet(params, "position") orelse return;
|
||||
const line = std.math.cast(u32, jsonInt(jsonGet(position, "line") orelse return) orelse return) orelse return;
|
||||
const character = std.math.cast(u32, jsonInt(jsonGet(position, "character") orelse return) orelse return) orelse return;
|
||||
|
||||
const analysis = self.sema_cache.get(uri) orelse {
|
||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, "null");
|
||||
try self.transport.writeMessage(resp);
|
||||
return;
|
||||
const analysis = self.sema_cache.get(ctx.uri) orelse {
|
||||
return try self.sendResponse(id_json, "null");
|
||||
};
|
||||
|
||||
const offset = positionToOffset(analysis.source, line, character) orelse {
|
||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, "null");
|
||||
try self.transport.writeMessage(resp);
|
||||
return;
|
||||
const offset = positionToOffset(analysis.source, pos.line, pos.character) orelse {
|
||||
return try self.sendResponse(id_json, "null");
|
||||
};
|
||||
|
||||
// Check if cursor is on a qualified name (e.g. std.print) — source-based, no AST
|
||||
@@ -255,17 +260,13 @@ pub const Server = struct {
|
||||
if (analysis.import_map.get(qn.ns)) |import_path| {
|
||||
if (try self.formatNamespaceMemberHover(analysis, qn.ns, qn.member, import_path)) |hover_text| {
|
||||
const hover_json = try lsp.hoverJson(self.allocator, hover_text);
|
||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, hover_json);
|
||||
try self.transport.writeMessage(resp);
|
||||
return;
|
||||
return try self.sendResponse(id_json, hover_json);
|
||||
}
|
||||
}
|
||||
// Struct field hover (e.g. point.x)
|
||||
if (try self.formatStructFieldHover(analysis, qn.ns, qn.member)) |hover_text| {
|
||||
const hover_json = try lsp.hoverJson(self.allocator, hover_text);
|
||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, hover_json);
|
||||
try self.transport.writeMessage(resp);
|
||||
return;
|
||||
return try self.sendResponse(id_json, hover_json);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,9 +276,7 @@ pub const Server = struct {
|
||||
if (node.data == .enum_literal) {
|
||||
if (try self.formatEnumVariantHover(analysis, node.data.enum_literal.name)) |hover_text| {
|
||||
const hover_json = try lsp.hoverJson(self.allocator, hover_text);
|
||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, hover_json);
|
||||
try self.transport.writeMessage(resp);
|
||||
return;
|
||||
return try self.sendResponse(id_json, hover_json);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -309,26 +308,18 @@ pub const Server = struct {
|
||||
const source_for_hover = if (resolved) |r| r.source else analysis.source;
|
||||
const hover_text = try formatSymbolHover(self.allocator, sym, analysis.root, source_for_hover);
|
||||
const hover_json = try lsp.hoverJson(self.allocator, hover_text);
|
||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, hover_json);
|
||||
try self.transport.writeMessage(resp);
|
||||
return;
|
||||
return try self.sendResponse(id_json, hover_json);
|
||||
}
|
||||
|
||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, "null");
|
||||
try self.transport.writeMessage(resp);
|
||||
try self.sendResponse(id_json, "null");
|
||||
}
|
||||
|
||||
fn handleDocumentSymbol(self: *Server, id: ?std.json.Value, params: std.json.Value) !void {
|
||||
const req_id = id orelse return;
|
||||
const id_json = try lsp.valueToJson(self.allocator, req_id);
|
||||
const ctx = try self.extractRequest(id, params) orelse return;
|
||||
const id_json = ctx.id_json;
|
||||
|
||||
const td = jsonGet(params, "textDocument") orelse return;
|
||||
const uri = jsonStr(jsonGet(td, "uri") orelse return) orelse return;
|
||||
|
||||
const analysis = self.sema_cache.get(uri) orelse {
|
||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, "[]");
|
||||
try self.transport.writeMessage(resp);
|
||||
return;
|
||||
const analysis = self.sema_cache.get(ctx.uri) orelse {
|
||||
return try self.sendResponse(id_json, "[]");
|
||||
};
|
||||
|
||||
var doc_symbols = std.ArrayList(lsp.DocumentSymbol).empty;
|
||||
@@ -359,23 +350,18 @@ pub const Server = struct {
|
||||
}
|
||||
|
||||
const symbols_json = try lsp.documentSymbolsJson(self.allocator, doc_symbols.items);
|
||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, symbols_json);
|
||||
try self.transport.writeMessage(resp);
|
||||
try self.sendResponse(id_json, symbols_json);
|
||||
}
|
||||
|
||||
fn handleCompletion(self: *Server, id: ?std.json.Value, params: std.json.Value) !void {
|
||||
const req_id = id orelse return;
|
||||
const id_json = try lsp.valueToJson(self.allocator, req_id);
|
||||
|
||||
const td = jsonGet(params, "textDocument") orelse return;
|
||||
const uri = jsonStr(jsonGet(td, "uri") orelse return) orelse return;
|
||||
const position = jsonGet(params, "position") orelse return;
|
||||
const line = std.math.cast(u32, jsonInt(jsonGet(position, "line") orelse return) orelse return) orelse return;
|
||||
const character = std.math.cast(u32, jsonInt(jsonGet(position, "character") orelse return) orelse return) orelse return;
|
||||
const ctx = try self.extractRequest(id, params) orelse return;
|
||||
const pos = extractPosition(params) orelse return;
|
||||
const id_json = ctx.id_json;
|
||||
const uri = ctx.uri;
|
||||
|
||||
// Check if cursor is after a dot (possibly with partial identifier typed)
|
||||
if (self.documents.get(uri)) |doc| {
|
||||
if (positionToOffset(doc.text, line, character)) |off| {
|
||||
if (positionToOffset(doc.text, pos.line, pos.character)) |off| {
|
||||
// Scan backwards past any identifier characters to find a dot
|
||||
var scan = off;
|
||||
while (scan > 0 and isIdentChar(doc.text[scan - 1])) scan -= 1;
|
||||
@@ -388,9 +374,7 @@ pub const Server = struct {
|
||||
|
||||
// Regular completion: all in-scope symbols + keywords
|
||||
const analysis = self.sema_cache.get(uri) orelse {
|
||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, "[]");
|
||||
try self.transport.writeMessage(resp);
|
||||
return;
|
||||
return try self.sendResponse(id_json, "[]");
|
||||
};
|
||||
|
||||
var items = std.ArrayList(lsp.CompletionItem).empty;
|
||||
@@ -449,8 +433,7 @@ pub const Server = struct {
|
||||
}
|
||||
|
||||
const items_json = try lsp.completionItemsJson(self.allocator, items.items);
|
||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, items_json);
|
||||
try self.transport.writeMessage(resp);
|
||||
try self.sendResponse(id_json, items_json);
|
||||
}
|
||||
|
||||
fn handleDotCompletion(self: *Server, id_json: []const u8, uri: []const u8, text: []const u8, cursor_offset: u32) !void {
|
||||
@@ -475,8 +458,7 @@ pub const Server = struct {
|
||||
}
|
||||
|
||||
const items_json = try lsp.completionListJson(self.allocator, items.items);
|
||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, items_json);
|
||||
try self.transport.writeMessage(resp);
|
||||
try self.sendResponse(id_json, items_json);
|
||||
}
|
||||
|
||||
fn collectMemberCompletions(self: *Server, items: *std.ArrayList(lsp.CompletionItem), analysis: DocumentAnalysis, name: []const u8) !void {
|
||||
@@ -594,31 +576,21 @@ pub const Server = struct {
|
||||
}
|
||||
|
||||
fn handleSignatureHelp(self: *Server, id: ?std.json.Value, params: std.json.Value) !void {
|
||||
const req_id = id orelse return;
|
||||
const id_json = try lsp.valueToJson(self.allocator, req_id);
|
||||
|
||||
const td = jsonGet(params, "textDocument") orelse return;
|
||||
const uri = jsonStr(jsonGet(td, "uri") orelse return) orelse return;
|
||||
const position = jsonGet(params, "position") orelse return;
|
||||
const line = std.math.cast(u32, jsonInt(jsonGet(position, "line") orelse return) orelse return) orelse return;
|
||||
const character = std.math.cast(u32, jsonInt(jsonGet(position, "character") orelse return) orelse return) orelse return;
|
||||
const req = try self.extractRequest(id, params) orelse return;
|
||||
const pos = extractPosition(params) orelse return;
|
||||
const id_json = req.id_json;
|
||||
const uri = req.uri;
|
||||
|
||||
const doc = self.documents.get(uri) orelse {
|
||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, "null");
|
||||
try self.transport.writeMessage(resp);
|
||||
return;
|
||||
return try self.sendResponse(id_json, "null");
|
||||
};
|
||||
|
||||
const offset = positionToOffset(doc.text, line, character) orelse {
|
||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, "null");
|
||||
try self.transport.writeMessage(resp);
|
||||
return;
|
||||
const offset = positionToOffset(doc.text, pos.line, pos.character) orelse {
|
||||
return try self.sendResponse(id_json, "null");
|
||||
};
|
||||
|
||||
const ctx = findCallContext(doc.text, offset) orelse {
|
||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, "null");
|
||||
try self.transport.writeMessage(resp);
|
||||
return;
|
||||
const call_ctx = findCallContext(doc.text, offset) orelse {
|
||||
return try self.sendResponse(id_json, "null");
|
||||
};
|
||||
|
||||
// Built-in function signatures
|
||||
@@ -636,25 +608,21 @@ pub const Server = struct {
|
||||
.{ .name = "write", .label = "write(str: string) -> void", .params = &.{"str: string"} },
|
||||
};
|
||||
for (&builtin_sigs) |b| {
|
||||
const matches = std.mem.eql(u8, ctx.name, b.name) or
|
||||
(std.mem.startsWith(u8, ctx.name, "std.") and std.mem.eql(u8, ctx.name[4..], b.name));
|
||||
const matches = std.mem.eql(u8, call_ctx.name, b.name) or
|
||||
(std.mem.startsWith(u8, call_ctx.name, "std.") and std.mem.eql(u8, call_ctx.name[4..], b.name));
|
||||
if (matches) {
|
||||
const sig_json = try lsp.signatureHelpJson(self.allocator, b.label, b.params, ctx.active_param);
|
||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, sig_json);
|
||||
try self.transport.writeMessage(resp);
|
||||
return;
|
||||
const sig_json = try lsp.signatureHelpJson(self.allocator, b.label, b.params, call_ctx.active_param);
|
||||
return try self.sendResponse(id_json, sig_json);
|
||||
}
|
||||
}
|
||||
|
||||
// Look up function in sema cache
|
||||
const analysis = self.sema_cache.get(uri) orelse {
|
||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, "null");
|
||||
try self.transport.writeMessage(resp);
|
||||
return;
|
||||
return try self.sendResponse(id_json, "null");
|
||||
};
|
||||
|
||||
// Try to find the function — either at top level or inside a namespace
|
||||
const fn_node = findFnDeclByName(analysis, ctx.name);
|
||||
const fn_node = findFnDeclByName(analysis, call_ctx.name);
|
||||
|
||||
if (fn_node) |fd| {
|
||||
var label_buf = std.ArrayList(u8).empty;
|
||||
@@ -684,27 +652,19 @@ pub const Server = struct {
|
||||
}
|
||||
}
|
||||
|
||||
const sig_json = try lsp.signatureHelpJson(self.allocator, label_buf.items, param_labels.items, ctx.active_param);
|
||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, sig_json);
|
||||
try self.transport.writeMessage(resp);
|
||||
return;
|
||||
const sig_json = try lsp.signatureHelpJson(self.allocator, label_buf.items, param_labels.items, call_ctx.active_param);
|
||||
return try self.sendResponse(id_json, sig_json);
|
||||
}
|
||||
|
||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, "null");
|
||||
try self.transport.writeMessage(resp);
|
||||
try self.sendResponse(id_json, "null");
|
||||
}
|
||||
|
||||
fn handleSemanticTokens(self: *Server, id: ?std.json.Value, params: std.json.Value) !void {
|
||||
const req_id = id orelse return;
|
||||
const id_json = try lsp.valueToJson(self.allocator, req_id);
|
||||
const ctx = try self.extractRequest(id, params) orelse return;
|
||||
const id_json = ctx.id_json;
|
||||
|
||||
const td = jsonGet(params, "textDocument") orelse return;
|
||||
const uri = jsonStr(jsonGet(td, "uri") orelse return) orelse return;
|
||||
|
||||
const analysis = self.sema_cache.get(uri) orelse {
|
||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, "{\"data\":[]}");
|
||||
try self.transport.writeMessage(resp);
|
||||
return;
|
||||
const analysis = self.sema_cache.get(ctx.uri) orelse {
|
||||
return try self.sendResponse(id_json, "{\"data\":[]}");
|
||||
};
|
||||
|
||||
var data = std.ArrayList(u32).empty;
|
||||
@@ -727,8 +687,7 @@ pub const Server = struct {
|
||||
}
|
||||
|
||||
const result_json = try lsp.semanticTokensJson(self.allocator, data.items);
|
||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, result_json);
|
||||
try self.transport.writeMessage(resp);
|
||||
try self.sendResponse(id_json, result_json);
|
||||
}
|
||||
|
||||
fn classifyToken(tok: sx.token.Token, analysis: DocumentAnalysis) ?u32 {
|
||||
@@ -1308,8 +1267,7 @@ pub const Server = struct {
|
||||
else
|
||||
uri;
|
||||
const loc_json = try lsp.locationJson(self.allocator, target_uri, range);
|
||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, loc_json);
|
||||
try self.transport.writeMessage(resp);
|
||||
try self.sendResponse(id_json, loc_json);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1355,8 +1313,7 @@ pub const Server = struct {
|
||||
const range = spanToRange(imp_source, target.span);
|
||||
const target_uri = try std.fmt.allocPrint(self.allocator, "file://{s}", .{import_path});
|
||||
const loc_json = try lsp.locationJson(self.allocator, target_uri, range);
|
||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, loc_json);
|
||||
try self.transport.writeMessage(resp);
|
||||
try self.sendResponse(id_json, loc_json);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user