@@ -615,9 +615,7 @@ fn initializedHandler(server: *Server, arena: std.mem.Allocator, notification: t
615615
616616 server .status = .initialized ;
617617
618- if (server .client_capabilities .supports_configuration and
619- server .client_capabilities .supports_workspace_did_change_configuration_dynamic_registration )
620- {
618+ if (server .client_capabilities .supports_workspace_did_change_configuration_dynamic_registration ) {
621619 try server .registerCapability ("workspace/didChangeConfiguration" , null );
622620 }
623621
@@ -677,15 +675,25 @@ fn registerCapability(server: *Server, method: []const u8, registersOptions: ?ty
677675 server .allocator .free (json_message );
678676}
679677
680- /// Request configuration options with the `workspace/configuration` request.
681678fn requestConfiguration (server : * Server ) Error ! void {
682- const configuration_items : [1 ]types.ConfigurationItem = .{
683- .{
684- .section = "zls" ,
685- .scopeUri = if (server .workspaces .items .len == 1 ) server .workspaces .items [0 ].uri else null ,
686- },
679+ var configuration_items = comptime config : {
680+ var comp_config : [std .meta .fields (Config ).len ]types.ConfigurationItem = undefined ;
681+ for (std .meta .fields (Config ), 0.. ) | field , index | {
682+ comp_config [index ] = .{
683+ .section = "zls." ++ field .name ,
684+ };
685+ }
686+
687+ break :config comp_config ;
687688 };
688689
690+ if (server .workspaces .items .len == 1 ) {
691+ const workspace = server .workspaces .items [0 ];
692+ for (& configuration_items ) | * item | {
693+ item .* .scopeUri = workspace .uri ;
694+ }
695+ }
696+
689697 const json_message = try server .sendToClientRequest (
690698 .{ .string = "i_haz_configuration" },
691699 "workspace/configuration" ,
@@ -696,28 +704,18 @@ fn requestConfiguration(server: *Server) Error!void {
696704 server .allocator .free (json_message );
697705}
698706
699- /// Handle the response of the `workspace/configuration` request.
700707fn handleConfiguration (server : * Server , json : std.json.Value ) error {OutOfMemory }! void {
701708 const tracy_zone = tracy .trace (@src ());
702709 defer tracy_zone .end ();
703710
704- const result : std.json.Value = switch (json ) {
705- .array = > | arr | blk : {
706- if (arr .items .len != 1 ) {
707- log .err ("Response to 'workspace/configuration' expects an array of size 1 but received {d}" , .{arr .items .len });
708- return ;
709- }
710- break :blk switch (arr .items [0 ]) {
711- .object = > arr .items [0 ],
712- .null = > return ,
713- else = > {
714- log .err ("Response to 'workspace/configuration' expects an array of objects but got an array of {t}." , .{json });
715- return ;
716- },
717- };
711+ const fields = std .meta .fields (configuration .Configuration );
712+ const result = switch (json ) {
713+ .array = > | arr | if (arr .items .len == fields .len ) arr .items else {
714+ log .err ("workspace/configuration expects an array of size {d} but received {d}" , .{ fields .len , arr .items .len });
715+ return ;
718716 },
719717 else = > {
720- log .err ("Response to ' workspace/configuration' expects an array but received {t}" , .{json });
718+ log .err ("workspace/configuration expects an array but received {t}" , .{json });
721719 return ;
722720 },
723721 };
@@ -726,15 +724,20 @@ fn handleConfiguration(server: *Server, json: std.json.Value) error{OutOfMemory}
726724 defer arena_allocator .deinit ();
727725 const arena = arena_allocator .allocator ();
728726
729- var new_config = std .json .parseFromValueLeaky (
730- configuration .Configuration ,
731- arena ,
732- result ,
733- .{ .ignore_unknown_fields = true },
734- ) catch | err | {
735- log .err ("Failed to parse response from 'workspace/configuration': {}" , .{err });
736- return ;
737- };
727+ var new_config : configuration.Configuration = .{};
728+
729+ inline for (fields , result ) | field , json_value | {
730+ var runtime_known_field_name : []const u8 = "" ; // avoid unnecessary function instantiations of `std.Io.Writer.print`
731+ runtime_known_field_name = field .name ;
732+
733+ const maybe_new_value = std .json .parseFromValueLeaky (field .type , arena , json_value , .{}) catch | err | blk : {
734+ log .err ("failed to parse configuration option '{s}': {}" , .{ runtime_known_field_name , err });
735+ break :blk null ;
736+ };
737+ if (maybe_new_value ) | new_value | {
738+ @field (new_config , field .name ) = new_value ;
739+ }
740+ }
738741
739742 const maybe_root_dir : ? []const u8 = if (server .workspaces .items .len == 1 ) dir : {
740743 const uri = std .Uri .parse (server .workspaces .items [0 ].uri ) catch | err | {
@@ -943,26 +946,13 @@ fn didChangeWorkspaceFoldersHandler(server: *Server, arena: std.mem.Allocator, n
943946fn didChangeConfigurationHandler (server : * Server , arena : std.mem.Allocator , notification : types.DidChangeConfigurationParams ) Error ! void {
944947 const settings = switch (notification .settings ) {
945948 .null = > {
946- if (server .client_capabilities .supports_configuration and
947- server .client_capabilities .supports_workspace_did_change_configuration_dynamic_registration )
948- {
949- // The client has informed us that the configuration options have
950- // changed. The will request them with `workspace/configuration`.
949+ if (server .client_capabilities .supports_configuration ) {
951950 try server .requestConfiguration ();
952951 }
953952 return ;
954953 },
955- .object = > | object | blk : {
956- if (server .client_capabilities .supports_configuration and
957- server .client_capabilities .supports_workspace_did_change_configuration_dynamic_registration )
958- {
959- log .debug ("Ignoring 'workspace/didChangeConfiguration' notification in favor of 'workspace/configuration'" , .{});
960- try server .requestConfiguration ();
961- return ;
962- }
963- break :blk object .get ("zls" ) orelse notification .settings ;
964- },
965- else = > notification .settings , // We will definitely fail to parse this
954+ .object = > | object | object .get ("zls" ) orelse notification .settings ,
955+ else = > notification .settings ,
966956 };
967957
968958 const new_config = std .json .parseFromValueLeaky (
0 commit comments