Skip to content

Commit 64f0139

Browse files
committed
move config option logic from Server to configuration.Manager
- cache WASI preopens - allow overriding the preopen directory for `zig_lib_path` and `global_cache_path` on WASI - refresh diagnostics if `zig_lib_path` changes - fix some cases where config options would be incorrectly resolved when multiple config sources are combined.
1 parent ac3b0a0 commit 64f0139

File tree

12 files changed

+739
-570
lines changed

12 files changed

+739
-570
lines changed

src/Server.zig

Lines changed: 116 additions & 483 deletions
Large diffs are not rendered by default.

src/configuration.zig

Lines changed: 554 additions & 7 deletions
Large diffs are not rendered by default.

src/features/completions.zig

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,8 @@ fn functionTypeCompletion(
309309

310310
const info = func_ty.data.function;
311311

312-
const use_snippets = builder.server.config.enable_snippets and builder.server.client_capabilities.supports_snippets;
312+
const config = &builder.server.config_manager.config;
313+
const use_snippets = config.enable_snippets and builder.server.client_capabilities.supports_snippets;
313314

314315
const has_self_param = if (parent_container_ty) |container_ty| blk: {
315316
if (container_ty.is_type_val) break :blk false;
@@ -322,7 +323,7 @@ fn functionTypeCompletion(
322323
const new_text = switch (new_text_format) {
323324
.only_name => func_name,
324325
.snippet => blk: {
325-
if (use_snippets and builder.server.config.enable_argument_placeholders) {
326+
if (use_snippets and config.enable_argument_placeholders) {
326327
break :blk try builder.analyser.stringifyFunction(.{
327328
.info = info,
328329
.include_fn_keyword = false,
@@ -376,7 +377,7 @@ fn functionTypeCompletion(
376377
.include_fn_keyword = false,
377378
.include_name = false,
378379
.skip_first_param = has_self_param,
379-
.parameters = if (builder.server.config.completion_label_details)
380+
.parameters = if (config.completion_label_details)
380381
.{ .show = .{
381382
.include_modifiers = true,
382383
.include_names = true,
@@ -444,7 +445,8 @@ fn completeLabel(builder: *Builder) error{OutOfMemory}!void {
444445
fn populateSnippedCompletions(builder: *Builder, snippets: []const snipped_data.Snipped) error{OutOfMemory}!void {
445446
try builder.completions.ensureUnusedCapacity(builder.arena, snippets.len);
446447

447-
const use_snippets = builder.server.config.enable_snippets and builder.server.client_capabilities.supports_snippets;
448+
const config = &builder.server.config_manager.config;
449+
const use_snippets = config.enable_snippets and builder.server.client_capabilities.supports_snippets;
448450
for (snippets) |snipped| {
449451
if (!use_snippets and snipped.kind == .Snippet) continue;
450452

@@ -464,7 +466,8 @@ const PrepareFunctionCompletionResult = struct { types.Range, types.Range, Funct
464466
fn prepareFunctionCompletion(builder: *Builder) PrepareFunctionCompletionResult {
465467
if (builder.cached_prepare_function_completion_result) |result| return result;
466468

467-
const use_snippets = builder.server.config.enable_snippets and builder.server.client_capabilities.supports_snippets;
469+
const config = &builder.server.config_manager.config;
470+
const use_snippets = config.enable_snippets and builder.server.client_capabilities.supports_snippets;
468471
const source = builder.orig_handle.tree.source;
469472

470473
var start_index = builder.source_index;
@@ -506,8 +509,9 @@ fn completeBuiltin(builder: *Builder) error{OutOfMemory}!void {
506509
const tracy_zone = tracy.trace(@src());
507510
defer tracy_zone.end();
508511

509-
const use_snippets = builder.server.config.enable_snippets and builder.server.client_capabilities.supports_snippets;
510-
const use_placeholders = use_snippets and builder.server.config.enable_argument_placeholders;
512+
const config = &builder.server.config_manager.config;
513+
const use_snippets = config.enable_snippets and builder.server.client_capabilities.supports_snippets;
514+
const use_placeholders = use_snippets and config.enable_argument_placeholders;
511515

512516
const insert_range, const replace_range, const new_text_format = prepareFunctionCompletion(builder);
513517

@@ -1377,7 +1381,8 @@ fn collectContainerFields(
13771381
const document_scope = try scope_handle.handle.getDocumentScope();
13781382
const scope_decls = document_scope.getScopeDeclarationsConst(scope_handle.scope);
13791383

1380-
const use_snippets = builder.server.config.enable_snippets and builder.server.client_capabilities.supports_snippets;
1384+
const config = &builder.server.config_manager.config;
1385+
const use_snippets = config.enable_snippets and builder.server.client_capabilities.supports_snippets;
13811386
for (scope_decls) |decl_index| {
13821387
const decl = document_scope.declarations.get(@intFromEnum(decl_index));
13831388
if (decl != .ast_node) continue;

src/features/diagnostics.zig

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ pub fn generateDiagnostics(
2626
const tracy_zone = tracy.trace(@src());
2727
defer tracy_zone.end();
2828

29+
const config = &server.config_manager.config;
30+
2931
if (handle.tree.errors.len == 0) {
3032
const tracy_zone2 = tracy.traceNamed(@src(), "ast-check");
3133
defer tracy_zone2.end();
@@ -68,11 +70,11 @@ pub fn generateDiagnostics(
6870
try code_actions.collectAutoDiscardDiagnostics(&analyser, handle, arena, &diagnostics, server.offset_encoding);
6971
}
7072

71-
if (server.config.warn_style and handle.tree.mode == .zig) {
73+
if (config.warn_style and handle.tree.mode == .zig) {
7274
try collectWarnStyleDiagnostics(handle.tree, arena, &diagnostics, server.offset_encoding);
7375
}
7476

75-
if (server.config.highlight_global_var_declarations and handle.tree.mode == .zig) {
77+
if (config.highlight_global_var_declarations and handle.tree.mode == .zig) {
7678
try collectGlobalVarDiagnostics(handle.tree, arena, &diagnostics, server.offset_encoding);
7779
}
7880

@@ -269,15 +271,16 @@ pub fn getAstCheckDiagnostics(server: *Server, handle: *DocumentStore.Handle) er
269271
defer tracy_zone.end();
270272

271273
std.debug.assert(handle.tree.errors.len == 0);
274+
const config = &server.config_manager.config;
272275

273276
if (std.process.can_spawn and
274-
server.config.prefer_ast_check_as_child_process and
277+
config.prefer_ast_check_as_child_process and
275278
handle.tree.mode == .zig and // TODO pass `--zon` if available
276-
server.config.zig_exe_path != null)
279+
config.zig_exe_path != null)
277280
{
278281
return getErrorBundleFromAstCheck(
279282
server.allocator,
280-
server.config.zig_exe_path.?,
283+
config.zig_exe_path.?,
281284
&server.zig_ast_check_lock,
282285
handle.tree.source,
283286
) catch |err| {

src/features/references.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -699,7 +699,7 @@ pub fn referencesHandler(server: *Server, arena: std.mem.Allocator, request: Gen
699699
decl,
700700
server.offset_encoding,
701701
include_decl,
702-
server.config.skip_std_references,
702+
server.config_manager.config.skip_std_references,
703703
handle,
704704
),
705705
};

src/main.zig

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ fn loadConfiguration(
404404
config.global_cache_path = try std.fs.path.join(config_arena.allocator(), &.{ cache_dir_path, "zls" });
405405
}
406406

407-
try server.updateConfiguration2(&config, .{ .resolve = false });
407+
try server.config_manager.setConfiguration2(server.allocator, .frontend, &config);
408408
}
409409

410410
const ParseArgsResult = struct {
@@ -546,9 +546,12 @@ pub fn main() !u8 {
546546
log.info("Log File: none", .{});
547547
}
548548

549-
const server = try zls.Server.create(allocator);
549+
const server: *zls.Server = try .create(.{
550+
.allocator = allocator,
551+
.transport = transport,
552+
.config = null,
553+
});
550554
defer server.destroy();
551-
server.setTransport(transport);
552555

553556
try loadConfiguration(allocator, server, result.config_path);
554557

tests/context.zig

Lines changed: 22 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,27 @@ const zls = @import("zls");
33
const builtin = @import("builtin");
44
const test_options = @import("test_options");
55

6-
const Config = zls.Config;
7-
const Server = zls.Server;
86
const types = zls.lsp.types;
97

108
const allocator = std.testing.allocator;
119

12-
const default_config: Config = .{
10+
const default_config: zls.configuration.UnresolvedConfig = .{
1311
.semantic_tokens = .full,
1412
.prefer_ast_check_as_child_process = false,
1513
.inlay_hints_exclude_single_argument = false,
1614
.inlay_hints_show_builtin = true,
1715
};
1816

1917
pub const Context = struct {
20-
server: *Server,
18+
server: *zls.Server,
2119
arena: std.heap.ArenaAllocator,
2220
file_id: u32 = 0,
2321

24-
var config_arena: std.heap.ArenaAllocator.State = .{};
25-
var cached_config: ?Config = null;
26-
var cached_resolved_config: ?@FieldType(Server, "resolved_config") = null;
22+
var cached_config_arena: std.heap.ArenaAllocator = .init(std.heap.page_allocator);
23+
var cached_config_manager: ?zls.configuration.Manager = null;
2724

2825
pub fn init() !Context {
29-
const server = try Server.create(allocator);
30-
errdefer server.destroy();
31-
32-
if (cached_config == null and cached_resolved_config == null) {
26+
const config_manager = cached_config_manager orelse config_manager: {
3327
var config = default_config;
3428
defer if (builtin.target.os.tag != .wasi) {
3529
if (config.zig_exe_path) |zig_exe_path| allocator.free(zig_exe_path);
@@ -44,19 +38,25 @@ pub const Context = struct {
4438
config.global_cache_path = try std.fs.path.resolve(allocator, &.{ cwd, test_options.global_cache_path });
4539
}
4640

47-
try server.updateConfiguration2(config, .{ .leaky_config_arena = true });
48-
} else {
49-
// the configuration has previously been resolved and cached.
50-
server.config_arena = config_arena;
51-
server.config = cached_config.?;
52-
server.resolved_config = cached_resolved_config.?;
41+
var config_manager: zls.configuration.Manager = .init;
42+
try config_manager.setConfiguration(cached_config_arena.allocator(), .frontend, &config);
43+
_ = try config_manager.resolveConfiguration(cached_config_arena.allocator());
44+
cached_config_manager = config_manager;
45+
break :config_manager config_manager;
46+
};
5347

54-
try server.updateConfiguration2(server.config, .{ .leaky_config_arena = true, .resolve = false });
55-
}
48+
const server: *zls.Server = try .create(.{
49+
.allocator = allocator,
50+
.transport = null,
51+
.config = null,
52+
.config_manager = config_manager,
53+
});
54+
errdefer server.destroy();
5655

57-
std.debug.assert(server.resolved_config.zig_lib_dir != null);
56+
std.debug.assert(server.config_manager.zig_lib_dir != null);
5857
std.debug.assert(server.document_store.config.zig_lib_dir != null);
59-
std.debug.assert(server.resolved_config.global_cache_dir != null);
58+
59+
std.debug.assert(server.config_manager.global_cache_dir != null);
6060
std.debug.assert(server.document_store.config.global_cache_dir != null);
6161

6262
var context: Context = .{
@@ -71,13 +71,7 @@ pub const Context = struct {
7171
}
7272

7373
pub fn deinit(self: *Context) void {
74-
config_arena = self.server.config_arena;
75-
cached_config = self.server.config;
76-
cached_resolved_config = self.server.resolved_config;
77-
78-
self.server.config_arena = .{};
79-
self.server.config = .{};
80-
self.server.resolved_config = .unresolved;
74+
self.server.config_manager = .init;
8175

8276
_ = self.server.sendRequestSync(self.arena.allocator(), "shutdown", {}) catch unreachable;
8377
self.server.sendNotificationSync(self.arena.allocator(), "exit", {}) catch unreachable;

tests/lifecycle.zig

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,13 @@ const test_options = @import("test_options");
66
const allocator = std.testing.allocator;
77

88
test "LSP lifecycle" {
9-
var server = try zls.Server.create(allocator);
9+
var server: *zls.Server = try .create(.{
10+
.allocator = allocator,
11+
.transport = null,
12+
.config = null,
13+
});
1014
defer server.destroy();
1115

12-
var zig_exe_path: ?[]const u8 = null;
13-
var global_cache_path: ?[]const u8 = null;
14-
15-
defer if (builtin.target.os.tag != .wasi) {
16-
if (zig_exe_path) |path| allocator.free(path);
17-
if (global_cache_path) |path| allocator.free(path);
18-
};
19-
if (builtin.target.os.tag != .wasi) {
20-
const cwd = try std.process.getCwdAlloc(allocator);
21-
defer allocator.free(cwd);
22-
zig_exe_path = try std.fs.path.resolve(allocator, &.{ cwd, test_options.zig_exe_path });
23-
global_cache_path = try std.fs.path.resolve(allocator, &.{ cwd, test_options.global_cache_path });
24-
}
25-
26-
try server.updateConfiguration2(.{
27-
.zig_exe_path = zig_exe_path,
28-
.zig_lib_path = null,
29-
.global_cache_path = global_cache_path,
30-
}, .{});
31-
3216
var arena_allocator: std.heap.ArenaAllocator = .init(allocator);
3317
defer arena_allocator.deinit();
3418
const arena = arena_allocator.allocator();

tests/lsp_features/code_actions.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -935,7 +935,7 @@ fn testDiagnostic(
935935
) !void {
936936
var ctx: Context = try .init();
937937
defer ctx.deinit();
938-
ctx.server.config.prefer_ast_check_as_child_process = !options.want_zir;
938+
ctx.server.config_manager.config.prefer_ast_check_as_child_process = !options.want_zir;
939939

940940
var phr = try helper.collectClearPlaceholders(allocator, before);
941941
defer phr.deinit(allocator);

tests/lsp_features/completion.zig

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4275,9 +4275,9 @@ fn testCompletionWithOptions(
42754275
ctx.server.client_capabilities.supports_completion_deprecated_old = true;
42764276
ctx.server.client_capabilities.supports_completion_deprecated_tag = true;
42774277

4278-
ctx.server.config.enable_argument_placeholders = options.enable_argument_placeholders;
4279-
ctx.server.config.enable_snippets = options.enable_snippets;
4280-
ctx.server.config.completion_label_details = options.completion_label_details;
4278+
ctx.server.config_manager.config.enable_argument_placeholders = options.enable_argument_placeholders;
4279+
ctx.server.config_manager.config.enable_snippets = options.enable_snippets;
4280+
ctx.server.config_manager.config.completion_label_details = options.completion_label_details;
42814281

42824282
const test_uri = try ctx.addDocument(.{ .source = text });
42834283

@@ -4512,8 +4512,8 @@ fn testCompletionTextEdit(
45124512

45134513
ctx.server.client_capabilities.supports_snippets = true;
45144514

4515-
ctx.server.config.enable_argument_placeholders = options.enable_argument_placeholders;
4516-
ctx.server.config.enable_snippets = options.enable_snippets;
4515+
ctx.server.config_manager.config.enable_argument_placeholders = options.enable_argument_placeholders;
4516+
ctx.server.config_manager.config.enable_snippets = options.enable_snippets;
45174517

45184518
const test_uri = try ctx.addDocument(.{ .source = text });
45194519
const handle = ctx.server.document_store.getHandle(test_uri).?;

0 commit comments

Comments
 (0)