From e7f8a8dcd9c0b7d5459b079b047a8fc3e2969b58 Mon Sep 17 00:00:00 2001 From: Alexandros Naskos Date: Tue, 12 Jan 2021 13:10:51 +0200 Subject: [PATCH] zls will now run the package extraction build runner without copying it in the destination folder. Instead, it will use a specific cache folder and run from the default cwd it was run from. Added build_runner_cache_path to the configuration file. --- README.md | 3 ++- src/config.zig | 6 +++-- src/document_store.zig | 49 ++++++++++++++++-------------------- src/main.zig | 26 +++++++++++++------ src/special/build_runner.zig | 2 +- 5 files changed, 47 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 5781b83..a8aca72 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,8 @@ The following options are currently available. | `zig_lib_path` | `?[]const u8` | `null` | zig library path, e.g. `/path/to/zig/lib/zig`, used to analyze std library imports. | | `zig_exe_path` | `?[]const u8` | `null` | zig executable path, e.g. `/path/to/zig/zig`, used to run the custom build runner. If `null`, zig is looked up in `PATH`. Will be used to infer the zig standard library path if none is provided. | | `warn_style` | `bool` | `false` | Enables warnings for style *guideline* mismatches | -| `build_runner_path` | `?[]const u8` | `null` | Path to the build_runner.zig file provided by zls. This option must be present in one of the global configuration files to have any effect. `null` is equivalent to `${executable_directory}/build_runner.zig` | +| `build_runner_path` | `?[]const u8` | `null` | Path to the build_runner.zig file provided by zls. `null` is equivalent to `${executable_directory}/build_runner.zig` | +| `build_runner_cache_path` | `?[]const u8` | `null` | Path to a directroy that will be used as zig's cache when running `zig run build_runner.zig ...`. `null` is equivalent to `${KnownFloders.Cache}/zls` | | `enable_semantic_tokens` | `bool` | `true` | Enables semantic token support when the client also supports it. | | `operator_completions` | `bool` | `true` | Enables `*` and `?` operators in completion lists. | diff --git a/src/config.zig b/src/config.zig index bd61523..9039e59 100644 --- a/src/config.zig +++ b/src/config.zig @@ -14,10 +14,12 @@ zig_exe_path: ?[]const u8 = null, /// guide explicitly states that the style info provided is a guideline only. warn_style: bool = false, -/// Path to the build_runner.zig file. This option must be present in one of -/// the global configuration directories to have any effect. +/// Path to the build_runner.zig file. build_runner_path: ?[]const u8 = null, +/// Path to a directory that will be used as cache when `zig run`ing the build runner +build_runner_cache_path: ?[]const u8 = null, + /// Semantic token support enable_semantic_tokens: bool = true, diff --git a/src/document_store.zig b/src/document_store.zig index 5f44f3d..d329926 100644 --- a/src/document_store.zig +++ b/src/document_store.zig @@ -38,6 +38,7 @@ handles: std.StringHashMap(*Handle), zig_exe_path: ?[]const u8, build_files: std.ArrayListUnmanaged(*BuildFile), build_runner_path: []const u8, +build_runner_cache_path: []const u8, std_uri: ?[]const u8, pub fn init( @@ -45,6 +46,7 @@ pub fn init( allocator: *std.mem.Allocator, zig_exe_path: ?[]const u8, build_runner_path: []const u8, + build_runner_cache_path: []const u8, zig_lib_path: ?[]const u8, ) !void { self.allocator = allocator; @@ -52,6 +54,7 @@ pub fn init( self.zig_exe_path = zig_exe_path; self.build_files = .{}; self.build_runner_path = build_runner_path; + self.build_runner_cache_path = build_runner_cache_path; self.std_uri = try stdUriFromLibPath(allocator, zig_lib_path); } @@ -59,6 +62,7 @@ const LoadPackagesContext = struct { build_file: *BuildFile, allocator: *std.mem.Allocator, build_runner_path: []const u8, + build_runner_cache_path: []const u8, zig_exe_path: []const u8, }; @@ -66,37 +70,26 @@ fn loadPackages(context: LoadPackagesContext) !void { const allocator = context.allocator; const build_file = context.build_file; const build_runner_path = context.build_runner_path; + const build_runner_cache_path = context.build_runner_cache_path; const zig_exe_path = context.zig_exe_path; - const directory_path = try URI.parse(allocator, build_file.uri[0 .. build_file.uri.len - "build.zig".len]); - defer allocator.free(directory_path); - - const target_path = try std.fs.path.resolve(allocator, &[_][]const u8{ directory_path, "build_runner.zig" }); - defer allocator.free(target_path); - - // For example, instead of testing if a file exists and then opening it, just - // open it and handle the error for file not found. - var file_exists = true; - check_file_exists: { - var fhandle = std.fs.cwd().openFile(target_path, .{ .read = true, .write = false }) catch |err| switch (err) { - error.FileNotFound => { - file_exists = false; - break :check_file_exists; - }, - else => break :check_file_exists, - }; - fhandle.close(); - } - - if (file_exists) return error.BuildRunnerFileExists; - - try std.fs.copyFileAbsolute(build_runner_path, target_path, .{}); - defer std.fs.deleteFileAbsolute(target_path) catch {}; + const build_file_path = try URI.parse(allocator, build_file.uri); + defer allocator.free(build_file_path); + const directory_path = build_file_path[0..build_file_path.len - "build.zig".len]; const zig_run_result = try std.ChildProcess.exec(.{ .allocator = allocator, - .argv = &[_][]const u8{ zig_exe_path, "run", "build_runner.zig" }, - .cwd = directory_path, + .argv = &[_][]const u8{ + zig_exe_path, + "run", + build_runner_path, + "--cache-dir", + build_runner_cache_path, + "--pkg-begin", + "@build@", + build_file_path, + "--pkg-end", + }, }); defer { @@ -193,6 +186,7 @@ fn newDocument(self: *DocumentStore, uri: []const u8, text: []u8) anyerror!*Hand .build_file = build_file, .allocator = self.allocator, .build_runner_path = self.build_runner_path, + .build_runner_cache_path = self.build_runner_cache_path, .zig_exe_path = self.zig_exe_path.?, }) catch |err| { log.debug("Failed to load packages of build file {s} (error: {})", .{ build_file.uri, err }); @@ -399,6 +393,7 @@ pub fn applySave(self: *DocumentStore, handle: *Handle) !void { .build_file = build_file, .allocator = self.allocator, .build_runner_path = self.build_runner_path, + .build_runner_cache_path = self.build_runner_cache_path, .zig_exe_path = self.zig_exe_path.?, }) catch |err| { log.debug("Failed to load packages of build file {s} (error: {})", .{ build_file.uri, err }); @@ -428,7 +423,6 @@ pub fn applyChanges( .character = range.Object.get("end").?.Object.get("character").?.Integer, }; - const change_text = change.Object.get("text").?.String; const start_index = (try offsets.documentPosition(document.*, start_pos, offset_encoding)).absolute_index; const end_index = (try offsets.documentPosition(document.*, end_pos, offset_encoding)).absolute_index; @@ -624,6 +618,7 @@ pub fn deinit(self: *DocumentStore) void { self.allocator.free(std_uri); } self.allocator.free(self.build_runner_path); + self.allocator.free(self.build_runner_cache_path); self.build_files.deinit(self.allocator); } diff --git a/src/main.zig b/src/main.zig index 83dcd0c..fed8140 100644 --- a/src/main.zig +++ b/src/main.zig @@ -13,6 +13,7 @@ const references = @import("references.zig"); const rename = @import("rename.zig"); const offsets = @import("offsets.zig"); const semantic_tokens = @import("semantic_tokens.zig"); +const known_folders = @import("known-folders"); const logger = std.log.scoped(.main); @@ -1553,8 +1554,6 @@ pub fn main() anyerror!void { } config_read: { - const known_folders = @import("known-folders"); - const res = try known_folders.getPath(allocator, .local_configuration); if (res) |local_config_path| { defer allocator.free(local_config_path); @@ -1670,15 +1669,26 @@ pub fn main() anyerror!void { logger.warn("Zig standard library path not specified in zls.json and could not be resolved from the zig executable", .{}); } - if (config.build_runner_path) |build_runner_path| { - try document_store.init(allocator, zig_exe_path, try std.mem.dupe(allocator, u8, build_runner_path), config.zig_lib_path); - } else { + const build_runner_path = if (config.build_runner_path) |p| + try allocator.dupe(u8, p) + else blk: { var exe_dir_bytes: [std.fs.MAX_PATH_BYTES]u8 = undefined; const exe_dir_path = try std.fs.selfExeDirPath(&exe_dir_bytes); + break :blk try std.fs.path.resolve(allocator, &[_][]const u8{ exe_dir_path, "build_runner.zig" }); + }; - const build_runner_path = try std.fs.path.resolve(allocator, &[_][]const u8{ exe_dir_path, "build_runner.zig" }); - try document_store.init(allocator, zig_exe_path, build_runner_path, config.zig_lib_path); - } + const build_runner_cache_path = if (config.build_runner_path) |p| + try allocator.dupe(u8, p) + else blk: { + const cache_dir_path = (try known_folders.getPath(allocator, .cache)) orelse { + logger.warn("Known-folders could not fetch the cache path", .{}); + return; + }; + defer allocator.free(cache_dir_path); + break :blk try std.fs.path.resolve(allocator, &[_][]const u8{ cache_dir_path, "zls" }); + }; + + try document_store.init(allocator, zig_exe_path, build_runner_path, build_runner_cache_path, config.zig_lib_path); defer document_store.deinit(); // This JSON parser is passed to processJsonRpc and reset. diff --git a/src/special/build_runner.zig b/src/special/build_runner.zig index 4e5630f..5dc8786 100644 --- a/src/special/build_runner.zig +++ b/src/special/build_runner.zig @@ -1,4 +1,4 @@ -const root = @import("build.zig"); +const root = @import("@build@"); const std = @import("std"); const io = std.io; const fmt = std.fmt;