From 527e6d4d249e50a65da130bae1fa8b28e6a61753 Mon Sep 17 00:00:00 2001 From: Techatrix Date: Sun, 16 Nov 2025 13:14:18 +0100 Subject: [PATCH 1/4] update to the new Io interface --- build.zig.zon | 12 ++++---- deps.nix | 18 +++++------ src/DocumentStore.zig | 2 ++ src/Server.zig | 7 +++++ src/build_runner/build_runner.zig | 30 ++++++++++++------ src/diff.zig | 2 +- src/features/diagnostics.zig | 33 ++++++++++---------- src/main.zig | 48 ++++++++++++++++------------- src/snippets.zig | 4 +-- src/translate_c.zig | 7 +++-- tests/analysis_check.zig | 5 +++ tests/context.zig | 2 ++ tests/language_features/cimport.zig | 2 ++ tests/lifecycle.zig | 2 ++ tests/lsp_features/completion.zig | 2 +- 15 files changed, 107 insertions(+), 69 deletions(-) diff --git a/build.zig.zon b/build.zig.zon index 598c61d87..44e68337a 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -19,16 +19,16 @@ // The `deps.nix` should also be updated to not fetch `tracy`. .dependencies = .{ .known_folders = .{ - .url = "https://github.com/ziglibs/known-folders/archive/92defaee76b07487769ca352fd0ba95bc8b42a2f.tar.gz", - .hash = "known_folders-0.0.0-Fy-PJkfRAAAVdptXWXBspIIC7EkVgLgWozU5zIk5Zgcy", + .url = "https://github.com/ziglibs/known-folders/archive/bafef170a73c064dc706fcfbdc2e406a35681a9c.tar.gz", + .hash = "known_folders-0.0.0-Fy-PJovNAAAtqbaXgBhV6G-Z4-WNo7P0Rov-x-npZq21", }, .diffz = .{ - .url = "https://github.com/ziglibs/diffz/archive/a20dd1f11b10819a6f570f98b42e1c91e3704357.tar.gz", - .hash = "diffz-0.0.1-G2tlIQrOAQCfH15jdyaLyrMgV8eGPouFhkCeYFTmJaLk", + .url = "https://github.com/ziglibs/diffz/archive/36fc805f459677093c93c210e8f9aed28be13847.tar.gz", + .hash = "diffz-0.0.1-G2tlIWTPAQAvAIoMPQjGnqr9NlOGV8ETeDELVd9pwlwO", }, .lsp_kit = .{ - .url = "https://github.com/zigtools/lsp-kit/archive/fe98e895ca3bd1b39965ab30f0f252f7b7e83ee6.tar.gz", - .hash = "lsp_kit-0.1.0-bi_PLzAyCgClDh8_M0U9Q50ysdsQBuRuBTZfwg6rZPd6", + .url = "https://github.com/zigtools/lsp-kit/archive/c46ac866dda11ab58e4ba71ed0d8ba21f43e81db.tar.gz", + .hash = "lsp_kit-0.1.0-bi_PL98yCgBfW3T4iLkfV5VOXc__pOpOsQsX1tRmpqAG", }, .tracy = .{ .url = "https://github.com/wolfpld/tracy/archive/refs/tags/v0.11.1.tar.gz", diff --git a/deps.nix b/deps.nix index 068847ba6..361dcc7c3 100644 --- a/deps.nix +++ b/deps.nix @@ -4,24 +4,24 @@ linkFarm "zig-packages" [ { - name = "diffz-0.0.1-G2tlIQrOAQCfH15jdyaLyrMgV8eGPouFhkCeYFTmJaLk"; + name = "diffz-0.0.1-G2tlIWTPAQAvAIoMPQjGnqr9NlOGV8ETeDELVd9pwlwO"; path = fetchzip { - url = "https://github.com/ziglibs/diffz/archive/a20dd1f11b10819a6f570f98b42e1c91e3704357.tar.gz"; - hash = "sha256-y7Ck5XZNnHxmPPWlDAqZZ2g3n67txj5/Zq04AhuW5+M="; + url = "https://github.com/ziglibs/diffz/archive/36fc805f459677093c93c210e8f9aed28be13847.tar.gz"; + hash = "sha256-Z6LWUU3W3OaiNN5FysjlQOHB+eezOndjXFvz8jlHqpg="; }; } { - name = "known_folders-0.0.0-Fy-PJkfRAAAVdptXWXBspIIC7EkVgLgWozU5zIk5Zgcy"; + name = "known_folders-0.0.0-Fy-PJovNAAAtqbaXgBhV6G-Z4-WNo7P0Rov-x-npZq21"; path = fetchzip { - url = "https://github.com/ziglibs/known-folders/archive/92defaee76b07487769ca352fd0ba95bc8b42a2f.tar.gz"; - hash = "sha256-+FviMdQGeHn2ymfXjIQPxLPx3haPy5zhPJuS3Ow8m68="; + url = "https://github.com/ziglibs/known-folders/archive/bafef170a73c064dc706fcfbdc2e406a35681a9c.tar.gz"; + hash = "sha256-zn152a/Ripd1NE8bm9/6R5Y9IGIEBdNmz+Kzp+/54Gc="; }; } { - name = "lsp_kit-0.1.0-bi_PLzAyCgClDh8_M0U9Q50ysdsQBuRuBTZfwg6rZPd6"; + name = "lsp_kit-0.1.0-bi_PL98yCgBfW3T4iLkfV5VOXc__pOpOsQsX1tRmpqAG"; path = fetchzip { - url = "https://github.com/zigtools/lsp-kit/archive/fe98e895ca3bd1b39965ab30f0f252f7b7e83ee6.tar.gz"; - hash = "sha256-1HW8kWhfpbBihzE6PiXXxGN03qIW20KCsBoyfSSWgNU="; + url = "https://github.com/zigtools/lsp-kit/archive/c46ac866dda11ab58e4ba71ed0d8ba21f43e81db.tar.gz"; + hash = "sha256-FQ1l2ie50QNuLSUrEyFwrfab1tL4H+lDBe5K7SYJ6kM="; }; } ] diff --git a/src/DocumentStore.zig b/src/DocumentStore.zig index e076caf76..e1d5b4b55 100644 --- a/src/DocumentStore.zig +++ b/src/DocumentStore.zig @@ -17,6 +17,7 @@ const DiagnosticsCollection = @import("DiagnosticsCollection.zig"); const DocumentStore = @This(); +io: std.Io, allocator: std.mem.Allocator, /// the DocumentStore assumes that `config` is not modified while calling one of its functions. config: Config, @@ -1594,6 +1595,7 @@ pub fn resolveCImport(self: *DocumentStore, handle: *Handle, node: Ast.Node.Inde }; const maybe_result = translate_c.translate( + self.io, self.allocator, self.config, include_dirs.items, diff --git a/src/Server.zig b/src/Server.zig index a6740c1a0..09fe1927f 100644 --- a/src/Server.zig +++ b/src/Server.zig @@ -41,6 +41,7 @@ const BuildOnSaveSupport = build_runner_shared.BuildOnSaveSupport; const log = std.log.scoped(.server); // public fields +io: std.Io, allocator: std.mem.Allocator, config_manager: configuration.Manager, document_store: DocumentStore, @@ -833,6 +834,7 @@ const Workspace = struct { std.debug.assert(workspace.build_on_save == null); workspace.build_on_save = BuildOnSave.init(.{ + .io = args.server.io, .allocator = args.server.allocator, .workspace_path = workspace_path, .build_on_save_args = config.build_on_save_args, @@ -1662,6 +1664,8 @@ fn isBlockingMessage(msg: Message) bool { } pub const CreateOptions = struct { + /// Must support `concurrent` unless the ZLS module is in single_threaded mode. + io: std.Io, /// Must be thread-safe unless the ZLS module is in single_threaded mode. allocator: std.mem.Allocator, /// Must be set when running `loop`. Controls how the server will send and receive messages. @@ -1677,14 +1681,17 @@ pub fn create(options: CreateOptions) (std.mem.Allocator.Error || std.Thread.Spa defer tracy_zone.end(); const allocator = options.allocator; + const io = options.io; const server = try allocator.create(Server); errdefer allocator.destroy(server); server.* = .{ + .io = io, .allocator = allocator, .config_manager = options.config_manager orelse .init(allocator), .document_store = .{ + .io = io, .allocator = allocator, .config = undefined, // set below .thread_pool = &server.thread_pool, diff --git a/src/build_runner/build_runner.zig b/src/build_runner/build_runner.zig index b9605c826..70f782c44 100644 --- a/src/build_runner/build_runner.zig +++ b/src/build_runner/build_runner.zig @@ -28,6 +28,12 @@ const Allocator = std.mem.Allocator; pub const dependencies = @import("@dependencies"); +pub const std_options: std.Options = .{ + .side_channels_mitigations = .none, + .http_disable_tls = true, + .crypto_fork_safety = false, +}; + ///! This is a modified build runner to extract information out of build.zig ///! Modified version of lib/build_runner.zig pub fn main() !void { @@ -44,6 +50,10 @@ pub fn main() !void { const args = try process.argsAlloc(arena); + var threaded = if (@hasDecl(std.Io, "Threaded")) std.Io.Threaded.init(arena) else {}; + defer if (@TypeOf(threaded) != void) threaded.deinit(); + const io = if (@TypeOf(threaded) != void) threaded.io() else {}; + // skip my own exe name var arg_idx: usize = 1; @@ -74,8 +84,10 @@ pub fn main() !void { }; var graph = structInitIgnoreUnknown(std.Build.Graph, .{ + .io = io, .arena = arena, .cache = .{ + .io = io, .gpa = arena, .manifest_dir = try local_cache_directory.handle.makeOpenPath("h", .{}), }, @@ -85,7 +97,10 @@ pub fn main() !void { .zig_lib_directory = zig_lib_directory, .host = .{ .query = .{}, - .result = try std.zig.system.resolveTargetQuery(.{}), + .result = if (@TypeOf(io) != void) + try std.zig.system.resolveTargetQuery(io, .{}) + else + try std.zig.system.resolveTargetQuery(.{}), }, .time_report = false, }); @@ -385,13 +400,9 @@ pub fn main() !void { fn do(ww: *Watch) void { while (true) { var buffer: [1]u8 = undefined; - var file_reader = std.fs.File.stdin().reader(&buffer); - const reader = &file_reader.interface; - const byte = reader.takeByte() catch |err| switch (err) { - error.EndOfStream => process.exit(0), - else => process.exit(1), - }; - switch (byte) { + const amt = std.fs.File.stdin().read(&buffer) catch process.exit(1); + if (amt == 0) process.exit(0); + switch (buffer[0]) { '\x00' => ww.trigger(), else => process.exit(1), } @@ -470,7 +481,7 @@ const Watch = struct { return .{ .fs_watch = if (@TypeOf(std.Build.Watch) != void) try std.Build.Watch.init() else {}, .supports_fs_watch = @TypeOf(std.Build.Watch) != void and shared.BuildOnSaveSupport.isSupportedRuntime(builtin.zig_version) == .supported, - .manual_event = .{}, + .manual_event = if (@hasField(std.Thread.ResetEvent, "unset")) .unset else .{}, .steps = &.{}, }; } @@ -757,6 +768,7 @@ fn workerMakeOneStep( .watch = true, .gpa = gpa, .web_server = null, + .ttyconf = .no_color, .unit_test_timeout_ns = null, })); diff --git a/src/diff.zig b/src/diff.zig index 901c19b30..6c5e12933 100644 --- a/src/diff.zig +++ b/src/diff.zig @@ -7,7 +7,7 @@ const tracy = @import("tracy"); const DiffMatchPatch = @import("diffz"); const dmp: DiffMatchPatch = .{ - .diff_timeout = 250, + .diff_timeout = .fromMilliseconds(250), }; pub fn edits( diff --git a/src/features/diagnostics.zig b/src/features/diagnostics.zig index 9b47fe164..41f063011 100644 --- a/src/features/diagnostics.zig +++ b/src/features/diagnostics.zig @@ -279,6 +279,7 @@ pub fn getAstCheckDiagnostics(server: *Server, handle: *DocumentStore.Handle) er config.zig_exe_path != null) { return getErrorBundleFromAstCheck( + server.io, server.allocator, config.zig_exe_path.?, &server.zig_ast_check_lock, @@ -312,6 +313,7 @@ pub fn getAstCheckDiagnostics(server: *Server, handle: *DocumentStore.Handle) er } fn getErrorBundleFromAstCheck( + io: std.Io, allocator: std.mem.Allocator, zig_exe_path: []const u8, zig_ast_check_lock: *std.Thread.Mutex, @@ -343,7 +345,7 @@ fn getErrorBundleFromAstCheck( process.stdin = null; - stderr_bytes = try readToEndAlloc(process.stderr.?, allocator, .limited(16 * 1024 * 1024)); + stderr_bytes = try readToEndAlloc(io, allocator, process.stderr.?, .limited(16 * 1024 * 1024)); const term = process.wait() catch |err| { log.warn("Failed to await zig ast-check process, error: {}", .{err}); @@ -476,6 +478,7 @@ pub fn getErrorBundleFromStderr( } pub const BuildOnSave = struct { + io: std.Io, allocator: std.mem.Allocator, child_process: *std.process.Child, thread: std.Thread, @@ -484,6 +487,7 @@ pub const BuildOnSave = struct { const ServerToClient = shared.ServerToClient; pub const InitOptions = struct { + io: std.Io, allocator: std.mem.Allocator, workspace_path: []const u8, build_on_save_args: []const []const u8, @@ -532,8 +536,9 @@ pub const BuildOnSave = struct { errdefer { _ = terminateChildProcessReportError( - child_process, + options.io, options.allocator, + child_process, "zig build runner", .kill, ); @@ -551,6 +556,7 @@ pub const BuildOnSave = struct { errdefer comptime unreachable; return .{ + .io = options.io, .allocator = options.allocator, .child_process = child_process, .thread = thread, @@ -565,8 +571,9 @@ pub const BuildOnSave = struct { self.child_process.stdin = null; const success = terminateChildProcessReportError( - self.child_process, + self.io, self.allocator, + self.child_process, "zig build runner", .wait, ); @@ -637,16 +644,6 @@ pub const BuildOnSave = struct { } log.debug("zig build runner process has exited", .{}); - - const stderr = if (child_process.stderr) |stderr| - readToEndAlloc(stderr, allocator, .limited(16 * 1024 * 1024)) catch "" - else - ""; - defer allocator.free(stderr); - - if (stderr.len != 0) { - log.debug("build runner stderr:\n{s}", .{stderr}); - } } fn handleWatchErrorBundle( @@ -692,13 +689,14 @@ pub const BuildOnSave = struct { }; fn terminateChildProcessReportError( - child_process: *std.process.Child, + io: std.Io, allocator: std.mem.Allocator, + child_process: *std.process.Child, name: []const u8, kind: enum { wait, kill }, ) bool { const stderr = if (child_process.stderr) |stderr| - readToEndAlloc(stderr, allocator, .limited(16 * 1024 * 1024)) catch "" + readToEndAlloc(io, allocator, stderr, .limited(16 * 1024 * 1024)) catch "" else ""; defer allocator.free(stderr); @@ -732,12 +730,13 @@ fn terminateChildProcessReportError( } fn readToEndAlloc( - file: std.fs.File, + io: std.Io, allocator: std.mem.Allocator, + file: std.fs.File, limit: std.Io.Limit, ) (std.fs.File.ReadError || error{ OutOfMemory, StreamTooLong })![]u8 { var buffer: [1024]u8 = undefined; - var file_reader = file.readerStreaming(&buffer); + var file_reader = file.readerStreaming(io, &buffer); return file_reader.interface.allocRemaining(allocator, limit) catch |err| switch (err) { error.ReadFailed => return file_reader.err.?, error.OutOfMemory, error.StreamTooLong => |e| return e, diff --git a/src/main.zig b/src/main.zig index f734f3c84..24ea7a1cd 100644 --- a/src/main.zig +++ b/src/main.zig @@ -106,9 +106,9 @@ fn logFn( } } -fn defaultLogFilePath(allocator: std.mem.Allocator) std.mem.Allocator.Error!?[]const u8 { +fn defaultLogFilePath(io: std.Io, allocator: std.mem.Allocator) std.mem.Allocator.Error!?[]const u8 { if (zig_builtin.target.os.tag == .wasi) return null; - const cache_path = known_folders.getPath(allocator, .cache) catch |err| switch (err) { + const cache_path = known_folders.getPath(io, allocator, .cache) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.ParseError => return null, } orelse return null; @@ -116,11 +116,11 @@ fn defaultLogFilePath(allocator: std.mem.Allocator) std.mem.Allocator.Error!?[]c return try std.fs.path.join(allocator, &.{ cache_path, "zls", "zls.log" }); } -fn createLogFile(allocator: std.mem.Allocator, override_log_file_path: ?[]const u8) ?struct { std.fs.File, []const u8 } { +fn createLogFile(io: std.Io, allocator: std.mem.Allocator, override_log_file_path: ?[]const u8) ?struct { std.fs.File, []const u8 } { const log_file_path = if (override_log_file_path) |log_file_path| allocator.dupe(u8, log_file_path) catch return null else - defaultLogFilePath(allocator) catch null orelse return null; + defaultLogFilePath(io, allocator) catch null orelse return null; errdefer allocator.free(log_file_path); if (std.fs.path.dirname(log_file_path)) |dirname| { @@ -161,8 +161,8 @@ const Env = struct { log_file: ?[]const u8, }; -fn @"zls env"(allocator: std.mem.Allocator) (std.mem.Allocator.Error || std.fs.File.WriteError)!noreturn { - const global_cache_dir = known_folders.getPath(allocator, .cache) catch |err| switch (err) { +fn @"zls env"(io: std.Io, allocator: std.mem.Allocator) (std.mem.Allocator.Error || std.fs.File.WriteError)!noreturn { + const global_cache_dir = known_folders.getPath(io, allocator, .cache) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.ParseError => null, }; @@ -171,19 +171,19 @@ fn @"zls env"(allocator: std.mem.Allocator) (std.mem.Allocator.Error || std.fs.F const zls_global_cache_dir = if (global_cache_dir) |cache_dir| try std.fs.path.join(allocator, &.{ cache_dir, "zls" }) else null; defer if (zls_global_cache_dir) |path| allocator.free(path); - const global_config_dir = known_folders.getPath(allocator, .global_configuration) catch |err| switch (err) { + const global_config_dir = known_folders.getPath(io, allocator, .global_configuration) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.ParseError => null, }; defer if (global_config_dir) |path| allocator.free(path); - const local_config_dir = known_folders.getPath(allocator, .local_configuration) catch |err| switch (err) { + const local_config_dir = known_folders.getPath(io, allocator, .local_configuration) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.ParseError => null, }; defer if (local_config_dir) |path| allocator.free(path); - var config_result = try loadConfigFromSystem(allocator); + var config_result = try loadConfigFromSystem(io, allocator); defer config_result.deinit(allocator); const config_file_path: ?[]const u8 = switch (config_result) { @@ -198,7 +198,7 @@ fn @"zls env"(allocator: std.mem.Allocator) (std.mem.Allocator.Error || std.fs.F .not_found => null, }; - const log_file_path = try defaultLogFilePath(allocator); + const log_file_path = try defaultLogFilePath(io, allocator); defer if (log_file_path) |path| allocator.free(path); var buffer: [512]u8 = undefined; @@ -235,7 +235,7 @@ const LoadConfigResult = union(enum) { const error_bundle = self.error_bundle orelse return null; var aw: std.Io.Writer.Allocating = .init(allocator); defer aw.deinit(); - error_bundle.renderToWriter(.{ .ttyconf = .no_color }, &aw.writer) catch |err| switch (err) { + error_bundle.renderToWriter(.{}, &aw.writer, .no_color) catch |err| switch (err) { error.WriteFailed => return error.OutOfMemory, error.Unexpected => unreachable, // no tty }; @@ -319,14 +319,14 @@ fn loadConfigFromFile(allocator: std.mem.Allocator, file_path: []const u8) error } }; } -fn loadConfigFromSystem(allocator: std.mem.Allocator) error{OutOfMemory}!LoadConfigResult { +fn loadConfigFromSystem(io: std.Io, allocator: std.mem.Allocator) error{OutOfMemory}!LoadConfigResult { if (zig_builtin.target.os.tag == .wasi) return .not_found; for ( [_]known_folders.KnownFolder{ .local_configuration, .global_configuration }, [_][]const u8{ "local", "global" }, ) |folder, name| { - const folder_path = known_folders.getPath(allocator, folder) catch |err| switch (err) { + const folder_path = known_folders.getPath(io, allocator, folder) catch |err| switch (err) { error.ParseError => { log.warn("failed to resolve {s} configuration path: {}", .{ name, err }); continue; @@ -349,6 +349,7 @@ fn loadConfigFromSystem(allocator: std.mem.Allocator) error{OutOfMemory}!LoadCon } fn loadConfiguration( + io: std.Io, allocator: std.mem.Allocator, server: *zls.Server, maybe_config_path: ?[]const u8, @@ -367,7 +368,7 @@ fn loadConfiguration( break :blk; } else - loadConfigFromSystem(allocator) catch |err| { + loadConfigFromSystem(io, allocator) catch |err| { log.err("failed to load configuration: {}", .{err}); break :blk; }; @@ -395,7 +396,7 @@ fn loadConfiguration( break :blk; } - const cache_dir_path = known_folders.getPath(allocator, .cache) catch null orelse { + const cache_dir_path = known_folders.getPath(io, allocator, .cache) catch null orelse { server.showMessage(.Error, "Failed to resolve global cache directory", .{}); break :blk; }; @@ -424,7 +425,7 @@ const ParseArgsResult = struct { const ParseArgsError = std.process.ArgIterator.InitError || std.mem.Allocator.Error || std.fs.File.WriteError; -fn parseArgs(allocator: std.mem.Allocator) ParseArgsError!ParseArgsResult { +fn parseArgs(io: std.Io, allocator: std.mem.Allocator) ParseArgsError!ParseArgsResult { var result: ParseArgsResult = .{}; errdefer result.deinit(allocator); @@ -446,7 +447,7 @@ fn parseArgs(allocator: std.mem.Allocator) ParseArgsError!ParseArgsResult { try std.fs.File.stdout().writeAll(zls.build_options.version_string ++ "\n"); std.process.exit(0); } else if (arg_index == 0 and std.mem.eql(u8, arg, "env")) { - try @"zls env"(allocator); + try @"zls env"(io, allocator); } if (std.mem.eql(u8, arg, "--config-path")) { // --config-path @@ -512,10 +513,14 @@ pub fn main() !u8 { var failing_allocator_state = if (exe_options.enable_failing_allocator) zls.testing.FailingAllocator.init(inner_allocator, exe_options.enable_failing_allocator_likelihood) else {}; const allocator: std.mem.Allocator = if (exe_options.enable_failing_allocator) failing_allocator_state.allocator() else inner_allocator; - const result = try parseArgs(allocator); + var threaded: std.Io.Threaded = .init(allocator); + defer threaded.deinit(); + const io = threaded.io(); + + const result = try parseArgs(io, allocator); defer result.deinit(allocator); - log_file, const log_file_path = createLogFile(allocator, result.log_file_path) orelse .{ null, null }; + log_file, const log_file_path = createLogFile(io, allocator, result.log_file_path) orelse .{ null, null }; defer if (log_file_path) |path| allocator.free(path); defer if (log_file) |file| { file.close(); @@ -523,7 +528,7 @@ pub fn main() !u8 { }; var read_buffer: [256]u8 = undefined; - var stdio_transport: zls.lsp.Transport.Stdio = .init(&read_buffer, .stdin(), .stdout()); + var stdio_transport: zls.lsp.Transport.Stdio = .init(io, &read_buffer, .stdin(), .stdout()); var thread_safe_transport: zls.lsp.ThreadSafeTransport(.{ .thread_safe_read = false, @@ -548,13 +553,14 @@ pub fn main() !u8 { } const server: *zls.Server = try .create(.{ + .io = io, .allocator = allocator, .transport = transport, .config = null, }); defer server.destroy(); - try loadConfiguration(allocator, server, result.config_path); + try loadConfiguration(io, allocator, server, result.config_path); try server.loop(); diff --git a/src/snippets.zig b/src/snippets.zig index eb3472b45..a0c9aee3b 100644 --- a/src/snippets.zig +++ b/src/snippets.zig @@ -22,7 +22,7 @@ pub const top_level_decl_data = [_]Snipped{ .{ .label = "test", .kind = .Snippet, .text = "test \"$1\" {$0}" }, .{ .label = "main", .kind = .Snippet, .text = "pub fn main() !void {$0}" }, .{ .label = "std_options", .kind = .Snippet, .text = "pub const std_options: std.Options = .{$0};" }, - .{ .label = "panic", .kind = .Snippet, .text = + .{ .label = "panic", .kind = .Snippet, .text = \\pub fn panic( \\ msg: []const u8, \\ trace: ?*std.builtin.StackTrace, @@ -89,7 +89,7 @@ pub const generic = [_]Snipped{ .{ .label = "log warn", .kind = .Snippet, .text = "std.log.warn(\"$1\", .{$0});" }, .{ .label = "log info", .kind = .Snippet, .text = "std.log.info(\"$1\", .{$0});" }, .{ .label = "log debug", .kind = .Snippet, .text = "std.log.debug(\"$1\", .{$0});" }, - .{ .label = "format", .kind = .Snippet, .text = + .{ .label = "format", .kind = .Snippet, .text = \\pub fn format( \\ self: @This(), \\ writer: *std.Io.Writer, diff --git a/src/translate_c.zig b/src/translate_c.zig index ea1dab3ee..10aef09de 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -107,6 +107,7 @@ pub const Result = union(enum) { /// null indicates a failure which is automatically logged /// Caller owns returned memory. pub fn translate( + io: std.Io, allocator: std.mem.Allocator, config: DocumentStore.Config, include_dirs: []const []const u8, @@ -176,7 +177,7 @@ pub fn translate( process.stdout_behavior = .Pipe; process.stderr_behavior = .Ignore; - errdefer |err| if (!zig_builtin.is_test) reportTranslateError(allocator, process.stderr, argv.items, @errorName(err)); + errdefer |err| if (!zig_builtin.is_test) reportTranslateError(io, allocator, process.stderr, argv.items, @errorName(err)); process.spawn() catch |err| { log.err("failed to spawn zig translate-c process, error: {}", .{err}); @@ -264,12 +265,12 @@ pub fn translate( } } -fn reportTranslateError(allocator: std.mem.Allocator, stderr: ?std.fs.File, argv: []const []const u8, err_name: []const u8) void { +fn reportTranslateError(io: std.Io, allocator: std.mem.Allocator, stderr: ?std.fs.File, argv: []const []const u8, err_name: []const u8) void { const joined = std.mem.join(allocator, " ", argv) catch return; defer allocator.free(joined); if (stderr) |file| { var buffer: [1024]u8 = undefined; - var file_reader = file.readerStreaming(&buffer); + var file_reader = file.readerStreaming(io, &buffer); const stderr_output = file_reader.interface.allocRemaining(allocator, .limited(16 * 1024 * 1024)) catch return; defer allocator.free(stderr_output); log.err("failed zig translate-c command:\n{s}\nstderr:{s}\nerror:{s}\n", .{ joined, stderr_output, err_name }); diff --git a/tests/analysis_check.zig b/tests/analysis_check.zig index 720eab992..8d28d73c8 100644 --- a/tests/analysis_check.zig +++ b/tests/analysis_check.zig @@ -30,6 +30,10 @@ pub fn main() Error!void { defer _ = debug_allocator.deinit(); const gpa = debug_allocator.allocator(); + var threaded: std.Io.Threaded = .init(gpa); + defer threaded.deinit(); + const io = threaded.io(); + var arg_it = std.process.argsWithAllocator(gpa) catch |err| std.debug.panic("failed to collect args: {}", .{err}); defer arg_it.deinit(); @@ -114,6 +118,7 @@ pub fn main() Error!void { defer diagnostics_collection.deinit(); var document_store: zls.DocumentStore = .{ + .io = io, .allocator = gpa, .config = config, .thread_pool = &thread_pool, diff --git a/tests/context.zig b/tests/context.zig index c13665606..8a9d7da19 100644 --- a/tests/context.zig +++ b/tests/context.zig @@ -5,6 +5,7 @@ const test_options = @import("test_options"); const types = zls.lsp.types; +const io = std.testing.io; const allocator = std.testing.allocator; const default_config: zls.configuration.UnresolvedConfig = .{ @@ -46,6 +47,7 @@ pub const Context = struct { }; const server: *zls.Server = try .create(.{ + .io = io, .allocator = allocator, .transport = null, .config = null, diff --git a/tests/language_features/cimport.zig b/tests/language_features/cimport.zig index f27499cba..3e92e4f8e 100644 --- a/tests/language_features/cimport.zig +++ b/tests/language_features/cimport.zig @@ -8,6 +8,7 @@ const Context = @import("../context.zig").Context; const offsets = zls.offsets; const translate_c = zls.translate_c; +const io = std.testing.io; const allocator: std.mem.Allocator = std.testing.allocator; test "zig compile server - translate c" { @@ -110,6 +111,7 @@ fn testTranslate(c_source: []const u8) !translate_c.Result { defer ctx.deinit(); var result = (try translate_c.translate( + io, allocator, ctx.server.document_store.config, &.{}, diff --git a/tests/lifecycle.zig b/tests/lifecycle.zig index 7b207df61..b066fe5a2 100644 --- a/tests/lifecycle.zig +++ b/tests/lifecycle.zig @@ -3,10 +3,12 @@ const builtin = @import("builtin"); const zls = @import("zls"); const test_options = @import("test_options"); +const io = std.testing.io; const allocator = std.testing.allocator; test "LSP lifecycle" { var server: *zls.Server = try .create(.{ + .io = io, .allocator = allocator, .transport = null, .config = null, diff --git a/tests/lsp_features/completion.zig b/tests/lsp_features/completion.zig index f82a9dcd9..d6e4d9e52 100644 --- a/tests/lsp_features/completion.zig +++ b/tests/lsp_features/completion.zig @@ -4597,7 +4597,7 @@ fn searchCompletionItemWithLabel(completion_list: types.CompletionList, label: [ if (std.mem.eql(u8, item.label, label)) return item; } - const stderr = std.debug.lockStderrWriter(&.{}); + const stderr, _ = std.debug.lockStderrWriter(&.{}); defer std.debug.unlockStderrWriter(); try stderr.print( From cfd54aef939d086927eb80aba8b1908ab86db99a Mon Sep 17 00:00:00 2001 From: Techatrix Date: Sun, 2 Nov 2025 00:59:10 +0100 Subject: [PATCH 2/4] set minimum zig version to `0.16.0-dev.1326+2e6f7d36b` --- build.zig.zon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.zig.zon b/build.zig.zon index 44e68337a..4891c3a25 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -10,7 +10,7 @@ // nix flake update --commit-lock-file // ``` // If you do not use Nix, a ZLS maintainer can take care of this. - .minimum_zig_version = "0.16.0-dev.728+87c18945c", + .minimum_zig_version = "0.16.0-dev.1326+2e6f7d36b", // If you do not use Nix, a ZLS maintainer can take care of this. // Whenever the dependencies are updated, run the following command: // ```bash From 73f2b652f228e5e7e51f843bb7ec198a613ceb62 Mon Sep 17 00:00:00 2001 From: Techatrix Date: Sun, 16 Nov 2025 13:01:34 +0100 Subject: [PATCH 3/4] flake.lock: Update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'gitignore': 'github:hercules-ci/gitignore.nix/637db329424fd7e46cf4185293b9cc8c88c95394?narHash=sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs%3D' (2024-02-28) → 'github:hercules-ci/gitignore.nix/cb5e3fdca1de58ccbc3ef53de65bd372b48f567c?narHash=sha256-XmjITeZNMTQXGhhww6ed/Wacy2KzD6svioyCX7pkUu4%3D' (2025-11-10) • Updated input 'nixpkgs': 'github:NixOS/nixpkgs/7e297ddff44a3cc93673bb38d0374df8d0ad73e4?narHash=sha256-4xggC56Rub3WInz5eD7EZWXuLXpNvJiUPahGtMkwtuc%3D' (2025-10-10) → 'github:NixOS/nixpkgs/3acb677ea67d4c6218f33de0db0955f116b7588c?narHash=sha256-A5LS0AJZ1yDPTa2fHxufZN%2B%2Bn8MCmtgrJDtxFxrH4S8%3D' (2025-11-13) • Updated input 'zig-overlay': 'github:mitchellh/zig-overlay/365085b6652259753b598d43b723858184980bbe?narHash=sha256-/zj5GYO5PKhBWGzbHbqT%2BehY8EghuABdQ2WGfCwZpCQ%3D' (2025-10-14) → 'github:mitchellh/zig-overlay/7ff98ce81ef0d13bb0866ac92620f568d8201b56?narHash=sha256-kOaLx2%2BkPWtex4JaP5RtSz57uc2GygZAiMTNfObmAPg%3D' (2025-11-16) --- flake.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index 7846823c0..82ee18c0f 100644 --- a/flake.lock +++ b/flake.lock @@ -41,11 +41,11 @@ ] }, "locked": { - "lastModified": 1709087332, - "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "lastModified": 1762808025, + "narHash": "sha256-XmjITeZNMTQXGhhww6ed/Wacy2KzD6svioyCX7pkUu4=", "owner": "hercules-ci", "repo": "gitignore.nix", - "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "rev": "cb5e3fdca1de58ccbc3ef53de65bd372b48f567c", "type": "github" }, "original": { @@ -56,11 +56,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1760139962, - "narHash": "sha256-4xggC56Rub3WInz5eD7EZWXuLXpNvJiUPahGtMkwtuc=", + "lastModified": 1763049705, + "narHash": "sha256-A5LS0AJZ1yDPTa2fHxufZN++n8MCmtgrJDtxFxrH4S8=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "7e297ddff44a3cc93673bb38d0374df8d0ad73e4", + "rev": "3acb677ea67d4c6218f33de0db0955f116b7588c", "type": "github" }, "original": { @@ -101,11 +101,11 @@ ] }, "locked": { - "lastModified": 1760401936, - "narHash": "sha256-/zj5GYO5PKhBWGzbHbqT+ehY8EghuABdQ2WGfCwZpCQ=", + "lastModified": 1763253467, + "narHash": "sha256-kOaLx2+kPWtex4JaP5RtSz57uc2GygZAiMTNfObmAPg=", "owner": "mitchellh", "repo": "zig-overlay", - "rev": "365085b6652259753b598d43b723858184980bbe", + "rev": "7ff98ce81ef0d13bb0866ac92620f568d8201b56", "type": "github" }, "original": { From c5f1d9feae3b19b09cd8d64959856f0b38bbdfcc Mon Sep 17 00:00:00 2001 From: Techatrix Date: Sun, 16 Nov 2025 13:15:00 +0100 Subject: [PATCH 4/4] CI: workaround dependency fetching deadlock --- .github/workflows/main.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6407ff364..4abdc37de 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -26,6 +26,12 @@ jobs: if: matrix.os == 'ubuntu-22.04' run: zig fmt --check . + - name: prefetch dependencies (workaround) + run: | + zig fetch https://github.com/ziglibs/known-folders/archive/bafef170a73c064dc706fcfbdc2e406a35681a9c.tar.gz + zig fetch https://github.com/ziglibs/diffz/archive/36fc805f459677093c93c210e8f9aed28be13847.tar.gz + zig fetch https://github.com/zigtools/lsp-kit/archive/c46ac866dda11ab58e4ba71ed0d8ba21f43e81db.tar.gz + - name: Run zig build check test run: zig build check test --summary all