Configuration handling fixes (#995)

* Fortify `server.handleConfiguration`.
* Move call to `server.registerCapability` within `server.initializedHandler`(was being sent prematurely).
This commit is contained in:
nullptrdevs 2023-02-13 14:59:06 -08:00 committed by GitHub
parent 409c203317
commit b28d3aadd7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -69,6 +69,7 @@ const ClientCapabilities = packed struct {
completion_doc_supports_md: bool = false, completion_doc_supports_md: bool = false,
label_details_support: bool = false, label_details_support: bool = false,
supports_configuration: bool = false, supports_configuration: bool = false,
supports_workspace_did_change_configuration_dynamic_registration: bool = false,
}; };
pub const Error = std.mem.Allocator.Error || error{ pub const Error = std.mem.Allocator.Error || error{
@ -1853,7 +1854,7 @@ fn initializeHandler(server: *Server, request: types.InitializeParams) Error!typ
server.client_capabilities.supports_configuration = workspace.configuration orelse false; server.client_capabilities.supports_configuration = workspace.configuration orelse false;
if (workspace.didChangeConfiguration) |did_change| { if (workspace.didChangeConfiguration) |did_change| {
if (did_change.dynamicRegistration orelse false) { if (did_change.dynamicRegistration orelse false) {
try server.registerCapability("workspace/didChangeConfiguration"); server.client_capabilities.supports_workspace_did_change_configuration_dynamic_registration = true;
} }
} }
} }
@ -1995,6 +1996,10 @@ fn initializedHandler(server: *Server, notification: types.InitializedParams) Er
server.status = .initialized; server.status = .initialized;
if (server.client_capabilities.supports_workspace_did_change_configuration_dynamic_registration) {
try server.registerCapability("workspace/didChangeConfiguration");
}
if (server.client_capabilities.supports_configuration) if (server.client_capabilities.supports_configuration)
try server.requestConfiguration(); try server.requestConfiguration();
} }
@ -2090,27 +2095,37 @@ fn handleConfiguration(server: *Server, json: std.json.Value) error{OutOfMemory}
const new_value: field.type = switch (ft) { const new_value: field.type = switch (ft) {
[]const u8 => switch (value) { []const u8 => switch (value) {
.String => |s| blk: { .String => |s| blk: {
if (s.len == 0) { const trimmed = std.mem.trim(u8, s, " ");
if (field.type == ?[]const u8) { if (trimmed.len == 0 or std.mem.eql(u8, trimmed, "nil")) {
break :blk null; log.warn("Ignoring new value for \"zls.{s}\": the given new value is invalid", .{field.name});
} else { break :blk @field(server.config, field.name);
break :blk s;
} }
} var nv = try server.allocator.dupe(u8, trimmed);
var nv = try server.allocator.dupe(u8, s);
if (@field(server.config, field.name)) |prev_val| server.allocator.free(prev_val); if (@field(server.config, field.name)) |prev_val| server.allocator.free(prev_val);
break :blk nv; break :blk nv;
}, // TODO: Allocation model? (same with didChangeConfiguration); imo this isn't *that* bad but still },
else => @panic("Invalid configuration value"), // TODO: Handle this else => blk: {
log.warn("Ignoring new value for \"zls.{s}\": the given new value has an invalid type", .{field.name});
break :blk @field(server.config, field.name);
},
}, },
else => switch (ti) { else => switch (ti) {
.Int => switch (value) { .Int => switch (value) {
.Integer => |s| std.math.cast(ft, s) orelse @panic("Invalid configuration value"), .Integer => |val| std.math.cast(ft, val) orelse blk: {
else => @panic("Invalid configuration value"), // TODO: Handle this log.warn("Ignoring new value for \"zls.{s}\": the given new value is invalid", .{field.name});
break :blk @field(server.config, field.name);
},
else => blk: {
log.warn("Ignoring new value for \"zls.{s}\": the given new value has an invalid type", .{field.name});
break :blk @field(server.config, field.name);
},
}, },
.Bool => switch (value) { .Bool => switch (value) {
.Bool => |b| b, .Bool => |b| b,
else => @panic("Invalid configuration value"), // TODO: Handle this else => blk: {
log.warn("Ignoring new value for \"zls.{s}\": the given new value has an invalid type", .{field.name});
break :blk @field(server.config, field.name);
},
}, },
else => @compileError("Not implemented for " ++ @typeName(ft)), else => @compileError("Not implemented for " ++ @typeName(ft)),
}, },
@ -2941,7 +2956,12 @@ fn processMessage(server: *Server, message: Message) Error!void {
}, },
.ResponseMessage => |response| { .ResponseMessage => |response| {
if (response.id != .string) return; if (response.id != .string) return;
if (std.mem.startsWith(u8, response.id.string, "register")) return; if (std.mem.startsWith(u8, response.id.string, "register")) {
if (response.@"error") |err| {
log.err("Error response for '{s}': {}, {s}", .{ response.id.string, err.code, err.message });
}
return;
}
if (std.mem.eql(u8, response.id.string, "apply_edit")) return; if (std.mem.eql(u8, response.id.string, "apply_edit")) return;
if (std.mem.eql(u8, response.id.string, "i_haz_configuration")) { if (std.mem.eql(u8, response.id.string, "i_haz_configuration")) {