diff options
| author | Gabriel Schneider <[email protected]> | 2026-06-30 20:29:43 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-06-30 22:21:44 -0300 |
| commit | f6089186cfe1517073fafc8979a7546ec773d6c1 (patch) | |
| tree | cfb474b5a5cff5d7197aa5084ea6013a0c53df6f /main.zig | |
| parent | 8b60c2c29c016c7db0fa6ee63769cea1defd9b3c (diff) | |
| download | pardes-full-prototype.tar.gz pardes-full-prototype.zip | |
stealing petsciinatorfull-prototype
Diffstat (limited to 'main.zig')
| -rw-r--r-- | main.zig | 46 |
1 files changed, 37 insertions, 9 deletions
@@ -392,7 +392,12 @@ fn isDir(path: [*:0]const u8) bool { // selectable text (acme-style). Caller frees with `alloc`. fn tagLine(alloc: std.mem.Allocator, t: *Term) ![]u8 { // an image pane's tag: a label + path (+ builtins); display-only, no mode/cwd. - if (t.image) |iv| return std.fmt.allocPrint(alloc, "img {s} {s}", .{ iv.path, pane_builtins_str }); + if (t.image) |iv| { + // toggles: Petscii (glyph art on/off), the color mode (C64 = commodore / + // Term = terminal palette), Ascii (include ascii glyphs in the matcher). + const mode = if (iv.pmode == .commodore) "C64" else "Term"; + return std.fmt.allocPrint(alloc, "img {s} Petscii {s} Ascii {s}", .{ iv.path, mode, pane_builtins_str }); + } // a file pane's tag: mode + path (+ builtins); no cwd. Files never reach tty. if (t.file) |f| { const fmode = if (t.mode == .insert) "in" else "nm"; @@ -625,7 +630,7 @@ fn openFileView(gpa: std.mem.Allocator, rp: [*:0]const u8, line: usize, cols: u1 // sharing the layout machinery. No pty (handle -1), no reader, a stub 1x1 emulator // (only its allocator-owned bits are touched). The render loop transmits + draws // the image (see image.zig). `rp` is the absolute path. Caller wires it in + frees. -fn openImageView(gpa: std.mem.Allocator, rp: [*:0]const u8, cols: u16, rows: u16) !*Term { +fn openImageView(gpa: std.mem.Allocator, rp: [*:0]const u8, cols: u16, rows: u16, petscii: bool) !*Term { const path = try gpa.dupe(u8, std.mem.span(rp)); errdefer gpa.free(path); const t = try gpa.create(Term); @@ -636,7 +641,7 @@ fn openImageView(gpa: std.mem.Allocator, rp: [*:0]const u8, cols: u16, rows: u16 .term = try ghostty_vt.Terminal.init(gpa, .{ .cols = 1, .rows = 1 }), .stream = undefined, .reader = .{ .any_future = null, .result = {} }, - .image = .{ .path = path }, + .image = .{ .path = path, .petscii = petscii }, .cols = cols, .rows = rows, }; @@ -950,7 +955,7 @@ fn renderPane(root: vaxis.Window, alloc: std.mem.Allocator, t: *Term, r: Rect, a // gutter so it reads like any other pane. kitty placements are re-issued each // frame, so this runs every render. Nothing else (text/cursor/selection) applies. if (t.image) |*iv| { - if (r.h > BOX_H) image.draw(iv, text.child(.{ .y_off = BOX_H, .height = r.h - BOX_H })); + if (r.h > BOX_H) image.draw(iv, text.child(.{ .y_off = BOX_H, .height = r.h - BOX_H }), r.w - GUTTER, r.h - BOX_H); const gut = root.child(.{ .x_off = r.x, .y_off = r.y, .width = GUTTER, .height = r.h }); const box_bg = if (active) accent else accent_dim; var gy: u16 = 0; @@ -2167,6 +2172,23 @@ fn actOnSelection( txt: []const u8, ) bool { const t = terms[id] orelse return false; + // image-pane tagline toggles (middle-click, acme execute): Petscii on/off, the + // C64/Term color mode, and Ascii glyphs. Intercept before the builtin/run dispatch. + if (button == .middle) if (t.image) |*iv| { + const w = std.mem.trim(u8, txt, " \t\r\n"); + if (std.mem.eql(u8, w, "Petscii")) { + iv.petscii = !iv.petscii; + return false; + } + if (std.mem.eql(u8, w, "C64") or std.mem.eql(u8, w, "Term")) { + iv.pmode = if (iv.pmode == .commodore) .terminal else .commodore; + return false; + } + if (std.mem.eql(u8, w, "Ascii")) { + iv.ascii = !iv.ascii; + return false; + } + }; if (button == .right) { // acme "look": resolve the selected word (peeling a :line suffix) relative // to the window's dir. A directory opens/focuses a terminal there + ls; a @@ -2214,9 +2236,9 @@ fn actOnSelection( } } else { const fp = std.mem.span(rp); - // an image opens as an IMAGE pane, but only when the terminal reported - // the kitty-graphics capability; otherwise it falls back to a text view. - const as_image = images_ok and image.isImagePath(fp); + // image paths open as IMAGE panes; they render via kitty when supported, + // else via the PETSCII fallback (also toggleable on the pane's tagline). + const as_image = image.isImagePath(fp); // focus an existing pane already showing this path (file or image) var found: ?usize = null; for (terms, 0..) |*slot, i| if (slot.*) |tt| { @@ -2238,7 +2260,7 @@ fn actOnSelection( } else null; if (slot) |free| { const opened: ?*Term = if (as_image) - (openImageView(gpa, rp, sw, sh) catch null) + (openImageView(gpa, rp, sw, sh, !images_ok) catch null) // petscii by default when no kitty else (openFileView(gpa, rp, pl.line, sw, sh) catch null); if (opened) |nt| { @@ -2882,7 +2904,13 @@ pub fn main(init: std.process.Init) !void { if (slot.*) |t| { // image panes transmit lazily (needs the tty writer, which lives // here on the render thread); renderPane then re-places the picture. - if (t.image) |*iv| image.ensureLoaded(iv, &vx, gpa, tty.writer()); + if (t.image) |*iv| { + image.ensureLoaded(iv, &vx, gpa, tty.writer()); + const r = rects[id]; + const bc = if (r.w > GUTTER) r.w - GUTTER else 0; + const br = if (r.h > BOX_H) r.h - BOX_H else 0; + image.ensureGrid(iv, gpa, bc, br); + } try renderPane(win, frame_arena.allocator(), t, rects[id], id == active); } } |
