diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-27 21:18:46 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:14 -0300 |
| commit | 2352f0079404f31d458745e687d195d8f9c5b39f (patch) | |
| tree | 2951e4cda92aa076c38e24e4ec45e81edded376b /src/panes.zig | |
| parent | d2d31742b3381a4c550baabd55852489b91dc277 (diff) | |
| download | pardes-2352f0079404f31d458745e687d195d8f9c5b39f.tar.gz pardes-2352f0079404f31d458745e687d195d8f9c5b39f.zip | |
Move the Image pane namespace out of panes.zig into image.zig
Pure move: the body of `pub const Image = struct { ... }` now sits at the
end of image.zig, dedented, under a "the image pane" banner, so the image
thing (decoding, glyph art, and the pane that shows it) is one file. Its
nine `image.X` self-references lose the prefix; image.zig gains the four
imports the pane code uses. panes.zig keeps `pub const Image =
@import("image.zig");`, so `panes.Image.x` callers are unchanged.
image.zig joins the embedded source list, since the pane code left
panes.zig which was on it.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/panes.zig')
| -rw-r--r-- | src/panes.zig | 231 |
1 files changed, 1 insertions, 230 deletions
diff --git a/src/panes.zig b/src/panes.zig index d494cfe4..bc579a92 100644 --- a/src/panes.zig +++ b/src/panes.zig @@ -3176,236 +3176,7 @@ pub const Output = struct { pub const Mini = @import("Mini.zig"); -pub const Image = struct { - const GridKey = struct { - cols: u16 = 0, - rows: u16 = 0, - palette: image.PaletteMode = .commodore, - ascii: bool = true, - }; - - pub const State = struct { - path: []u8, - glyph_art: bool = false, - pmode: image.PaletteMode = .commodore, - ascii: bool = true, - tried: bool = false, - rgba: []u8 = &.{}, - iw: usize = 0, - ih: usize = 0, - /// Dump-loaded bytes, decoded lazily by the same path as a disk image. - raw: []u8 = &.{}, - grid: image.GlyphArt.Grid = .{ .cells = &.{}, .cols = 0, .rows = 0 }, - grid_key: GridKey = .{}, - - pub fn deinit(state: *State, gpa: std.mem.Allocator) void { - gpa.free(state.path); - if (state.rgba.len > 0) gpa.free(state.rgba); - if (state.raw.len > 0) gpa.free(state.raw); - if (state.grid.cells.len > 0) gpa.free(state.grid.cells); - state.* = undefined; - } - }; - - /// Construct an image pane from a path and optionally transferred dump bytes. - /// `raw` must be image_gpa-owned and ownership transfers only on success. - /// Without them the file is read here, not at the first draw: a draw - /// must not go out into the host (`pardes.turn`), and the path may be a - /// mount this editor serves. A file that cannot be read draws blank. - pub fn create(p: *pardes.Pardes, id: usize, path: []const u8, raw: []u8) !*pardes.Pane { - var bytes = raw; - var read_here = false; - if (bytes.len == 0) { - // The slot stays ours across the read: another request may - // make a pane meanwhile. - p.reserved_slots[id] = true; - defer p.reserved_slots[id] = false; - if (filesystem.read(p, path)) |from_disk| { - defer p.gpa.free(from_disk); - bytes = try p.image_gpa.dupe(u8, from_disk); - read_here = true; - } else |_| {} - } - errdefer if (read_here) p.image_gpa.free(bytes); - const path_copy = try p.image_gpa.dupe(u8, path); - errdefer p.image_gpa.free(path_copy); - const pane = try p.newDocPane(id); - pane.image = .{ .path = path_copy, .raw = bytes }; - return pane; - } - - /// Serialize the binary image record used by images and, for dump-schema - /// compatibility, PDFs. Common pane metadata is supplied by the core. - pub fn dumpPane( - p: *pardes.Pardes, - arena: std.mem.Allocator, - pane: *const pardes.Pane, - tag: []const u8, - body: []const u8, - scroll: usize, - path: []const u8, - raw: []const u8, - ) !dump.Pane { - const bytes = if (raw.len > 0) raw else filesystem.read(p, path) catch &.{}; - defer if (raw.len == 0) p.gpa.free(bytes); - return .{ - .kind = .image, - .tag = tag, - .body = body, - .scroll = scroll, - .cols = pane.cols, - .rows = pane.rows, - .vweight = pane.vweight, - .collapsed = pane.collapsed, - .image = .{ - .path = path, - .bytes_b64 = if (bytes.len > 0) try dump.encodeBytes(arena, bytes) else "", - .petscii = if (pane.image) |state| state.glyph_art else false, - .palette = if (pane.image) |state| switch (state.pmode) { - .commodore => .commodore, - .terminal => .terminal, - } else .commodore, - .ascii = if (pane.image) |state| state.ascii else true, - }, - }; - } - - pub fn restore(p: *pardes.Pardes, id: usize, src: dump.Pane) !*pardes.Pane { - const saved = src.image.?; - var raw: []u8 = if (saved.bytes_b64.len > 0) - try dump.decodeBytes(p.image_gpa, saved.bytes_b64) - else - &.{}; - errdefer if (raw.len > 0) p.image_gpa.free(raw); - const pane = try create(p, id, saved.path, raw); - raw = &.{}; - pane.image.?.glyph_art = saved.petscii; - pane.image.?.pmode = switch (saved.palette) { - .commodore => .commodore, - .terminal => .terminal, - }; - pane.image.?.ascii = saved.ascii; - pane.cols = @max(1, src.cols); - pane.rows = @max(1, src.rows); - return pane; - } - - pub fn toggleGlyphArt(state: *State) void { - state.glyph_art = !state.glyph_art; - } - - pub fn togglePalette(state: *State) void { - state.pmode = if (state.pmode == .commodore) .terminal else .commodore; - } - - pub fn toggleAscii(state: *State) void { - state.ascii = !state.ascii; - } - - /// Image renderer choices are pane-local, not global Config values. Keep them - /// queryable where they apply: the live tag beside the image's path. - pub fn tagPrefix(arena: std.mem.Allocator, state: *const State) ![]u8 { - return std.fmt.allocPrint( - arena, - "{s} petscii:{s} palette:{s} ascii:{s} {s}", - .{ - config.tag_image, - if (state.glyph_art) "on" else "off", - @tagName(state.pmode), - if (state.ascii) "on" else "off", - state.path, - }, - ); - } - - pub fn legacySavedPrefix(state: *const State, saved_tag: []const u8) ?[]const u8 { - const lead = config.tag_image ++ " "; - if (!std.mem.startsWith(u8, saved_tag, lead)) return null; - const path_at = lead.len; - if (!std.mem.startsWith(u8, saved_tag[path_at..], state.path)) return null; - return saved_tag[0 .. path_at + state.path.len]; - } - - fn ensureDecoded(p: *pardes.Pardes, state: *State) void { - if (state.tried) return; - state.tried = true; - if (state.raw.len == 0) return; // nothing was readable at open - if (image.decode(p.image_gpa, state.raw)) |decoded| { - state.rgba = decoded.rgba; - state.iw = decoded.w; - state.ih = decoded.h; - } - } - - fn ensureGrid(p: *pardes.Pardes, state: *State, cols: u16, rows: u16) void { - const wanted = GridKey{ .cols = cols, .rows = rows, .palette = state.pmode, .ascii = state.ascii }; - if (state.grid.cells.len > 0 and std.meta.eql(state.grid_key, wanted)) return; - if (state.grid.cells.len > 0) p.image_gpa.free(state.grid.cells); - const palette = switch (state.pmode) { - .commodore => image.GlyphArt.commodore, - .terminal => image.terminal_palette, - }; - state.grid = image.GlyphArt.render( - p.image_gpa, - state.rgba, - state.iw, - state.ih, - cols, - rows, - palette, - state.ascii, - ) catch .{ .cells = &.{}, .cols = 0, .rows = 0 }; - state.grid_key = wanted; - } - - pub fn draw( - p: *pardes.Pardes, - state: *State, - pane_id: u8, - serial: u32, - x: u16, - y: u16, - cols: u16, - rows: u16, - ) void { - ensureDecoded(p, state); - if (state.rgba.len == 0 or cols == 0 or rows == 0) return; - if (!state.glyph_art and p.native_images) { - _ = p.appendImagePlace(.{ - .pane = pane_id, - .serial = serial, - .x = x, - .y = y, - .w = cols, - .h = rows, - .rgba = state.rgba, - .iw = state.iw, - .ih = state.ih, - }); - return; - } - - ensureGrid(p, state, cols, rows); - if (state.grid.cells.len == 0) return; - const offx = if (cols > state.grid.cols) (@as(usize, cols) - state.grid.cols) / 2 else 0; - const offy = if (rows > state.grid.rows) (@as(usize, rows) - state.grid.rows) / 2 else 0; - for (0..state.grid.rows) |cy| for (0..state.grid.cols) |cx| { - const cell = &state.grid.cells[cy * state.grid.cols + cx]; - const fg: pardes.Color = switch (state.pmode) { - .commodore => .{ .rgb = image.GlyphArt.commodore[cell.fg] }, - .terminal => .{ .index = cell.fg }, - }; - const bg: pardes.Color = switch (state.pmode) { - .commodore => .{ .rgb = image.GlyphArt.commodore[cell.bg] }, - .terminal => .{ .index = cell.bg }, - }; - const sx = x + @as(u16, @intCast(offx + cx)); - const sy = y + @as(u16, @intCast(offy + cy)); - if (sx < p.surface.cols and sy < p.surface.rows) - p.surface.set(sx, sy, cell.glyph[0..cell.glyph_len], .{ .fg = fg, .bg = bg }); - }; - } -}; +pub const Image = @import("image.zig"); pub const Pdf = struct { pub const enabled = @import("pardes_config").mupdf; |
