diff --git a/src/app.zig b/src/app.zig index 763dff0..75419a0 100644 --- a/src/app.zig +++ b/src/app.zig @@ -8,6 +8,7 @@ const List = @import("./list.zig").List; const Directories = @import("./directories.zig"); const FileLogger = @import("./file_logger.zig"); const CircStack = @import("./circ_stack.zig").CircularStack; +const Image = @import("./image.zig"); const zuid = @import("zuid"); const vaxis = @import("vaxis"); const Key = vaxis.Key; @@ -79,32 +80,6 @@ pub const Event = union(enum) { winsize: vaxis.Winsize, }; -pub const Image = struct { - const Status = enum { - ready, - processing, - failed, - }; - - ///Only use on first transmission. Subsequent draws should use - ///`Image.image`. - data: ?vaxis.zigimg.Image = null, - image: ?vaxis.Image = null, - path: ?[]const u8 = null, - status: Status = .processing, - - pub fn deinit(self: @This(), alloc: std.mem.Allocator, vx: vaxis.Vaxis, tty: *vaxis.Tty) void { - if (self.image) |image| { - vx.freeImage(tty.writer(), image.id); - } - if (self.data) |data| { - var d = data; - d.deinit(alloc); - } - if (self.path) |path| alloc.free(path); - } -}; - const actions_len = 100; const image_cache_cap = 100; @@ -132,10 +107,7 @@ text_input_buf: [std.fs.max_path_bytes]u8 = undefined, yanked: ?struct { dir: []const u8, entry: std.fs.Dir.Entry } = null, last_known_height: usize, -images: struct { - mutex: std.Thread.Mutex = .{}, - cache: std.StringHashMap(Image), -}, +images: Image.Cache, pub fn init(alloc: std.mem.Allocator, entry_dir: ?[]const u8) !App { var vx = try vaxis.init(alloc, .{ diff --git a/src/drawer.zig b/src/drawer.zig index e04bd18..779cad5 100644 --- a/src/drawer.zig +++ b/src/drawer.zig @@ -8,6 +8,7 @@ const vaxis = @import("vaxis"); const Git = @import("./git.zig"); const List = @import("./list.zig").List; const zeit = @import("zeit"); +const Image = @import("./image.zig"); const Drawer = @This(); @@ -231,7 +232,7 @@ fn drawFilePreview( } else { if (cache_entry.data == null) { const path = try app.alloc.dupe(u8, self.current_item_path); - processImage(app, path) catch { + Image.processImage(app.alloc, app, path) catch { app.alloc.free(path); break :unsupported; }; @@ -271,7 +272,7 @@ fn drawFilePreview( }, .{}); const path = try app.alloc.dupe(u8, self.current_item_path); - processImage(app, path) catch { + Image.processImage(app.alloc, app, path) catch { app.alloc.free(path); break :unsupported; }; @@ -651,66 +652,3 @@ fn drawNotification( .style = config.styles.notification.box, }, .{ .wrap = .word }); } - -fn processImage(app: *App, path: []const u8) error{ Unsupported, OutOfMemory }!void { - app.images.cache.put(path, .{ .path = path, .status = .processing }) catch { - const message = try std.fmt.allocPrint(app.alloc, "Failed to load image '{s}' - error occurred while attempting to add image to cache.", .{path}); - defer app.alloc.free(message); - app.notification.write(message, .err) catch {}; - if (app.file_logger) |file_logger| file_logger.write(message, .err) catch {}; - return error.Unsupported; - }; - - const load_img_thread = std.Thread.spawn(.{}, loadImage, .{ - app, - path, - }) catch { - app.images.mutex.lock(); - if (app.images.cache.getPtr(path)) |entry| { - entry.status = .failed; - } - app.images.mutex.unlock(); - - const message = try std.fmt.allocPrint(app.alloc, "Failed to load image '{s}' - error occurred while attempting to spawn processing thread.", .{path}); - defer app.alloc.free(message); - app.notification.write(message, .err) catch {}; - if (app.file_logger) |file_logger| file_logger.write(message, .err) catch {}; - - return error.Unsupported; - }; - load_img_thread.detach(); -} - -fn loadImage(app: *App, path: []const u8) error{OutOfMemory}!void { - var buf: [(1024 * 1024) * 5]u8 = undefined; // 5mb - const data = vaxis.zigimg.Image.fromFilePath(app.alloc, path, &buf) catch { - app.images.mutex.lock(); - if (app.images.cache.getPtr(path)) |entry| { - entry.status = .failed; - } - app.images.mutex.unlock(); - - const message = try std.fmt.allocPrint(app.alloc, "Failed to load image '{s}' - error occurred while attempting to read image from path.", .{path}); - defer app.alloc.free(message); - app.notification.write(message, .err) catch {}; - if (app.file_logger) |file_logger| file_logger.write(message, .err) catch {}; - - return; - }; - - app.images.mutex.lock(); - if (app.images.cache.getPtr(path)) |entry| { - entry.status = .ready; - entry.data = data; - entry.path = path; - } else { - const message = try std.fmt.allocPrint(app.alloc, "Failed to load image '{s}' - error occurred while attempting to add image to cache.", .{path}); - defer app.alloc.free(message); - app.notification.write(message, .err) catch {}; - if (app.file_logger) |file_logger| file_logger.write(message, .err) catch {}; - return; - } - app.images.mutex.unlock(); - - app.loop.postEvent(.image_ready); -} diff --git a/src/image.zig b/src/image.zig new file mode 100644 index 0000000..85e7e45 --- /dev/null +++ b/src/image.zig @@ -0,0 +1,99 @@ +const std = @import("std"); +const vaxis = @import("vaxis"); +const App = @import("app.zig"); + + +pub const Cache = struct { + mutex: std.Thread.Mutex = .{}, + cache: std.StringHashMap(Image), +}; + +const Status = enum { + ready, + processing, + failed, +}; + +const Image = @This(); + +///Only use on first transmission. Subsequent draws should use +///`Image.image`. +data: ?vaxis.zigimg.Image = null, +image: ?vaxis.Image = null, +path: ?[]const u8 = null, +status: Status = .processing, + +pub fn deinit(self: @This(), alloc: std.mem.Allocator, vx: vaxis.Vaxis, tty: *vaxis.Tty) void { + if (self.image) |image| { + vx.freeImage(tty.writer(), image.id); + } + if (self.data) |data| { + var d = data; + d.deinit(alloc); + } + if (self.path) |path| alloc.free(path); +} + +pub fn processImage(alloc: std.mem.Allocator, app: *App, path: []const u8) error{ Unsupported, OutOfMemory }!void { + app.images.cache.put(path, .{ .path = path, .status = .processing }) catch { + const message = try std.fmt.allocPrint(alloc, "Failed to load image '{s}' - error occurred while attempting to add image to cache.", .{path}); + defer alloc.free(message); + app.notification.write(message, .err) catch {}; + if (app.file_logger) |file_logger| file_logger.write(message, .err) catch {}; + return error.Unsupported; + }; + + const load_img_thread = std.Thread.spawn(.{}, loadImage, .{ + alloc, + app, + path, + }) catch { + app.images.mutex.lock(); + if (app.images.cache.getPtr(path)) |entry| { + entry.status = .failed; + } + app.images.mutex.unlock(); + + const message = try std.fmt.allocPrint(alloc, "Failed to load image '{s}' - error occurred while attempting to spawn processing thread.", .{path}); + defer alloc.free(message); + app.notification.write(message, .err) catch {}; + if (app.file_logger) |file_logger| file_logger.write(message, .err) catch {}; + + return error.Unsupported; + }; + load_img_thread.detach(); +} + +fn loadImage(alloc: std.mem.Allocator, app: *App, path: []const u8) error{OutOfMemory}!void { + var buf: [(1024 * 1024) * 5]u8 = undefined; // 5mb + const data = vaxis.zigimg.Image.fromFilePath(alloc, path, &buf) catch { + app.images.mutex.lock(); + if (app.images.cache.getPtr(path)) |entry| { + entry.status = .failed; + } + app.images.mutex.unlock(); + + const message = try std.fmt.allocPrint(alloc, "Failed to load image '{s}' - error occurred while attempting to read image from path.", .{path}); + defer alloc.free(message); + app.notification.write(message, .err) catch {}; + if (app.file_logger) |file_logger| file_logger.write(message, .err) catch {}; + + return; + }; + + app.images.mutex.lock(); + if (app.images.cache.getPtr(path)) |entry| { + entry.status = .ready; + entry.data = data; + entry.path = path; + } else { + const message = try std.fmt.allocPrint(alloc, "Failed to load image '{s}' - error occurred while attempting to add image to cache.", .{path}); + defer alloc.free(message); + app.notification.write(message, .err) catch {}; + if (app.file_logger) |file_logger| file_logger.write(message, .err) catch {}; + return; + } + app.images.mutex.unlock(); + + app.loop.postEvent(.image_ready); +}