地圖 (Jido) is a lightweight Unix TUI file explorer designed for speed and simplicity.

feat: add `--entry-dir=PATH` arg

This arg allows jido to be opened within a specified directory.

+89 -44
+2 -2
src/app.zig
··· 131 131 cache: std.StringHashMap(Image), 132 132 }, 133 133 134 - pub fn init(alloc: std.mem.Allocator) !App { 134 + pub fn init(alloc: std.mem.Allocator, entry_dir: ?[]const u8) !App { 135 135 var vx = try vaxis.init(alloc, .{ 136 136 .kitty_keyboard_flags = .{ 137 137 .report_text = false, ··· 150 150 .should_quit = false, 151 151 .vx = vx, 152 152 .tty = try vaxis.Tty.init(), 153 - .directories = try Directories.init(alloc), 153 + .directories = try Directories.init(alloc, entry_dir), 154 154 .help_menu = help_menu, 155 155 .text_input = vaxis.widgets.TextInput.init(alloc, &vx.unicode), 156 156 .actions = CircStack(Action, actions_len).init(),
+15 -13
src/commands.zig
··· 131 131 try app.repopulateDirectory(""); 132 132 } 133 133 134 + pub fn resolvePath(buf: *[std.fs.max_path_bytes]u8, path: []const u8, dir: std.fs.Dir) []const u8 { 135 + const resolved_path = if (std.mem.startsWith(u8, path, "~")) path: { 136 + var home_dir = (environment.getHomeDir() catch break :path path) orelse break :path path; 137 + defer home_dir.close(); 138 + const relative = std.mem.trim(u8, path[1..], std.fs.path.sep_str); 139 + return home_dir.realpath( 140 + if (relative.len == 0) "." else relative, 141 + buf, 142 + ) catch path; 143 + } else path; 144 + 145 + return dir.realpath(resolved_path, buf) catch path; 146 + } 147 + 134 148 ///Change directory. 135 149 pub fn cd(app: *App, path: []const u8) error{OutOfMemory}!void { 136 150 var message: ?[]const u8 = null; 137 151 defer if (message) |msg| app.alloc.free(msg); 138 152 139 153 var path_buf: [std.fs.max_path_bytes]u8 = undefined; 140 - const resolved_path = lbl: { 141 - const resolved_path = if (std.mem.startsWith(u8, path, "~")) path: { 142 - var home_dir = (environment.getHomeDir() catch break :path path) orelse break :path path; 143 - defer home_dir.close(); 144 - const relative = std.mem.trim(u8, path[1..], std.fs.path.sep_str); 145 - break :lbl home_dir.realpath( 146 - if (relative.len == 0) "." else relative, 147 - &path_buf, 148 - ) catch path; 149 - } else path; 150 - 151 - break :lbl app.directories.dir.realpath(resolved_path, &path_buf) catch path; 152 - }; 154 + const resolved_path = resolvePath(&path_buf, path, app.directories.dir); 153 155 154 156 const dir = app.directories.dir.openDir(resolved_path, .{ .iterate = true }) catch |err| { 155 157 message = switch (err) {
+1
src/config.zig
··· 18 18 preview_file: bool = true, 19 19 empty_trash_on_exit: bool = false, 20 20 true_dir_size: bool = false, 21 + entry_dir: ?[]const u8 = null, 21 22 styles: Styles = .{}, 22 23 keybinds: Keybinds = .{}, 23 24
+16 -2
src/directories.zig
··· 19 19 child_entries: List([]const u8), 20 20 searcher: fuzzig.Ascii, 21 21 22 - pub fn init(alloc: std.mem.Allocator) !Self { 22 + pub fn init(alloc: std.mem.Allocator, entry_dir: ?[]const u8) !Self { 23 + const dir_path = if (entry_dir) |dir| dir else "."; 24 + const dir = std.fs.cwd().openDir(dir_path, .{ .iterate = true }) catch |err| { 25 + switch (err) { 26 + error.FileNotFound => { 27 + std.log.err("path '{s}' could not be found.", .{dir_path}); 28 + return err; 29 + }, 30 + else => { 31 + std.log.err("{}", .{err}); 32 + return err; 33 + }, 34 + } 35 + }; 36 + 23 37 return Self{ 24 38 .alloc = alloc, 25 - .dir = try std.fs.cwd().openDir(".", .{ .iterate = true }), 39 + .dir = dir, 26 40 .entries = List(std.fs.Dir.Entry).init(alloc), 27 41 .history = CircStack(usize, history_len).init(), 28 42 .child_entries = List([]const u8).init(alloc),
+55 -27
src/main.zig
··· 5 5 const FileLogger = @import("file_logger.zig"); 6 6 const vaxis = @import("vaxis"); 7 7 const config = &@import("./config.zig").config; 8 + const resolvePath = @import("./commands.zig").resolvePath; 8 9 9 10 pub const panic = vaxis.panic_handler; 10 11 ··· 25 26 } 26 27 const alloc = gpa.allocator(); 27 28 29 + var entry_buf: [std.fs.max_path_bytes]u8 = undefined; 30 + var entry_dir_path: ?[]const u8 = null; 31 + 28 32 var args = std.process.args(); 29 33 _ = args.skip(); 30 - if (args.next()) |arg| { 34 + while (args.next()) |arg| { 31 35 if (std.mem.eql(u8, arg, "--version") or std.mem.eql(u8, arg, "-v")) { 32 36 std.debug.print("jido v{}\n", .{options.version}); 33 37 return; ··· 42 46 \\Flags: 43 47 \\ -h, --help Show help information and exit. 44 48 \\ -v, --version Print version information and exit. 49 + \\ --entry-dir=PATH Open jido at chosen dir. 45 50 \\ 46 51 , .{}); 47 52 return; 48 53 } 54 + 55 + if (std.mem.startsWith(u8, arg, "--entry-dir")) { 56 + var path: ?[]const u8 = null; 57 + if (arg.len > 11 and arg[11] == '=') { 58 + var iter = std.mem.tokenizeAny(u8, arg, "="); 59 + _ = iter.next(); 60 + if (iter.next()) |p| path = p; 61 + } else { 62 + if (args.next()) |p| path = p; 63 + } 64 + 65 + if (path) |p| { 66 + var dir = try std.fs.cwd().openDir(".", .{ .iterate = true }); 67 + defer dir.close(); 68 + entry_dir_path = resolvePath(&entry_buf, p, dir); 69 + } 70 + } 49 71 } 50 72 51 - var app = try App.init(alloc); 52 - defer app.deinit(); 73 + { 74 + var app = App.init(alloc, entry_dir_path) catch { 75 + vaxis.recover(); 76 + std.posix.exit(1); 77 + }; 78 + defer app.deinit(); 53 79 54 - config.parse(alloc, &app) catch |err| switch (err) { 55 - error.SyntaxError => { 56 - app.notification.write("Encountered a syntax error while parsing the config file.", .err) catch { 57 - std.log.err("Encountered a syntax error while parsing the config file.", .{}); 58 - }; 59 - }, 60 - error.InvalidCharacter => { 61 - app.notification.write("One or more overriden keybinds are invalid.", .err) catch { 62 - std.log.err("One or more overriden keybinds are invalid.", .{}); 63 - }; 64 - }, 65 - error.DuplicateKeybind => { 66 - // Error logged in function 67 - }, 68 - else => { 69 - const message = try std.fmt.allocPrint(alloc, "Encountend an unknown error while parsing the config file - {}", .{err}); 70 - defer alloc.free(message); 80 + config.parse(alloc, &app) catch |err| switch (err) { 81 + error.SyntaxError => { 82 + app.notification.write("Encountered a syntax error while parsing the config file.", .err) catch { 83 + std.log.err("Encountered a syntax error while parsing the config file.", .{}); 84 + }; 85 + }, 86 + error.InvalidCharacter => { 87 + app.notification.write("One or more overriden keybinds are invalid.", .err) catch { 88 + std.log.err("One or more overriden keybinds are invalid.", .{}); 89 + }; 90 + }, 91 + error.DuplicateKeybind => { 92 + // Error logged in function 93 + }, 94 + else => { 95 + const message = try std.fmt.allocPrint(alloc, "Encountend an unknown error while parsing the config file - {}", .{err}); 96 + defer alloc.free(message); 97 + 98 + app.notification.write(message, .err) catch { 99 + std.log.err("Encountend an unknown error while parsing the config file - {}", .{err}); 100 + }; 101 + }, 102 + }; 71 103 72 - app.notification.write(message, .err) catch { 73 - std.log.err("Encountend an unknown error while parsing the config file - {}", .{err}); 74 - }; 75 - }, 76 - }; 104 + app.file_logger = if (config.config_dir) |dir| FileLogger.init(dir) else null; 77 105 78 - app.file_logger = if (config.config_dir) |dir| FileLogger.init(dir) else null; 106 + try app.run(); 107 + } 79 108 80 - try app.run(); 81 109 }