Skip to content

Commit 78e7474

Browse files
committed
Use zig env to find zig lib path instead of assuming the executable comes from a distribution tarball
1 parent 892847d commit 78e7474

File tree

3 files changed

+78
-39
lines changed

3 files changed

+78
-39
lines changed

src/analysis.zig

+4-4
Original file line numberDiff line numberDiff line change
@@ -813,7 +813,7 @@ pub fn resolveTypeOfNodeInternal(
813813

814814
const import_str = handle.tree.tokenSlice(import_param.castTag(.StringLiteral).?.token);
815815
const new_handle = (store.resolveImport(handle, import_str[1 .. import_str.len - 1]) catch |err| {
816-
log.debug("Error {} while processing import {}\n", .{ err, import_str });
816+
log.debug("Error {} while processing import {}", .{ err, import_str });
817817
return null;
818818
}) orelse return null;
819819

@@ -1071,7 +1071,7 @@ pub fn getFieldAccessType(
10711071
current_type = (try resolveUnwrapOptionalType(store, arena, current_type, &bound_type_params)) orelse return null;
10721072
},
10731073
else => {
1074-
log.debug("Unrecognized token {} after period.\n", .{after_period.id});
1074+
log.debug("Unrecognized token {} after period.", .{after_period.id});
10751075
return null;
10761076
},
10771077
}
@@ -1122,7 +1122,7 @@ pub fn getFieldAccessType(
11221122
current_type = (try resolveBracketAccessType(store, arena, current_type, if (is_range) .Range else .Single, &bound_type_params)) orelse return null;
11231123
},
11241124
else => {
1125-
log.debug("Unimplemented token: {}\n", .{tok.id});
1125+
log.debug("Unimplemented token: {}", .{tok.id});
11261126
return null;
11271127
},
11281128
}
@@ -1169,7 +1169,7 @@ pub fn nodeToString(tree: *ast.Tree, node: *ast.Node) ?[]const u8 {
11691169
}
11701170
},
11711171
else => {
1172-
log.debug("INVALID: {}\n", .{node.tag});
1172+
log.debug("INVALID: {}", .{node.tag});
11731173
},
11741174
}
11751175

src/document_store.zig

