From dbab84d0694747096a274ce10a72bf9ba3738afc Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Fri, 6 Dec 2024 21:05:33 +0100 Subject: [PATCH] refactor: move bin_path to separate module make it usable for general path searches --- src/bin_path.zig | 47 ++++++++++++++++++++++++++++++++++ src/list_languages.zig | 58 ++++++------------------------------------ 2 files changed, 55 insertions(+), 50 deletions(-) create mode 100644 src/bin_path.zig diff --git a/src/bin_path.zig b/src/bin_path.zig new file mode 100644 index 0000000..756edfa --- /dev/null +++ b/src/bin_path.zig @@ -0,0 +1,47 @@ +const std = @import("std"); +const builtin = @import("builtin"); + +pub const find_binary_in_path = switch (builtin.os.tag) { + .windows => find_binary_in_path_windows, + else => find_binary_in_path_posix, +}; + +fn find_binary_in_path_posix(allocator: std.mem.Allocator, binary_name: []const u8) std.mem.Allocator.Error!?[:0]const u8 { + const bin_paths = std.process.getEnvVarOwned(allocator, "PATH") catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + error.EnvironmentVariableNotFound, error.InvalidWtf8 => &.{}, + }; + defer allocator.free(bin_paths); + var bin_path_iterator = std.mem.splitScalar(u8, bin_paths, std.fs.path.delimiter); + while (bin_path_iterator.next()) |bin_path| { + const resolved_binary_path = try std.fs.path.resolve(allocator, &.{ bin_path, binary_name }); + defer allocator.free(resolved_binary_path); + std.posix.access(resolved_binary_path, std.posix.X_OK) catch continue; + return try allocator.dupeZ(u8, resolved_binary_path); + } + return null; +} + +fn find_binary_in_path_windows(allocator: std.mem.Allocator, binary_name_: []const u8) std.mem.Allocator.Error!?[:0]const u8 { + const bin_paths = std.process.getEnvVarOwned(allocator, "PATH") catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + error.EnvironmentVariableNotFound, error.InvalidWtf8 => &.{}, + }; + defer allocator.free(bin_paths); + var path = std.ArrayList(u8).init(allocator); + try path.appendSlice(binary_name_); + try path.appendSlice(".exe"); + const binary_name = try path.toOwnedSlice(); + defer allocator.free(binary_name); + var bin_path_iterator = std.mem.splitScalar(u8, bin_paths, std.fs.path.delimiter); + while (bin_path_iterator.next()) |bin_path| { + if (!std.fs.path.isAbsolute(bin_path)) continue; + var dir = std.fs.openDirAbsolute(bin_path, .{}) catch continue; + defer dir.close(); + _ = dir.statFile(binary_name) catch continue; + const resolved_binary_path = try std.fs.path.join(allocator, &[_][]const u8{ bin_path, binary_name }); + defer allocator.free(resolved_binary_path); + return try allocator.dupeZ(u8, resolved_binary_path); + } + return null; +} diff --git a/src/list_languages.zig b/src/list_languages.zig index ab66f21..8da59d4 100644 --- a/src/list_languages.zig +++ b/src/list_languages.zig @@ -2,6 +2,8 @@ const std = @import("std"); const syntax = @import("syntax"); const builtin = @import("builtin"); +const bin_path = @import("bin_path.zig"); + const checkmark_width = if (builtin.os.tag != .windows) 2 else 3; const success_mark = if (builtin.os.tag != .windows) "✓ " else "[y]"; @@ -28,24 +30,17 @@ pub fn list(allocator: std.mem.Allocator, writer: anytype, tty_config: std.io.tt try tty_config.setColor(writer, .reset); try writer.writeAll("\n"); - const bin_paths = std.process.getEnvVarOwned(allocator, "PATH") catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - error.EnvironmentVariableNotFound, error.InvalidWtf8 => &.{}, - }; - - defer allocator.free(bin_paths); - for (syntax.FileType.file_types) |file_type| { try write_string(writer, file_type.name, max_language_len + 1); try write_segmented(writer, file_type.extensions, ",", max_extensions_len + 1, tty_config); if (file_type.language_server) |language_server| - try write_checkmark(writer, try can_execute(allocator, bin_paths, language_server[0]), tty_config); + try write_checkmark(writer, can_execute(allocator, language_server[0]), tty_config); try write_segmented(writer, file_type.language_server, " ", max_langserver_len + 1, tty_config); if (file_type.formatter) |formatter| - try write_checkmark(writer, try can_execute(allocator, bin_paths, formatter[0]), tty_config); + try write_checkmark(writer, can_execute(allocator, formatter[0]), tty_config); try write_segmented(writer, file_type.formatter, " ", max_formatter_len, tty_config); try writer.writeAll("\n"); @@ -99,45 +94,8 @@ fn write_padding(writer: anytype, len: usize, pad_len: usize) !void { for (0..pad_len - len) |_| try writer.writeAll(" "); } -const can_execute = switch (builtin.os.tag) { - .windows => can_execute_windows, - else => can_execute_posix, -}; - -fn can_execute_posix(allocator: std.mem.Allocator, bin_paths: []const u8, file_path: []const u8) std.mem.Allocator.Error!bool { - if (!std.process.can_spawn) return false; - - var bin_path_iterator = std.mem.splitScalar(u8, bin_paths, std.fs.path.delimiter); - - while (bin_path_iterator.next()) |bin_path| { - const resolved_file_path = try std.fs.path.resolve(allocator, &.{ bin_path, file_path }); - defer allocator.free(resolved_file_path); - - std.posix.access(resolved_file_path, std.posix.X_OK) catch continue; - - return true; - } - - return false; -} - -fn can_execute_windows(allocator: std.mem.Allocator, bin_paths: []const u8, file_path_: []const u8) std.mem.Allocator.Error!bool { - var path = std.ArrayList(u8).init(allocator); - try path.appendSlice(file_path_); - try path.appendSlice(".exe"); - const file_path = try path.toOwnedSlice(); - defer allocator.free(file_path); - - var bin_path_iterator = std.mem.splitScalar(u8, bin_paths, std.fs.path.delimiter); - - while (bin_path_iterator.next()) |bin_path| { - if (!std.fs.path.isAbsolute(bin_path)) continue; - var dir = std.fs.openDirAbsolute(bin_path, .{}) catch continue; - defer dir.close(); - - _ = dir.statFile(file_path) catch continue; - return true; - } - - return false; +fn can_execute(allocator: std.mem.Allocator, binary_name: []const u8) bool { + const resolved_binary_path = bin_path.find_binary_in_path(allocator, binary_name) catch return false; + defer if (resolved_binary_path) |path| allocator.free(path); + return resolved_binary_path != null; }