Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 51 additions & 41 deletions src/Server.zig
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,9 @@ fn initializedHandler(server: *Server, arena: std.mem.Allocator, notification: t

server.status = .initialized;

if (server.client_capabilities.supports_workspace_did_change_configuration_dynamic_registration) {
if (server.client_capabilities.supports_configuration and
server.client_capabilities.supports_workspace_did_change_configuration_dynamic_registration)
{
try server.registerCapability("workspace/didChangeConfiguration", null);
}

Expand Down Expand Up @@ -690,25 +692,15 @@ fn registerCapability(server: *Server, method: []const u8, registersOptions: ?ty
server.allocator.free(json_message);
}

/// Request configuration options with the `workspace/configuration` request.
fn requestConfiguration(server: *Server) Error!void {
var configuration_items = comptime config: {
var comp_config: [std.meta.fields(Config).len]types.ConfigurationItem = undefined;
for (std.meta.fields(Config), 0..) |field, index| {
comp_config[index] = .{
.section = "zls." ++ field.name,
};
}

break :config comp_config;
const configuration_items: [1]types.ConfigurationItem = .{
.{
.section = "zls",
.scopeUri = if (server.workspaces.items.len == 1) server.workspaces.items[0].uri else null,
},
};

if (server.workspaces.items.len == 1) {
const workspace = server.workspaces.items[0];
for (&configuration_items) |*item| {
item.*.scopeUri = workspace.uri;
}
}

const json_message = try server.sendToClientRequest(
.{ .string = "i_haz_configuration" },
"workspace/configuration",
Expand All @@ -719,18 +711,28 @@ fn requestConfiguration(server: *Server) Error!void {
server.allocator.free(json_message);
}

/// Handle the response of the `workspace/configuration` request.
fn handleConfiguration(server: *Server, json: std.json.Value) error{OutOfMemory}!void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();

const fields = std.meta.fields(configuration.Configuration);
const result = switch (json) {
.array => |arr| if (arr.items.len == fields.len) arr.items else {
log.err("workspace/configuration expects an array of size {d} but received {d}", .{ fields.len, arr.items.len });
return;
const result: std.json.Value = switch (json) {
.array => |arr| blk: {
if (arr.items.len != 1) {
log.err("Response to 'workspace/configuration' expects an array of size 1 but received {d}", .{arr.items.len});
return;
}
break :blk switch (arr.items[0]) {
.object => arr.items[0],
.null => return,
else => {
log.err("Response to 'workspace/configuration' expects an array of objects but got an array of {t}.", .{json});
return;
},
};
},
else => {
log.err("workspace/configuration expects an array but received {t}", .{json});
log.err("Response to 'workspace/configuration' expects an array but received {t}", .{json});
return;
},
};
Expand All @@ -739,20 +741,15 @@ fn handleConfiguration(server: *Server, json: std.json.Value) error{OutOfMemory}
defer arena_allocator.deinit();
const arena = arena_allocator.allocator();

var new_config: configuration.Configuration = .{};

inline for (fields, result) |field, json_value| {
var runtime_known_field_name: []const u8 = ""; // avoid unnecessary function instantiations of `std.Io.Writer.print`
runtime_known_field_name = field.name;

const maybe_new_value = std.json.parseFromValueLeaky(field.type, arena, json_value, .{}) catch |err| blk: {
log.err("failed to parse configuration option '{s}': {}", .{ runtime_known_field_name, err });
break :blk null;
};
if (maybe_new_value) |new_value| {
@field(new_config, field.name) = new_value;
}
}
var new_config = std.json.parseFromValueLeaky(
configuration.Configuration,
arena,
result,
.{ .ignore_unknown_fields = true },
) catch |err| {
log.err("Failed to parse response from 'workspace/configuration': {}", .{err});
return;
};

const maybe_root_dir: ?[]const u8 = if (server.workspaces.items.len == 1) dir: {
const uri = std.Uri.parse(server.workspaces.items[0].uri) catch |err| {
Expand Down Expand Up @@ -781,7 +778,7 @@ fn handleConfiguration(server: *Server, json: std.json.Value) error{OutOfMemory}
break :check_relative;
};

const absolute = try std.fs.path.join(arena, &.{
const absolute = try std.fs.path.resolve(arena, &.{
root_dir, maybe_relative,
});

Expand Down Expand Up @@ -961,13 +958,26 @@ fn didChangeWorkspaceFoldersHandler(server: *Server, arena: std.mem.Allocator, n
fn didChangeConfigurationHandler(server: *Server, arena: std.mem.Allocator, notification: types.DidChangeConfigurationParams) Error!void {
const settings = switch (notification.settings) {
.null => {
if (server.client_capabilities.supports_configuration) {
if (server.client_capabilities.supports_configuration and
server.client_capabilities.supports_workspace_did_change_configuration_dynamic_registration)
{
// The client has informed us that the configuration options have
// changed. The will request them with `workspace/configuration`.
try server.requestConfiguration();
}
return;
},
.object => |object| object.get("zls") orelse notification.settings,
else => notification.settings,
.object => |object| blk: {
if (server.client_capabilities.supports_configuration and
server.client_capabilities.supports_workspace_did_change_configuration_dynamic_registration)
{
log.debug("Ignoring 'workspace/didChangeConfiguration' notification in favor of 'workspace/configuration'", .{});
try server.requestConfiguration();
return;
}
break :blk object.get("zls") orelse notification.settings;
},
else => notification.settings, // We will definitely fail to parse this
};

const new_config = std.json.parseFromValueLeaky(
Expand Down
Loading