diff --git a/src/Config.zig b/src/Config.zig index 688c1f7..00d5552 100644 --- a/src/Config.zig +++ b/src/Config.zig @@ -127,51 +127,18 @@ pub fn configChanged(config: *Config, allocator: std.mem.Allocator, builtin_crea config.zig_exe_path = try setup.findZig(allocator); } - if (config.zig_exe_path) |exe_path| { + if (config.zig_exe_path) |exe_path| blk: { logger.info("Using zig executable {s}", .{exe_path}); - if (config.zig_lib_path == null) find_lib_path: { - // Use `zig env` to find the lib path - const zig_env_result = try std.ChildProcess.exec(.{ - .allocator = allocator, - .argv = &[_][]const u8{ exe_path, "env" }, - }); + if (config.zig_lib_path != null) break :blk; - defer { - allocator.free(zig_env_result.stdout); - allocator.free(zig_env_result.stderr); - } + var env = getZigEnv(allocator, exe_path) orelse break :blk; + defer std.json.parseFree(Env, env, .{ .allocator = allocator }); - switch (zig_env_result.term) { - .Exited => |exit_code| { - if (exit_code == 0) { - const Env = struct { - zig_exe: []const u8, - lib_dir: ?[]const u8, - std_dir: []const u8, - global_cache_dir: []const u8, - version: []const u8, - target: ?[]const u8 = null, - }; - - var json_env = std.json.parse( - Env, - &std.json.TokenStream.init(zig_env_result.stdout), - .{ .allocator = allocator }, - ) catch { - logger.err("Failed to parse zig env JSON result", .{}); - break :find_lib_path; - }; - defer std.json.parseFree(Env, json_env, .{ .allocator = allocator }); - // We know this is allocated with `allocator`, we just steal it! - config.zig_lib_path = json_env.lib_dir.?; - json_env.lib_dir = null; - logger.info("Using zig lib path '{?s}'", .{config.zig_lib_path}); - } - }, - else => logger.err("zig env invocation failed", .{}), - } - } + // We know this is allocated with `allocator`, we just steal it! + config.zig_lib_path = env.lib_dir.?; + env.lib_dir = null; + logger.info("Using zig lib path '{s}'", .{config.zig_lib_path.?}); } else { logger.warn("Zig executable path not specified in zls.json and could not be found in PATH", .{}); } @@ -231,3 +198,51 @@ pub fn configChanged(config: *Config, allocator: std.mem.Allocator, builtin_crea try file.writeAll(@embedFile("special/build_runner.zig")); } } + +pub const Env = struct { + zig_exe: []const u8, + lib_dir: ?[]const u8, + std_dir: []const u8, + global_cache_dir: []const u8, + version: []const u8, + target: ?[]const u8 = null, +}; + +/// result has to be freed with `std.json.parseFree` +pub fn getZigEnv(allocator: std.mem.Allocator, zig_exe_path: []const u8) ?Env { + const zig_env_result = std.ChildProcess.exec(.{ + .allocator = allocator, + .argv = &[_][]const u8{ zig_exe_path, "env" }, + }) catch { + logger.err("Failed to execute zig env", .{}); + return null; + }; + + defer { + allocator.free(zig_env_result.stdout); + allocator.free(zig_env_result.stderr); + } + + switch (zig_env_result.term) { + .Exited => |code| { + if (code != 0) { + logger.err("zig env failed with error_code: {}", .{code}); + return null; + } + }, + else => logger.err("zig env invocation failed", .{}), + } + + var token_stream = std.json.TokenStream.init(zig_env_result.stdout); + return std.json.parse( + Env, + &token_stream, + .{ + .allocator = allocator, + .ignore_unknown_fields = true, + }, + ) catch { + logger.err("Failed to parse zig env JSON result", .{}); + return null; + }; +} diff --git a/src/Server.zig b/src/Server.zig index 902f334..bad0a72 100644 --- a/src/Server.zig +++ b/src/Server.zig @@ -133,10 +133,10 @@ fn respondGeneric(writer: anytype, id: types.RequestId, response: []const u8) !v } fn showMessage(server: *Server, writer: anytype, message_type: types.MessageType, message: []const u8) !void { - try send(writer, server.allocator, types.Notification{ + try send(writer, server.arena.allocator(), types.Notification{ .method = "window/showMessage", .params = .{ - .ShowMessageParams = .{ + .ShowMessage = .{ .type = message_type, .message = message, }, @@ -1600,6 +1600,20 @@ fn initializeHandler(server: *Server, writer: anytype, id: types.RequestId, req: log.info("zls initialized", .{}); log.info("{}", .{server.client_capabilities}); log.info("Using offset encoding: {s}", .{std.meta.tagName(server.offset_encoding)}); + + // TODO avoid having to call getZigEnv twice + // once in init and here + const env = Config.getZigEnv(server.allocator, server.config.zig_exe_path.?) orelse return; + defer std.json.parseFree(Config.Env, env, .{ .allocator = server.allocator }); + + const zig_exe_version = std.SemanticVersion.parse(env.version) catch return; + + if (zig_builtin.zig_version.order(zig_exe_version) == .gt) { + try server.showMessage(writer, .Warning, + \\ZLS has been build with a newer version than you are using! + \\This may cause unexpected issues. + ); + } } fn registerCapability(server: *Server, writer: anytype, method: []const u8) !void {