diff --git a/src/document_store.zig b/src/document_store.zig index d329926..c49673b 100644 --- a/src/document_store.zig +++ b/src/document_store.zig @@ -75,7 +75,7 @@ fn loadPackages(context: LoadPackagesContext) !void { 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 directory_path = build_file_path[0 .. build_file_path.len - "build.zig".len]; const zig_run_result = try std.ChildProcess.exec(.{ .allocator = allocator, @@ -191,55 +191,68 @@ fn newDocument(self: *DocumentStore, uri: []const u8, text: []u8) anyerror!*Hand }) catch |err| { log.debug("Failed to load packages of build file {s} (error: {})", .{ build_file.uri, err }); }; - } else if (self.zig_exe_path != null and !in_std) associate_build_file: { - // Look into build files to see if we already have one that fits - for (self.build_files.items) |build_file| { + } else if (self.zig_exe_path != null and !in_std) { + // Look into build files to see if we already have one that lives in the directory structure + var candidate = for (self.build_files.items) |build_file| { const build_file_base_uri = build_file.uri[0 .. std.mem.lastIndexOfScalar(u8, build_file.uri, '/').? + 1]; if (std.mem.startsWith(u8, uri, build_file_base_uri)) { - log.debug("Found an associated build file: {s}", .{build_file.uri}); - build_file.refs += 1; - handle.associated_build_file = build_file; - break :associate_build_file; + log.debug("Found a candidate associated build file: {s}", .{build_file.uri}); + break build_file; } - } - // Otherwise, try to find a build file. + } else null; + // Then, try to find the closest build file. var curr_path = try URI.parse(self.allocator, uri); defer self.allocator.free(curr_path); while (true) { - if (curr_path.len == 0) break :associate_build_file; + if (curr_path.len == 0) break; if (std.mem.lastIndexOfScalar(u8, curr_path[0 .. curr_path.len - 1], std.fs.path.sep)) |idx| { // This includes the last separator curr_path = curr_path[0 .. idx + 1]; + // Try to open the folder, then the file. var folder = std.fs.cwd().openDir(curr_path, .{}) catch |err| switch (err) { error.FileNotFound => continue, else => return err, }; defer folder.close(); - // Try to open the file, read it and add the new document if we find it. - const build_file_text = folder.readFileAlloc(self.allocator, "build.zig", std.math.maxInt(usize)) catch |err| switch (err) { + var build_file = folder.openFile("build.zig", .{}) catch |err| switch (err) { error.FileNotFound, error.AccessDenied => continue, else => return err, }; - errdefer self.allocator.free(build_file_text); + defer build_file.close(); + // Calculate build file's URI var candidate_path = try std.mem.concat(self.allocator, u8, &[_][]const u8{ curr_path, "build.zig" }); defer self.allocator.free(candidate_path); - const build_file_uri = try URI.fromPath(self.allocator, candidate_path); errdefer self.allocator.free(build_file_uri); - const build_file_handle = try self.newDocument(build_file_uri, build_file_text); - - if (build_file_handle.is_build_file) |build_file| { - build_file.refs += 1; + if (candidate) |candidate_build_file| { + // Check if it is the same as the current candidate we got from the existing build files. + // If it isn't, we need to read the file and make a new build file. + if (std.mem.eql(u8, candidate_build_file.uri, build_file_uri)) { + self.allocator.free(build_file_uri); + break; + } } - handle.associated_build_file = build_file_handle.is_build_file; + + // Read the build file, create a new document, set the candidate to the new build file. + const build_file_text = try build_file.readToEndAlloc(self.allocator, std.math.maxInt(usize)); + errdefer self.allocator.free(build_file_text); + + const build_file_handle = try self.newDocument(build_file_uri, build_file_text); + candidate = build_file_handle.is_build_file.?; break; - } else break :associate_build_file; + } else break; + } + // Finally, associate the candidate build file, if any, to the new document. + if (candidate) |build_file| { + build_file.refs += 1; + handle.associated_build_file = build_file; + log.debug("Associated build file `{s}` to document `{s}`", .{build_file.uri, handle.uri()}); } }