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

fix: update zigimg + libvaxis to fix image segfault during image processing

Changed files
+70 -17
src
+9 -3
build.zig.zon
··· 2 2 .name = .jido, 3 3 .fingerprint = 0xee45eabe36cafb57, 4 4 .version = "1.3.0", 5 - .minimum_zig_version = "0.14.0", 5 + .minimum_zig_version = "0.15.2", 6 6 7 7 .dependencies = .{ 8 + // Replace with rockorager/libvaxis once https://github.com/rockorager/libvaxis/pull/293 is merged 8 9 .vaxis = .{ 9 - .url = "git+https://github.com/rockorager/libvaxis.git#75035b169e91a51c233f3742161f8eb8eafca659", 10 - .hash = "vaxis-0.5.1-BWNV_IE-CQBYmSf_boEKUyv6den0Gmj5LksxvdCx2pBL", 10 + .url = "git+https://github.com/rob9315/libvaxis.git#8d04cffd9137b4a8c56b356de98b32023ae752f3", 11 + .hash = "vaxis-0.5.1-BWNV_OA-CQDeFBHIx9ryyASogr2GE3FsAm-l5Ii5-HZT", 11 12 }, 12 13 .fuzzig = .{ 13 14 .url = "git+https://github.com/fjebaker/fuzzig#4251fe4230d38e721514394a485db62ee1667ff3", ··· 21 22 .zuid = .{ 22 23 .url = "https://github.com/BrookJeynes/zuid/archive/refs/heads/bj/2025-12-31/feat/0.15.1.tar.gz", 23 24 .hash = "zuid-3.0.0-l7aPyUlXAAAk9BLSDm2roA3i78Sy6_GvQI4hwe0PHI_m", 25 + }, 26 + // Replace with zigimg/zigimg once https://github.com/zigimg/zigimg/pull/305 is merged 27 + .zigimg = .{ 28 + .url = "git+https://github.com/brookjeynes/zigimg.git#9714df09f76891323c7fdbbbf23a17b79024fffb", 29 + .hash = "zigimg-0.1.0-8_eo2j4mFwCU7tWnqvkYtzqe-OPRn_bxEql_IJhW85LT", 24 30 }, 25 31 }, 26 32
+7 -2
src/app.zig
··· 79 79 }; 80 80 81 81 pub const Image = struct { 82 + const buf_size = (1024 * 1024) * 5; // 5mb 82 83 const Status = enum { 83 84 ready, 84 85 processing, 86 + failed, 85 87 }; 86 88 87 89 ///Only use on first transmission. Subsequent draws should use ··· 91 93 path: ?[]const u8 = null, 92 94 status: Status = .processing, 93 95 94 - pub fn deinit(self: @This(), alloc: std.mem.Allocator) void { 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 + } 95 100 if (self.data) |data| { 96 101 var d = data; 97 102 d.deinit(alloc); ··· 197 202 198 203 var image_iter = self.images.cache.iterator(); 199 204 while (image_iter.next()) |img| { 200 - img.value_ptr.deinit(self.alloc); 205 + img.value_ptr.deinit(self.alloc, self.vx, &self.tty); 201 206 } 202 207 self.images.cache.deinit(); 203 208 }
+54 -12
src/drawer.zig
··· 208 208 break :file; 209 209 } 210 210 211 + if (cache_entry.status == .failed) { 212 + _ = preview_win.print(&.{ 213 + .{ .text = "Failed to process image." }, 214 + }, .{}); 215 + break :file; 216 + } 217 + 211 218 if (cache_entry.image) |img| { 212 219 img.draw(preview_win, .{ .scale = .contain }) catch |err| { 213 220 const message = try std.fmt.allocPrint(app.alloc, "Failed to draw image to screen - {}.", .{err}); ··· 224 231 } else { 225 232 if (cache_entry.data == null) { 226 233 const path = try app.alloc.dupe(u8, self.current_item_path); 227 - var buffer: [1024]u8 = undefined; 228 - processImage(app, path, &buffer) catch break :unsupported; 234 + processImage(app, path) catch { 235 + app.alloc.free(path); 236 + break :unsupported; 237 + }; 238 + _ = preview_win.print(&.{ 239 + .{ .text = "Image still processing." }, 240 + }, .{}); 241 + break :file; 229 242 } 230 243 231 244 if (app.vx.transmitImage(app.alloc, app.tty.writer(), &cache_entry.data.?, .rgba)) |img| { ··· 241 254 break :file; 242 255 }; 243 256 cache_entry.image = img; 244 - cache_entry.data.?.deinit(app.alloc); 257 + if (cache_entry.data) |data| { 258 + var d = data; 259 + d.deinit(app.alloc); 260 + } 245 261 cache_entry.data = null; 246 262 } else |_| { 247 263 break :unsupported; ··· 250 266 251 267 break :file; 252 268 } else { 269 + _ = preview_win.print(&.{ 270 + .{ .text = "Processing image." }, 271 + }, .{}); 272 + 253 273 const path = try app.alloc.dupe(u8, self.current_item_path); 254 - var buffer: [1024]u8 = undefined; 255 - processImage(app, path, &buffer) catch break :unsupported; 274 + processImage(app, path) catch { 275 + app.alloc.free(path); 276 + break :unsupported; 277 + }; 256 278 } 257 279 258 280 break :file; ··· 630 652 }, .{ .wrap = .word }); 631 653 } 632 654 633 - fn processImage(app: *App, path: []const u8, buffer: *[1024]u8) error{ Unsupported, OutOfMemory }!void { 655 + fn processImage(app: *App, path: []const u8) error{ Unsupported, OutOfMemory }!void { 634 656 app.images.cache.put(path, .{ .path = path, .status = .processing }) catch { 635 657 const message = try std.fmt.allocPrint(app.alloc, "Failed to load image '{s}' - error occurred while attempting to add image to cache.", .{path}); 636 658 defer app.alloc.free(message); ··· 642 664 const load_img_thread = std.Thread.spawn(.{}, loadImage, .{ 643 665 app, 644 666 path, 645 - buffer, 646 - }) catch return error.Unsupported; 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 + }; 647 681 load_img_thread.detach(); 648 682 } 649 683 650 - fn loadImage(app: *App, path: []const u8, buffer: *[1024]u8) error{ Unsupported, OutOfMemory }!void { 651 - const data = vaxis.zigimg.Image.fromFilePath(app.alloc, path, buffer) catch { 684 + fn loadImage(app: *App, path: []const u8) error{OutOfMemory}!void { 685 + var buf: [(1024 * 1024) * 5]u8 = undefined; 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 + 652 693 const message = try std.fmt.allocPrint(app.alloc, "Failed to load image '{s}' - error occurred while attempting to read image from path.", .{path}); 653 694 defer app.alloc.free(message); 654 695 app.notification.write(message, .err) catch {}; 655 696 if (app.file_logger) |file_logger| file_logger.write(message, .err) catch {}; 656 - return error.Unsupported; 697 + 698 + return; 657 699 }; 658 700 659 701 app.images.mutex.lock(); ··· 665 707 defer app.alloc.free(message); 666 708 app.notification.write(message, .err) catch {}; 667 709 if (app.file_logger) |file_logger| file_logger.write(message, .err) catch {}; 668 - return error.Unsupported; 710 + return; 669 711 } 670 712 app.images.mutex.unlock(); 671 713