Use zig-lsp-codegen (#850)
* add lsp.zig * change references from types.zig to lsp.zig * remove types.zig and requests.zig * add tres as a submodule * transition codebase from types.zig to lsp.zig * update lsp.zig * completely overhaul message handler * fix memory errors * partially transition tests to lsp.zig * update lsp.zig * more test fixes * disable failing tests * fix message handling bugs * fix remaining tests * access correct union in diff.applyTextEdits * more message handler fixes * run zig fmt * update tres submodule * fix memory access to freed memory * simplify initialize_msg for testing * check if publishDiagnostics is supported
This commit is contained in:
@@ -8,13 +8,12 @@ const ErrorBuilder = @import("../ErrorBuilder.zig");
|
||||
|
||||
const types = zls.types;
|
||||
const offsets = zls.offsets;
|
||||
const requests = zls.requests;
|
||||
|
||||
const allocator: std.mem.Allocator = std.testing.allocator;
|
||||
|
||||
const Completion = struct {
|
||||
label: []const u8,
|
||||
kind: types.CompletionItem.Kind,
|
||||
kind: types.CompletionItemKind,
|
||||
detail: ?[]const u8 = null,
|
||||
};
|
||||
|
||||
@@ -412,16 +411,13 @@ fn testCompletion(source: []const u8, expected_completions: []const Completion)
|
||||
|
||||
try ctx.requestDidOpen(test_uri, text);
|
||||
|
||||
const request = requests.Completion{
|
||||
.params = .{
|
||||
.textDocument = .{ .uri = test_uri },
|
||||
.position = offsets.indexToPosition(source, cursor_idx, ctx.server.offset_encoding),
|
||||
},
|
||||
const params = types.CompletionParams{
|
||||
.textDocument = .{ .uri = test_uri },
|
||||
.position = offsets.indexToPosition(source, cursor_idx, ctx.server.offset_encoding),
|
||||
};
|
||||
|
||||
@setEvalBranchQuota(2000);
|
||||
const response = try ctx.requestGetResponse(?types.CompletionList, "textDocument/completion", request);
|
||||
defer response.deinit();
|
||||
@setEvalBranchQuota(5000);
|
||||
const response = try ctx.requestGetResponse(?types.CompletionList, "textDocument/completion", params);
|
||||
|
||||
const completion_list: types.CompletionList = response.result orelse {
|
||||
std.debug.print("Server returned `null` as the result\n", .{});
|
||||
@@ -462,11 +458,11 @@ fn testCompletion(source: []const u8, expected_completions: []const Completion)
|
||||
unreachable;
|
||||
};
|
||||
|
||||
if (expected_completion.kind != actual_completion.kind) {
|
||||
try error_builder.msgAtIndex("label '{s}' should be of kind '{s}' but was '{s}'!", cursor_idx, .err, .{
|
||||
if (actual_completion.kind == null or expected_completion.kind != actual_completion.kind.?) {
|
||||
try error_builder.msgAtIndex("label '{s}' should be of kind '{s}' but was '{?s}'!", cursor_idx, .err, .{
|
||||
label,
|
||||
@tagName(expected_completion.kind),
|
||||
@tagName(actual_completion.kind),
|
||||
if (actual_completion.kind) |kind| @tagName(kind) else null,
|
||||
});
|
||||
return error.InvalidCompletionKind;
|
||||
}
|
||||
@@ -500,9 +496,15 @@ fn extractCompletionLabels(items: anytype) error{ DuplicateCompletionLabel, OutO
|
||||
errdefer set.deinit(allocator);
|
||||
try set.ensureTotalCapacity(allocator, items.len);
|
||||
for (items) |item| {
|
||||
switch (item.kind) {
|
||||
.Keyword, .Snippet => continue,
|
||||
else => {},
|
||||
const maybe_kind = switch (@typeInfo(@TypeOf(item.kind))) {
|
||||
.Optional => item.kind,
|
||||
else => @as(?@TypeOf(item.kind), item.kind),
|
||||
};
|
||||
if (maybe_kind) |kind| {
|
||||
switch (kind) {
|
||||
.Keyword, .Snippet => continue,
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
if (set.fetchPutAssumeCapacity(item.label, {}) != null) return error.DuplicateCompletionLabel;
|
||||
}
|
||||
|
||||
@@ -2,10 +2,11 @@ const std = @import("std");
|
||||
const zls = @import("zls");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
const tres = @import("tres");
|
||||
|
||||
const Context = @import("../context.zig").Context;
|
||||
|
||||
const types = zls.types;
|
||||
const requests = zls.requests;
|
||||
|
||||
const allocator: std.mem.Allocator = std.testing.allocator;
|
||||
|
||||
@@ -48,15 +49,16 @@ fn testFoldingRange(source: []const u8, expect: []const u8) !void {
|
||||
|
||||
try ctx.requestDidOpen(test_uri, source);
|
||||
|
||||
const request = requests.FoldingRange{ .params = .{ .textDocument = .{ .uri = test_uri } } };
|
||||
const params = types.FoldingRangeParams{ .textDocument = .{ .uri = test_uri } };
|
||||
|
||||
const response = try ctx.requestGetResponse(?[]types.FoldingRange, "textDocument/foldingRange", request);
|
||||
defer response.deinit();
|
||||
const response = try ctx.requestGetResponse(?[]types.FoldingRange, "textDocument/foldingRange", params);
|
||||
|
||||
var actual = std.ArrayList(u8).init(allocator);
|
||||
defer actual.deinit();
|
||||
|
||||
try std.json.stringify(response.result, .{}, actual.writer());
|
||||
try tres.stringify(response.result, .{
|
||||
.emit_null_optional_fields = false,
|
||||
}, actual.writer());
|
||||
try expectEqualJson(expect, actual.items);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ const ErrorBuilder = @import("../ErrorBuilder.zig");
|
||||
|
||||
const types = zls.types;
|
||||
const offsets = zls.offsets;
|
||||
const requests = zls.requests;
|
||||
|
||||
const allocator: std.mem.Allocator = std.testing.allocator;
|
||||
|
||||
@@ -83,7 +82,7 @@ fn testInlayHints(source: []const u8) !void {
|
||||
|
||||
const range = types.Range{
|
||||
.start = types.Position{ .line = 0, .character = 0 },
|
||||
.end = offsets.indexToPosition(phr.new_source, phr.new_source.len, .utf16),
|
||||
.end = offsets.indexToPosition(phr.new_source, phr.new_source.len, .@"utf-16"),
|
||||
};
|
||||
|
||||
const InlayHint = struct {
|
||||
@@ -92,15 +91,12 @@ fn testInlayHints(source: []const u8) !void {
|
||||
kind: types.InlayHintKind,
|
||||
};
|
||||
|
||||
const request = requests.InlayHint{
|
||||
.params = .{
|
||||
.textDocument = .{ .uri = test_uri },
|
||||
.range = range,
|
||||
},
|
||||
const params = types.InlayHintParams{
|
||||
.textDocument = .{ .uri = test_uri },
|
||||
.range = range,
|
||||
};
|
||||
|
||||
const response = try ctx.requestGetResponse(?[]InlayHint, "textDocument/inlayHint", request);
|
||||
defer response.deinit();
|
||||
const response = try ctx.requestGetResponse(?[]InlayHint, "textDocument/inlayHint", params);
|
||||
|
||||
const hints: []InlayHint = response.result orelse {
|
||||
std.debug.print("Server returned `null` as the result\n", .{});
|
||||
@@ -124,7 +120,7 @@ fn testInlayHints(source: []const u8) !void {
|
||||
for (hints) |hint| {
|
||||
if (position.line != hint.position.line or position.character != hint.position.character) continue;
|
||||
|
||||
const actual_label = hint.label[0 .. hint.label.len - 1]; // exclude :
|
||||
const actual_label = hint.label[0..hint.label.len];
|
||||
|
||||
if (!std.mem.eql(u8, expected_label, actual_label)) {
|
||||
try error_builder.msgAtLoc("expected label `{s}` here but got `{s}`!", new_loc, .err, .{ expected_label, actual_label });
|
||||
|
||||
@@ -7,7 +7,6 @@ const Context = @import("../context.zig").Context;
|
||||
const ErrorBuilder = @import("../ErrorBuilder.zig");
|
||||
|
||||
const types = zls.types;
|
||||
const requests = zls.requests;
|
||||
const offsets = zls.offsets;
|
||||
|
||||
const allocator: std.mem.Allocator = std.testing.allocator;
|
||||
@@ -113,16 +112,13 @@ fn testReferences(source: []const u8) !void {
|
||||
const var_name = offsets.locToSlice(source, var_loc);
|
||||
const var_loc_middle = var_loc.start + (var_loc.end - var_loc.start) / 2;
|
||||
|
||||
const request = requests.References{
|
||||
.params = .{
|
||||
.textDocument = .{ .uri = file_uri },
|
||||
.position = offsets.indexToPosition(source, var_loc_middle, ctx.server.offset_encoding),
|
||||
.context = .{ .includeDeclaration = true },
|
||||
},
|
||||
const params = types.ReferenceParams{
|
||||
.textDocument = .{ .uri = file_uri },
|
||||
.position = offsets.indexToPosition(source, var_loc_middle, ctx.server.offset_encoding),
|
||||
.context = .{ .includeDeclaration = true },
|
||||
};
|
||||
|
||||
const response = try ctx.requestGetResponse(?[]types.Location, "textDocument/references", request);
|
||||
defer response.deinit();
|
||||
const response = try ctx.requestGetResponse(?[]types.Location, "textDocument/references", params);
|
||||
|
||||
const locations: []types.Location = response.result orelse {
|
||||
std.debug.print("Server returned `null` as the result\n", .{});
|
||||
|
||||
@@ -38,20 +38,19 @@ fn testSelectionRange(source: []const u8, want: []const []const u8) !void {
|
||||
|
||||
try ctx.requestDidOpen(test_uri, phr.new_source);
|
||||
|
||||
const position = offsets.locToRange(phr.new_source, phr.locations.items(.new)[0], .utf16).start;
|
||||
const position = offsets.locToRange(phr.new_source, phr.locations.items(.new)[0], .@"utf-16").start;
|
||||
|
||||
const SelectionRange = struct {
|
||||
range: types.Range,
|
||||
parent: ?*@This(),
|
||||
parent: ?*@This() = null,
|
||||
};
|
||||
|
||||
const request = requests.SelectionRange{ .params = .{
|
||||
const params = types.SelectionRangeParams{
|
||||
.textDocument = .{ .uri = test_uri },
|
||||
.positions = &[_]types.Position{position},
|
||||
} };
|
||||
};
|
||||
|
||||
const response = try ctx.requestGetResponse(?[]SelectionRange, "textDocument/selectionRange", request);
|
||||
defer response.deinit();
|
||||
const response = try ctx.requestGetResponse(?[]SelectionRange, "textDocument/selectionRange", params);
|
||||
|
||||
const selectionRanges: []SelectionRange = response.result orelse {
|
||||
std.debug.print("Server returned `null` as the result\n", .{});
|
||||
@@ -63,7 +62,7 @@ fn testSelectionRange(source: []const u8, want: []const []const u8) !void {
|
||||
|
||||
var it: ?*SelectionRange = &selectionRanges[0];
|
||||
while (it) |r| {
|
||||
const slice = offsets.rangeToSlice(phr.new_source, r.range, .utf16);
|
||||
const slice = offsets.rangeToSlice(phr.new_source, r.range, .@"utf-16");
|
||||
(try got.addOne()).* = slice;
|
||||
it = r.parent;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ const builtin = @import("builtin");
|
||||
|
||||
const Context = @import("../context.zig").Context;
|
||||
|
||||
const requests = zls.requests;
|
||||
const types = zls.types;
|
||||
|
||||
const allocator: std.mem.Allocator = std.testing.allocator;
|
||||
|
||||
@@ -41,21 +41,7 @@ fn testSemanticTokens(source: []const u8, expected: []const u32) !void {
|
||||
var ctx = try Context.init();
|
||||
defer ctx.deinit();
|
||||
|
||||
const open_document = requests.OpenDocument{
|
||||
.params = .{
|
||||
.textDocument = .{
|
||||
.uri = file_uri,
|
||||
// .languageId = "zig",
|
||||
// .version = 420,
|
||||
.text = source,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const did_open_method = try std.json.stringifyAlloc(allocator, open_document.params, .{});
|
||||
defer allocator.free(did_open_method);
|
||||
|
||||
try ctx.request("textDocument/didOpen", did_open_method, null);
|
||||
try ctx.requestDidOpen(file_uri, source);
|
||||
|
||||
const Response = struct {
|
||||
data: []const u32,
|
||||
|
||||
Reference in New Issue
Block a user