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

refactor: Image struct from app.zig -> image.zig

+104 -95
+2 -30
src/app.zig
··· 8 8 const Directories = @import("./directories.zig"); 9 9 const FileLogger = @import("./file_logger.zig"); 10 10 const CircStack = @import("./circ_stack.zig").CircularStack; 11 + const Image = @import("./image.zig"); 11 12 const zuid = @import("zuid"); 12 13 const vaxis = @import("vaxis"); 13 14 const Key = vaxis.Key; ··· 79 80 winsize: vaxis.Winsize, 80 81 }; 81 82 82 - pub const Image = struct { 83 - const Status = enum { 84 - ready, 85 - processing, 86 - failed, 87 - }; 88 - 89 - ///Only use on first transmission. Subsequent draws should use 90 - ///`Image.image`. 91 - data: ?vaxis.zigimg.Image = null, 92 - image: ?vaxis.Image = null, 93 - path: ?[]const u8 = null, 94 - status: Status = .processing, 95 - 96 - pub fn deinit(self: @This(), alloc: std.mem.Allocator, vx: vaxis.Vaxis, tty: *vaxis.Tty) void { 97 - if (self.image) |image| { 98 - vx.freeImage(tty.writer(), image.id); 99 - } 100 - if (self.data) |data| { 101 - var d = data; 102 - d.deinit(alloc); 103 - } 104 - if (self.path) |path| alloc.free(path); 105 - } 106 - }; 107 - 108 83 const actions_len = 100; 109 84 const image_cache_cap = 100; 110 85 ··· 132 107 yanked: ?struct { dir: []const u8, entry: std.fs.Dir.Entry } = null, 133 108 last_known_height: usize, 134 109 135 - images: struct { 136 - mutex: std.Thread.Mutex = .{}, 137 - cache: std.StringHashMap(Image), 138 - }, 110 + images: Image.Cache, 139 111 140 112 pub fn init(alloc: std.mem.Allocator, entry_dir: ?[]const u8) !App { 141 113 var vx = try vaxis.init(alloc, .{
+3 -65
src/drawer.zig
··· 8 8 const Git = @import("./git.zig"); 9 9 const List = @import("./list.zig").List; 10 10 const zeit = @import("zeit"); 11 + const Image = @import("./image.zig"); 11 12 12 13 const Drawer = @This(); 13 14 ··· 231 232 } else { 232 233 if (cache_entry.data == null) { 233 234 const path = try app.alloc.dupe(u8, self.current_item_path); 234 - processImage(app, path) catch { 235 + Image.processImage(app.alloc, app, path) catch { 235 236 app.alloc.free(path); 236 237 break :unsupported; 237 238 }; ··· 271 272 }, .{}); 272 273 273 274 const path = try app.alloc.dupe(u8, self.current_item_path); 274 - processImage(app, path) catch { 275 + Image.processImage(app.alloc, app, path) catch { 275 276 app.alloc.free(path); 276 277 break :unsupported; 277 278 }; ··· 651 652 .style = config.styles.notification.box, 652 653 }, .{ .wrap = .word }); 653 654 } 654 - 655 - fn processImage(app: *App, path: []const u8) error{ Unsupported, OutOfMemory }!void { 656 - app.images.cache.put(path, .{ .path = path, .status = .processing }) catch { 657 - const message = try std.fmt.allocPrint(app.alloc, "Failed to load image '{s}' - error occurred while attempting to add image to cache.", .{path}); 658 - defer app.alloc.free(message); 659 - app.notification.write(message, .err) catch {}; 660 - if (app.file_logger) |file_logger| file_logger.write(message, .err) catch {}; 661 - return error.Unsupported; 662 - }; 663 - 664 - const load_img_thread = std.Thread.spawn(.{}, loadImage, .{ 665 - app, 666 - path, 667 - }) catch { 668 - app.images.mutex.lock(); 669 - if (app.images.cache.getPtr(path)) |entry| { 670 - entry.status = .failed; 671 - } 672 - app.images.mutex.unlock(); 673 - 674 - const message = try std.fmt.allocPrint(app.alloc, "Failed to load image '{s}' - error occurred while attempting to spawn processing thread.", .{path}); 675 - defer app.alloc.free(message); 676 - app.notification.write(message, .err) catch {}; 677 - if (app.file_logger) |file_logger| file_logger.write(message, .err) catch {}; 678 - 679 - return error.Unsupported; 680 - }; 681 - load_img_thread.detach(); 682 - } 683 - 684 - fn loadImage(app: *App, path: []const u8) error{OutOfMemory}!void { 685 - var buf: [(1024 * 1024) * 5]u8 = undefined; // 5mb 686 - const data = vaxis.zigimg.Image.fromFilePath(app.alloc, path, &buf) catch { 687 - app.images.mutex.lock(); 688 - if (app.images.cache.getPtr(path)) |entry| { 689 - entry.status = .failed; 690 - } 691 - app.images.mutex.unlock(); 692 - 693 - const message = try std.fmt.allocPrint(app.alloc, "Failed to load image '{s}' - error occurred while attempting to read image from path.", .{path}); 694 - defer app.alloc.free(message); 695 - app.notification.write(message, .err) catch {}; 696 - if (app.file_logger) |file_logger| file_logger.write(message, .err) catch {}; 697 - 698 - return; 699 - }; 700 - 701 - app.images.mutex.lock(); 702 - if (app.images.cache.getPtr(path)) |entry| { 703 - entry.status = .ready; 704 - entry.data = data; 705 - entry.path = path; 706 - } else { 707 - const message = try std.fmt.allocPrint(app.alloc, "Failed to load image '{s}' - error occurred while attempting to add image to cache.", .{path}); 708 - defer app.alloc.free(message); 709 - app.notification.write(message, .err) catch {}; 710 - if (app.file_logger) |file_logger| file_logger.write(message, .err) catch {}; 711 - return; 712 - } 713 - app.images.mutex.unlock(); 714 - 715 - app.loop.postEvent(.image_ready); 716 - }
+99
src/image.zig
··· 1 + const std = @import("std"); 2 + const vaxis = @import("vaxis"); 3 + const App = @import("app.zig"); 4 + 5 + 6 + pub const Cache = struct { 7 + mutex: std.Thread.Mutex = .{}, 8 + cache: std.StringHashMap(Image), 9 + }; 10 + 11 + const Status = enum { 12 + ready, 13 + processing, 14 + failed, 15 + }; 16 + 17 + const Image = @This(); 18 + 19 + ///Only use on first transmission. Subsequent draws should use 20 + ///`Image.image`. 21 + data: ?vaxis.zigimg.Image = null, 22 + image: ?vaxis.Image = null, 23 + path: ?[]const u8 = null, 24 + status: Status = .processing, 25 + 26 + pub fn deinit(self: @This(), alloc: std.mem.Allocator, vx: vaxis.Vaxis, tty: *vaxis.Tty) void { 27 + if (self.image) |image| { 28 + vx.freeImage(tty.writer(), image.id); 29 + } 30 + if (self.data) |data| { 31 + var d = data; 32 + d.deinit(alloc); 33 + } 34 + if (self.path) |path| alloc.free(path); 35 + } 36 + 37 + pub fn processImage(alloc: std.mem.Allocator, app: *App, path: []const u8) error{ Unsupported, OutOfMemory }!void { 38 + app.images.cache.put(path, .{ .path = path, .status = .processing }) catch { 39 + const message = try std.fmt.allocPrint(alloc, "Failed to load image '{s}' - error occurred while attempting to add image to cache.", .{path}); 40 + defer alloc.free(message); 41 + app.notification.write(message, .err) catch {}; 42 + if (app.file_logger) |file_logger| file_logger.write(message, .err) catch {}; 43 + return error.Unsupported; 44 + }; 45 + 46 + const load_img_thread = std.Thread.spawn(.{}, loadImage, .{ 47 + alloc, 48 + app, 49 + path, 50 + }) catch { 51 + app.images.mutex.lock(); 52 + if (app.images.cache.getPtr(path)) |entry| { 53 + entry.status = .failed; 54 + } 55 + app.images.mutex.unlock(); 56 + 57 + const message = try std.fmt.allocPrint(alloc, "Failed to load image '{s}' - error occurred while attempting to spawn processing thread.", .{path}); 58 + defer alloc.free(message); 59 + app.notification.write(message, .err) catch {}; 60 + if (app.file_logger) |file_logger| file_logger.write(message, .err) catch {}; 61 + 62 + return error.Unsupported; 63 + }; 64 + load_img_thread.detach(); 65 + } 66 + 67 + fn loadImage(alloc: std.mem.Allocator, app: *App, path: []const u8) error{OutOfMemory}!void { 68 + var buf: [(1024 * 1024) * 5]u8 = undefined; // 5mb 69 + const data = vaxis.zigimg.Image.fromFilePath(alloc, path, &buf) catch { 70 + app.images.mutex.lock(); 71 + if (app.images.cache.getPtr(path)) |entry| { 72 + entry.status = .failed; 73 + } 74 + app.images.mutex.unlock(); 75 + 76 + const message = try std.fmt.allocPrint(alloc, "Failed to load image '{s}' - error occurred while attempting to read image from path.", .{path}); 77 + defer alloc.free(message); 78 + app.notification.write(message, .err) catch {}; 79 + if (app.file_logger) |file_logger| file_logger.write(message, .err) catch {}; 80 + 81 + return; 82 + }; 83 + 84 + app.images.mutex.lock(); 85 + if (app.images.cache.getPtr(path)) |entry| { 86 + entry.status = .ready; 87 + entry.data = data; 88 + entry.path = path; 89 + } else { 90 + const message = try std.fmt.allocPrint(alloc, "Failed to load image '{s}' - error occurred while attempting to add image to cache.", .{path}); 91 + defer alloc.free(message); 92 + app.notification.write(message, .err) catch {}; 93 + if (app.file_logger) |file_logger| file_logger.write(message, .err) catch {}; 94 + return; 95 + } 96 + app.images.mutex.unlock(); 97 + 98 + app.loop.postEvent(.image_ready); 99 + }