+16-16
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ fn loadPackages(context: LoadPackagesContext) !void {
107107
switch (zig_run_result.term) {
108108
.Exited => |exit_code| {
109109
if (exit_code == 0) {
110-
log.debug("Finished zig run for build file {}\n", .{build_file.uri});
110+
log.debug("Finished zig run for build file {}", .{build_file.uri});
111111

112112
for (build_file.packages.items) |old_pkg| {
113113
allocator.free(old_pkg.name);
@@ -145,7 +145,7 @@ fn loadPackages(context: LoadPackagesContext) !void {
145145
/// This function asserts the document is not open yet and takes ownership
146146
/// of the uri and text passed in.
147147
fn newDocument(self: *DocumentStore, uri: []const u8, text: []u8) anyerror!*Handle {
148-
log.debug("Opened document: {}\n", .{uri});
148+
log.debug("Opened document: {}", .{uri});
149149

150150
var handle = try self.allocator.create(Handle);
151151
errdefer self.allocator.destroy(handle);
@@ -173,7 +173,7 @@ fn newDocument(self: *DocumentStore, uri: []const u8, text: []u8) anyerror!*Hand
173173
// TODO: Better logic for detecting std or subdirectories?
174174
const in_std = std.mem.indexOf(u8, uri, "/std/") != null;
175175
if (self.zig_exe_path != null and std.mem.endsWith(u8, uri, "/build.zig") and !in_std) {
176-
log.debug("Document is a build file, extracting packages...\n", .{});
176+
log.debug("Document is a build file, extracting packages...", .{});
177177
// This is a build file.
178178
var build_file = try self.allocator.create(BuildFile);
179179
errdefer self.allocator.destroy(build_file);
@@ -195,15 +195,15 @@ fn newDocument(self: *DocumentStore, uri: []const u8, text: []u8) anyerror!*Hand
195195
.build_runner_path = self.build_runner_path,
196196
.zig_exe_path = self.zig_exe_path.?,
197197
}) catch |err| {
198-
log.debug("Failed to load packages of build file {} (error: {})\n", .{ build_file.uri, err });
198+
log.debug("Failed to load packages of build file {} (error: {})", .{ build_file.uri, err });
199199
};
200200
} else if (self.zig_exe_path != null and !in_std) associate_build_file: {
201201
// Look into build files to see if we already have one that fits
202202
for (self.build_files.items) |build_file| {
203203
const build_file_base_uri = build_file.uri[0 .. std.mem.lastIndexOfScalar(u8, build_file.uri, '/').? + 1];
204204

205205
if (std.mem.startsWith(u8, uri, build_file_base_uri)) {
206-
log.debug("Found an associated build file: {}\n", .{build_file.uri});
206+
log.debug("Found an associated build file: {}", .{build_file.uri});
207207
build_file.refs += 1;
208208
handle.associated_build_file = build_file;
209209
break :associate_build_file;
@@ -255,12 +255,12 @@ fn newDocument(self: *DocumentStore, uri: []const u8, text: []u8) anyerror!*Hand
255255

256256
pub fn openDocument(self: *DocumentStore, uri: []const u8, text: []const u8) !*Handle {
257257
if (self.handles.getEntry(uri)) |entry| {
258-
log.debug("Document already open: {}, incrementing count\n", .{uri});
258+
log.debug("Document already open: {}, incrementing count", .{uri});
259259
entry.value.count += 1;
260260
if (entry.value.is_build_file) |build_file| {
261261
build_file.refs += 1;
262262
}
263-
log.debug("New count: {}\n", .{entry.value.count});
263+
log.debug("New count: {}", .{entry.value.count});
264264
return entry.value;
265265
}
266266

@@ -275,7 +275,7 @@ pub fn openDocument(self: *DocumentStore, uri: []const u8, text: []const u8) !*H
275275
fn decrementBuildFileRefs(self: *DocumentStore, build_file: *BuildFile) void {
276276
build_file.refs -= 1;
277277
if (build_file.refs == 0) {
278-
log.debug("Freeing build file {}\n", .{build_file.uri});
278+
log.debug("Freeing build file {}", .{build_file.uri});
279279
for (build_file.packages.items) |pkg| {
280280
self.allocator.free(pkg.name);
281281
self.allocator.free(pkg.uri);
@@ -301,7 +301,7 @@ fn decrementCount(self: *DocumentStore, uri: []const u8) void {
301301
if (entry.value.count > 0)
302302
return;
303303

304-
log.debug("Freeing document: {}\n", .{uri});
304+
log.debug("Freeing document: {}", .{uri});
305305

306306
if (entry.value.associated_build_file) |build_file| {
307307
self.decrementBuildFileRefs(build_file);
@@ -338,7 +338,7 @@ pub fn getHandle(self: *DocumentStore, uri: []const u8) ?*Handle {
338338

339339
// Check if the document text is now sane, move it to sane_text if so.
340340
fn refreshDocument(self: *DocumentStore, handle: *Handle, zig_lib_path: ?[]const u8) !void {
341-
log.debug("New text for document {}\n", .{handle.uri()});
341+
log.debug("New text for document {}", .{handle.uri()});
342342
handle.tree.deinit();
343343
handle.tree = try std.zig.parse(self.allocator, handle.document.text);
344344

@@ -384,7 +384,7 @@ fn refreshDocument(self: *DocumentStore, handle: *Handle, zig_lib_path: ?[]const
384384
while (idx < still_exist.len) : (idx += 1) {
385385
if (still_exist[idx]) continue;
386386

387-
log.debug("Import removed: {}\n", .{handle.import_uris.items[idx - offset]});
387+
log.debug("Import removed: {}", .{handle.import_uris.items[idx - offset]});
388388
const uri = handle.import_uris.orderedRemove(idx - offset);
389389
offset += 1;
390390

@@ -401,7 +401,7 @@ pub fn applySave(self: *DocumentStore, handle: *Handle) !void {
401401
.build_runner_path = self.build_runner_path,
402402
.zig_exe_path = self.zig_exe_path.?,
403403
}) catch |err| {
404-
log.debug("Failed to load packages of build file {} (error: {})\n", .{ build_file.uri, err });
404+
log.debug("Failed to load packages of build file {} (error: {})", .{ build_file.uri, err });
405405
};
406406
}
407407
}
@@ -483,7 +483,7 @@ pub fn uriFromImportStr(
483483
) !?[]const u8 {
484484
if (std.mem.eql(u8, import_str, "std")) {
485485
if (self.std_uri) |uri| return try std.mem.dupe(allocator, u8, uri) else {
486-
log.debug("Cannot resolve std library import, path is null.\n", .{});
486+
log.debug("Cannot resolve std library import, path is null.", .{});
487487
return null;
488488
}
489489
} else if (std.mem.eql(u8, import_str, "builtin")) {
@@ -549,7 +549,7 @@ pub fn resolveImport(self: *DocumentStore, handle: *Handle, import_str: []const
549549
defer allocator.free(file_path);
550550

551551
var file = std.fs.cwd().openFile(file_path, .{}) catch {
552-
log.debug("Cannot open import file {}\n", .{file_path});
552+
log.debug("Cannot open import file {}", .{file_path});
553553
return null;
554554
};
555555

@@ -561,7 +561,7 @@ pub fn resolveImport(self: *DocumentStore, handle: *Handle, import_str: []const
561561
errdefer allocator.free(file_contents);
562562

563563
file.reader().readNoEof(file_contents) catch {
564-
log.debug("Could not read from file {}\n", .{file_path});
564+
log.debug("Could not read from file {}", .{file_path});
565565
return null;
566566
};
567567

@@ -582,7 +582,7 @@ fn stdUriFromLibPath(allocator: *std.mem.Allocator, zig_lib_path: ?[]const u8) !
582582
const std_path = std.fs.path.resolve(allocator, &[_][]const u8{
583583
zpath, "./std/std.zig",
584584
}) catch |err| {
585-
log.debug("Failed to resolve zig std library path, error: {}\n", .{err});
585+
log.debug("Failed to resolve zig std library path, error: {}", .{err});
586586
return null;
587587
};
588588

src/main.zig

+58-19
Original file line numberDiff line numberDiff line change
@@ -1031,20 +1031,20 @@ fn loadConfig(folder_path: []const u8) ?Config {
10311031

10321032
const file_buf = folder.readFileAlloc(allocator, "zls.json", 0x1000000) catch |err| {
10331033
if (err != error.FileNotFound)
1034-
logger.warn("Error while reading configuration file: {}\n", .{err});
1034+
logger.warn("Error while reading configuration file: {}", .{err});
10351035
return null;
10361036
};
10371037
defer allocator.free(file_buf);
10381038

10391039
// TODO: Better errors? Doesn't seem like std.json can provide us positions or context.
10401040
var config = std.json.parse(Config, &std.json.TokenStream.init(file_buf), std.json.ParseOptions{ .allocator = allocator }) catch |err| {
1041-
logger.warn("Error while parsing configuration file: {}\n", .{err});
1041+
logger.warn("Error while parsing configuration file: {}", .{err});
10421042
return null;
10431043
};
10441044

10451045
if (config.zig_lib_path) |zig_lib_path| {
10461046
if (!std.fs.path.isAbsolute(zig_lib_path)) {
1047-
logger.warn("zig library path is not absolute, defaulting to null.\n", .{});
1047+
logger.warn("zig library path is not absolute, defaulting to null.", .{});
10481048
allocator.free(zig_lib_path);
10491049
config.zig_lib_path = null;
10501050
}
@@ -1154,8 +1154,8 @@ fn initializeHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req:
11541154
});
11551155

11561156
logger.notice("zls initialized", .{});
1157-
logger.info("{}\n", .{client_capabilities});
1158-
logger.notice("Using offset encoding: {}\n", .{std.meta.tagName(offset_encoding)});
1157+
logger.info("{}", .{client_capabilities});
1158+
logger.notice("Using offset encoding: {}", .{std.meta.tagName(offset_encoding)});
11591159
}
11601160

11611161
var keep_running = true;
@@ -1334,7 +1334,7 @@ fn formattingHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req:
13341334
process.stdout_behavior = .Pipe;
13351335

13361336
process.spawn() catch |err| {
1337-
logger.warn("Failed to spawn zig fmt process, error: {}\n", .{err});
1337+
logger.warn("Failed to spawn zig fmt process, error: {}", .{err});
13381338
return try respondGeneric(id, null_result_response);
13391339
};
13401340
try process.stdin.?.writeAll(handle.document.text);
@@ -1429,7 +1429,7 @@ fn processJsonRpc(arena: *std.heap.ArenaAllocator, parser: *std.json.Parser, jso
14291429
const start_time = std.time.milliTimestamp();
14301430
defer {
14311431
const end_time = std.time.milliTimestamp();
1432-
logger.debug("Took {}ms to process method {}\n", .{ end_time - start_time, method });
1432+
logger.debug("Took {}ms to process method {}", .{ end_time - start_time, method });
14331433
}
14341434

14351435
const method_map = .{
@@ -1469,7 +1469,7 @@ fn processJsonRpc(arena: *std.heap.ArenaAllocator, parser: *std.json.Parser, jso
14691469
done = extractErr(method_info[2](arena, id, request_obj, config));
14701470
} else |err| {
14711471
if (err == error.MalformedJson) {
1472-
logger.warn("Could not create request type {} from JSON {}\n", .{ @typeName(ReqT), json });
1472+
logger.warn("Could not create request type {} from JSON {}", .{ @typeName(ReqT), json });
14731473
}
14741474
done = err;
14751475
}
@@ -1526,9 +1526,9 @@ pub fn main() anyerror!void {
15261526
defer allocator.free(arg);
15271527
if (std.mem.eql(u8, arg, "--debug-log")) {
15281528
actual_log_level = .debug;
1529-
std.debug.print("Enabled debug logging\n", .{});
1529+
std.debug.print("Enabled debug logging", .{});
15301530
} else {
1531-
std.debug.print("Unrecognized argument {}\n", .{arg});
1531+
std.debug.print("Unrecognized argument {}", .{arg});
15321532
std.os.exit(1);
15331533
}
15341534
}
@@ -1582,12 +1582,12 @@ pub fn main() anyerror!void {
15821582
break :find_zig;
15831583
}
15841584

1585-
logger.debug("zig path `{}` is not absolute, will look in path\n", .{exe_path});
1585+
logger.debug("zig path `{}` is not absolute, will look in path", .{exe_path});
15861586
}
15871587

15881588
const env_path = std.process.getEnvVarOwned(allocator, "PATH") catch |err| switch (err) {
15891589
error.EnvironmentVariableNotFound => {
1590-
logger.warn("Could not get PATH.\n", .{});
1590+
logger.warn("Could not get PATH environmental variable", .{});
15911591
break :find_zig;
15921592
},
15931593
else => return err,
@@ -1608,22 +1608,61 @@ pub fn main() anyerror!void {
16081608

16091609
var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
16101610
zig_exe_path = try std.mem.dupe(allocator, u8, std.os.realpath(full_path, &buf) catch continue);
1611-
logger.info("Found zig in PATH: {}\n", .{zig_exe_path});
1611+
logger.info("Found zig in PATH: {}", .{zig_exe_path});
16121612
break :find_zig;
16131613
}
16141614
}
16151615

16161616
if (zig_exe_path) |exe_path| {
16171617
config.zig_exe_path = exe_path;
1618-
logger.info("Using zig executable {}\n", .{exe_path});
1619-
if (config.zig_lib_path == null) {
1620-
// Set the lib path relative to the executable path.
1621-
config.zig_lib_path = try std.fs.path.resolve(allocator, &[_][]const u8{
1622-
std.fs.path.dirname(exe_path).?, "./lib/zig",
1618+
logger.info("Using zig executable {}", .{exe_path});
1619+
if (config.zig_lib_path == null) find_lib_path: {
1620+
// Use `zig env` to find the lib path
1621+
const zig_env_result = try std.ChildProcess.exec(.{
1622+
.allocator = allocator,
1623+
.argv = &[_][]const u8{ exe_path, "env" },
16231624
});
16241625

1625-
logger.info("Resolved standard library from executable: {}\n", .{config.zig_lib_path});
1626+
defer {
1627+
allocator.free(zig_env_result.stdout);
1628+
allocator.free(zig_env_result.stderr);
1629+
}
1630+
1631+
switch (zig_env_result.term) {
1632+
.Exited => |exit_code| {
1633+
if (exit_code == 0) {
1634+
const Env = struct {
1635+
zig_exe: []const u8,
1636+
lib_dir: ?[]const u8,
1637+
std_dir: []const u8,
1638+
global_cache_dir: []const u8,
1639+
version: []const u8,
1640+
};
1641+
1642+
var json_env = std.json.parse(
1643+
Env,
1644+
&std.json.TokenStream.init(zig_env_result.stdout),
1645+
.{ .allocator = allocator },
1646+
) catch {
1647+
logger.alert("Failed to parse zig env JSON result", .{});
1648+
break :find_lib_path;
1649+
};
1650+
defer std.json.parseFree(Env, json_env, .{ .allocator = allocator });
1651+
// We know this is allocated with `allocator`, we just steal it!
1652+
config.zig_lib_path = json_env.lib_dir.?;
1653+
json_env.lib_dir = null;
1654+
logger.notice("Using zig lib path '{}'", .{config.zig_lib_path});
1655+
}
1656+
},
1657+
else => logger.alert("zig env invocation failed", .{}),
1658+
}
16261659
}
1660+
} else {
1661+
logger.warn("Zig executable path not specified in zls.json and could not be found in PATH", .{});
1662+
}
1663+
1664+
if (config.zig_lib_path == null) {
1665+
logger.warn("Zig standard library path not specified in zls.json and could not be resolved from the zig executable", .{});
16271666
}
16281667

16291668
if (config.build_runner_path) |build_runner_path| {

0 commit comments

Comments
 (0)