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

feat: Added force delete keybind. It's unbound by default. docs: Updated README and example-config.json to show how to unbound keybinds. chore: bumped patch version and updated CHANGELOG.

+4
CHANGELOG.md
··· 1 1 # Changelog 2 2 3 + ## v0.9.6 (2025-03-31) 4 + - feat: Added ability to unbound keybinds. 5 + - feat: Added force delete keybind. It's unbound by default. 6 + 3 7 ## v0.9.5 (2025-03-29) 4 8 - feat: Added [-v | --version] and [-h | --help] args. 5 9
+1 -1
PROJECT_BOARD.md
··· 12 12 - [ ] Copy files. 13 13 - [ ] Copy folders. 14 14 - [ ] Keybind to unzip archives. 15 - - [ ] Keybind to hard delete items (bypass trash). 15 + - [x] Keybind to hard delete items (bypass trash). 16 16 - [x] Ability to unbind keys. 17 17 18 18 ### Refactors
+3 -1
README.md
··· 111 111 .enter_command_mode: ?Char = ':', 112 112 .jump_top: ?Char = 'g', 113 113 .jump_bottom: ?Char = 'G', 114 - .toggle_verbose_file_information: ?Char = 'v' 114 + .toggle_verbose_file_information: ?Char = 'v', 115 + .force_delete: ?Char = null -- Files deleted this way are 116 + not recoverable 115 117 } 116 118 117 119 NotificationStyles = struct {
+1 -1
build.zig
··· 2 2 const builtin = @import("builtin"); 3 3 4 4 ///Must match the `version` in `build.zig.zon`. 5 - const version = std.SemanticVersion{ .major = 0, .minor = 9, .patch = 5 }; 5 + const version = std.SemanticVersion{ .major = 0, .minor = 9, .patch = 6 }; 6 6 7 7 const targets: []const std.Target.Query = &.{ 8 8 .{ .cpu_arch = .aarch64, .os_tag = .macos },
+1 -1
build.zig.zon
··· 1 1 .{ 2 2 .name = .jido, 3 3 .fingerprint = 0xee45eabe36cafb57, 4 - .version = "0.9.5", 4 + .version = "0.9.6", 5 5 .minimum_zig_version = "0.14.0", 6 6 7 7 .dependencies = .{
+2 -1
example-config.json
··· 4 4 "show_images": true, 5 5 "preview_file": true, 6 6 "keybinds": { 7 - "toggle_hidden_files": "h" 7 + "toggle_hidden_files": "h", 8 + "force_delete": null 8 9 }, 9 10 "styles": { 10 11 "selected_list_item": {
+1
src/config.zig
··· 209 209 jump_top: ?Char = @enumFromInt('g'), 210 210 jump_bottom: ?Char = @enumFromInt('G'), 211 211 toggle_verbose_file_information: ?Char = @enumFromInt('v'), 212 + force_delete: ?Char = null, 212 213 }; 213 214 214 215 const Styles = struct {
+16 -3
src/event_handlers.zig
··· 174 174 app.text_input.insertSliceAtCursor(":") catch {}; 175 175 app.state = .command; 176 176 }, 177 - .jump_bottom => { 178 - app.directories.entries.selectLast(); 179 - }, 177 + .jump_bottom => app.directories.entries.selectLast(), 180 178 .jump_top => app.directories.entries.selectFirst(), 181 179 .toggle_verbose_file_information => app.drawer.verbose = !app.drawer.verbose, 180 + .force_delete => { 181 + const entry = lbl: { 182 + const entry = app.directories.getSelected() catch { 183 + try app.notification.writeErr(.UnableToDelete); 184 + return; 185 + }; 186 + if (entry) |e| break :lbl e else return; 187 + }; 188 + 189 + app.directories.dir.deleteTree(entry.name) catch { 190 + try app.notification.writeErr(.UnableToDelete); 191 + return; 192 + }; 193 + app.directories.removeSelected(); 194 + }, 182 195 } 183 196 } else { 184 197 switch (key.codepoint) {