summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-10-01 13:30:42 -0300
committerGabriel Schneider <[email protected]>2026-10-01 13:44:34 -0300
commitbac1c62c1905a5ce11a6b630d556bc349041628b (patch)
treeea3e154923ca5f36adb3e0e65920a17e464ca55f
parent7c84ebe66494c3b05dcd23f198b5c5f4189cb708 (diff)
downloadpardes-bac1c62c1905a5ce11a6b630d556bc349041628b.tar.gz
pardes-bac1c62c1905a5ce11a6b630d556bc349041628b.zip
An image's or a terminal's tag says petscii:on when it is drawn as glyph art, as it always is with no graphics; Petscii on|off still chooses for when there are
The images and tagbottomimage goldens are re-recorded for the word. Co-Authored-By: Claude Opus 5.5 <[email protected]>
-rw-r--r--src/edit.zig2
-rw-r--r--src/image.zig6
-rw-r--r--src/ninep/ctl.zig9
-rw-r--r--src/ninep/pane.zig2
-rw-r--r--src/pardes.zig6
-rw-r--r--src/tagline.zig18
-rw-r--r--src/terminal.zig4
-rw-r--r--test/panes.zig2
-rw-r--r--test/snapshots/images.golden18
-rw-r--r--test/snapshots/tagbottomimage.golden6
10 files changed, 44 insertions, 29 deletions
diff --git a/src/edit.zig b/src/edit.zig
index 1305d66f..3e3ba341 100644
--- a/src/edit.zig
+++ b/src/edit.zig
@@ -500,7 +500,7 @@ pub fn setEditTextEnd(p: *Pardes, t: *Text, new: []u8, known_end: ?modal.Cursor)
// caller reads the new text back, as a body's is kept.
defer retireEditText(p, new);
const pane = t.pane() orelse return;
- const prefix = tagline.pathPrefix(p.scratch.allocator(), pane) catch return;
+ const prefix = tagline.pathPrefix(p, p.scratch.allocator(), pane) catch return;
if (!std.mem.startsWith(u8, new, prefix)) {
t.refused = true;
return;
diff --git a/src/image.zig b/src/image.zig
index 4a8bcdf4..72520ad6 100644
--- a/src/image.zig
+++ b/src/image.zig
@@ -919,13 +919,15 @@ pub fn toggleAscii(state: *State) void {
/// 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 {
+/// `glyphs`: whether the picture is drawn as glyph art, which a terminal
+/// with no graphics does whatever `glyph_art` says.
+pub fn tagPrefix(arena: std.mem.Allocator, state: *const State, glyphs: bool) ![]u8 {
return std.fmt.allocPrint(
arena,
"{s} petscii:{s} palette:{s} ascii:{s} {s}",
.{
config.tag_image,
- if (state.glyph_art) "on" else "off",
+ if (glyphs) "on" else "off",
@tagName(state.pmode),
if (state.ascii) "on" else "off",
state.path,
diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig
index f2490e38..75e4b823 100644
--- a/src/ninep/ctl.zig
+++ b/src/ninep/ctl.zig
@@ -1855,6 +1855,15 @@ test "a builtin for one kind of pane is refused on another, and still acts on it
const glyphs = doc.image.?.glyph_art;
try testing.expectEqual(Status.ok, wr(p, Node.of(doc.serial, .ctl), "Petscii\n").reply.status);
try testing.expect(doc.image.?.glyph_art != glyphs);
+ // Its tag says what is drawn: with no graphics, glyph art whatever
+ // Petscii chose; with them, what it chose.
+ for ([_]bool{ false, true }) |art| {
+ doc.image.?.glyph_art = art;
+ p.native_images = false;
+ try testing.expect(std.mem.indexOf(u8, try pardes.tagline.tagPrefix(p, doc), " petscii:on ") != null);
+ p.native_images = true;
+ try testing.expect(std.mem.indexOf(u8, try pardes.tagline.tagPrefix(p, doc), if (art) " petscii:on " else " petscii:off ") != null);
+ }
}
test "exec Save writes the named file through the host" {
diff --git a/src/ninep/pane.zig b/src/ninep/pane.zig
index ae4dcd71..92ce8d8a 100644
--- a/src/ninep/pane.zig
+++ b/src/ninep/pane.zig
@@ -751,7 +751,7 @@ pub fn applyTagTruncation(p: *Pardes, pane: *Pane) void {
pane.tag.own = empty;
// what is left is the prefix; the cursor goes after it
pane.tag.cur_row = 0;
- pane.tag.cur_col = if (tagline.pathPrefix(p.scratch.allocator(), pane)) |prefix| @intCast(prefix.len) else |_| 0;
+ pane.tag.cur_col = if (tagline.pathPrefix(p, p.scratch.allocator(), pane)) |prefix| @intCast(prefix.len) else |_| 0;
pane.tag.vsel.active = false;
pane.tag.nsel = 0;
pf.tag_rewrite = true;
diff --git a/src/pardes.zig b/src/pardes.zig
index 310a4b56..d0bb9229 100644
--- a/src/pardes.zig
+++ b/src/pardes.zig
@@ -7136,7 +7136,7 @@ pub const Pardes = struct {
var wrap_room: [32 * 1024]u8 = undefined;
var wrap_fba = std.heap.FixedBufferAllocator.init(&wrap_room);
const wa = wrap_fba.allocator();
- const prefix = tagline.prefixIn(wa, pane) catch return pane.tag_rows;
+ const prefix = tagline.prefixIn(p, wa, pane) catch return pane.tag_rows;
const whole = std.mem.concat(wa, u8, &.{ prefix, tagline.curTail(pane) }) catch return pane.tag_rows;
const shown = tagline.wrapTag(wa, whole, tagline.tagWidth(p, id)) catch return pane.tag_rows;
return @intCast(@max(BOX_H, @min(shown.rows(), MAX_TAG_ROWS)));
@@ -7195,7 +7195,7 @@ pub const Pardes = struct {
// every event may take from the scratch arena.
var room: [2 * limits.host_path_cap + 256]u8 = undefined;
var measure = std.heap.FixedBufferAllocator.init(&room);
- const lead = if (tagline.prefixIn(measure.allocator(), pane)) |prefix| prefix.len else |_| pane.tag_lead;
+ const lead = if (tagline.prefixIn(p, measure.allocator(), pane)) |prefix| prefix.len else |_| pane.tag_lead;
if (lead != pane.tag_lead) {
const t = &pane.tag;
const old: i32 = @intCast(pane.tag_lead);
@@ -7215,7 +7215,7 @@ pub const Pardes = struct {
var lines = std.mem.count(u8, tagline.curTail(pane), "\n") + 1;
var wanted = lines;
var caret_row: usize = @intCast(@max(0, pane.tag.cur_row));
- if (tagline.prefixIn(wa, pane)) |prefix| {
+ if (tagline.prefixIn(p, wa, pane)) |prefix| {
if (std.mem.concat(wa, u8, &.{ prefix, tagline.curTail(pane) })) |whole| {
if (tagline.wrapTag(wa, whole, tagline.tagWidth(p, id))) |shown| {
lines = shown.rows();
diff --git a/src/tagline.zig b/src/tagline.zig
index 5a9e2346..a1ce437d 100644
--- a/src/tagline.zig
+++ b/src/tagline.zig
@@ -94,10 +94,11 @@ fn shownDir(arena: std.mem.Allocator, pane: *Pane) ![]const u8 {
/// The computed start of a pane's tag -- its path and dirty marker, a
/// PDF's page, a terminal's directory -- without the space that parts it
/// from the tag's own text. It is never stored, and never edited.
-pub fn pathPrefix(arena: std.mem.Allocator, pane: *Pane) ![]const u8 {
+pub fn pathPrefix(p: *const Pardes, arena: std.mem.Allocator, pane: *Pane) ![]const u8 {
if (comptime pdf_enabled) if (pane.pdf) |pv|
return std.fmt.allocPrint(arena, "{s} [{d}/{d}]", .{ pv.path, pv.page + 1, pv.page_count });
- if (pane.image) |*state| return panes.Image.tagPrefix(arena, state);
+ // What is drawn: with no graphics, glyph art whatever `Petscii` says.
+ if (pane.image) |*state| return panes.Image.tagPrefix(arena, state, state.glyph_art or !p.native_images);
// A command pane: its directory, the line it runs, and how that went.
// Its first line only, cut to 48 bytes at a character's start: a tag's
// first row is where the prefix ends, and a line that ran over to a
@@ -127,18 +128,21 @@ pub fn pathPrefix(arena: std.mem.Allocator, pane: *Pane) ![]const u8 {
if (pane.file) |f| return if (pane.prompt == .name) pane.input.own orelse f.path else f.path;
// A terminal showing kitty graphics says how it draws them, as an image
// pane does, and so does one drawing them as glyph art by choice.
- if (panes.terminal.petscii(pane)) |on| if (on or panes.terminal.hasImages(pane))
- return std.fmt.allocPrint(arena, "{s} petscii:{s}", .{ (try shownDir(arena, pane)), if (on) "on" else "off" });
+ if (panes.terminal.petscii(pane)) |chosen| {
+ const on = chosen or !p.native_images;
+ if (chosen or panes.terminal.hasImages(pane))
+ return std.fmt.allocPrint(arena, "{s} petscii:{s}", .{ (try shownDir(arena, pane)), if (on) "on" else "off" });
+ }
return (try shownDir(arena, pane));
}
pub fn tagPrefix(p: *Pardes, pane: *Pane) ![]u8 {
- return prefixIn(p.scratch.allocator(), pane);
+ return prefixIn(p, p.scratch.allocator(), pane);
}
/// The prefix as the tag shows it, built in `arena`.
-pub fn prefixIn(arena: std.mem.Allocator, pane: *Pane) ![]u8 {
- const prefix = try pathPrefix(arena, pane);
+pub fn prefixIn(p: *const Pardes, arena: std.mem.Allocator, pane: *Pane) ![]u8 {
+ const prefix = try pathPrefix(p, arena, pane);
// The space between the prefix and the tag's own text is the text's
// (every default starts with one), but the prefix is computed, so it
// cannot trust the text to keep it: with it deleted, Look and Exec
diff --git a/src/terminal.zig b/src/terminal.zig
index 80b9455c..140dae76 100644
--- a/src/terminal.zig
+++ b/src/terminal.zig
@@ -3072,8 +3072,8 @@ test "without pixels, or by the Petscii builtin, a terminal's image is glyph art
try std.testing.expectEqual(@as(usize, 0), imagePlaces(s).len);
try std.testing.expect(painted(s.at(tx, y)) and painted(s.at(tx + 1, y)));
try std.testing.expect(!painted(s.at(tx + 2, y)));
- // The tag says so, as an image pane's does.
- try std.testing.expect(std.mem.indexOf(u8, try tagline.tagPrefix(p, pane), " petscii:off") != null);
+ // The tag says what is drawn, glyph art, as an image pane's does.
+ try std.testing.expect(std.mem.indexOf(u8, try tagline.tagPrefix(p, pane), " petscii:on") != null);
// Pixels where they can be drawn; the builtin flips the pane to glyphs
// and back.
diff --git a/test/panes.zig b/test/panes.zig
index 935defb5..8f1c510a 100644
--- a/test/panes.zig
+++ b/test/panes.zig
@@ -3142,7 +3142,7 @@ const ImageTests = struct {
toggleGlyphArt(&state);
togglePalette(&state);
toggleAscii(&state);
- const tag = try tagPrefix(std.testing.allocator, &state);
+ const tag = try tagPrefix(std.testing.allocator, &state, state.glyph_art);
defer std.testing.allocator.free(tag);
try std.testing.expectEqualStrings(
config.tag_image ++ " petscii:on palette:terminal ascii:off /tmp/picture.ppm",
diff --git a/test/snapshots/images.golden b/test/snapshots/images.golden
index e888460d..0f15804b 100644
--- a/test/snapshots/images.golden
+++ b/test/snapshots/images.golden
@@ -5,8 +5,8 @@
| ls ls
| pic.ppm pic.ppm
|
-| img petscii:off palette:commodore ascii:on /tmp/pardes-snap/images/cwd/p
-| ic.ppm Tty Collapse Del
+| img petscii:on palette:commodore ascii:on /tmp/pardes-snap/images/cwd/pi
+| c.ppm Tty Collapse Del
| x🬱\╲🬌\~▄🬥4▟g*🬺🬶_🬆🬻
| >A8🬌Cq&.\H&🬹🬜C▛🬻
| ><e'🬷y🬙▄Fso🬴🬆🬹
@@ -26,8 +26,8 @@
|3: 0-0 d,#608269, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 #e5eee5,#608269, 76-149 #e5eee5,#0d1410,
|4: 0-0 d,#608269, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 #e5eee5,#608269, 76-149 #e5eee5,#0d1410,
|5: 0-0 d,#608269, 1-74 d,#0d1410, 75-75 d,#608269, 76-149 d,#0d1410,
-|6: 0-1 d,#add38a, 2-2 d,#314738, 3-73 #becfc4,#314738, 74-74 #dfbce5,#314738, 75-75 #dfbce5,#608269, 76-149 #dfbce5,#0d1410,
-|7: 0-2 d,#314738, 3-9 #dfbce5,#314738, 10-74 #becfc4,#314738, 75-75 #becfc4,#608269, 76-149 #becfc4,#0d1410,
+|6: 0-1 d,#add38a, 2-2 d,#314738, 3-72 #becfc4,#314738, 73-74 #dfbce5,#314738, 75-75 #dfbce5,#608269, 76-149 #dfbce5,#0d1410,
+|7: 0-2 d,#314738, 3-8 #dfbce5,#314738, 9-74 #becfc4,#314738, 75-75 #becfc4,#608269, 76-149 #becfc4,#0d1410,
|8: 0-0 d,#152019, 1-28 d,#0d1410, 29-30 #959595,#6c6c6c, 31-31 #6c6c6c,#959595, 32-32 #959595,#6c6c6c, 33-33 #6c6c6c,#959595, 34-35 #959595,#6c6c6c, 36-36 #6c6c6c,#959595, 37-37 #959595,#6c6c6c, 38-40 #6c6c6c,#959595, 41-41 #959595,#6c6c6c, 42-43 #6c6c6c,#959595, 44-44 #959595,#6c6c6c, 45-45 #6c6c6c,#6c5eb5, 46-46 #352879,#959595, 47-74 #352879,#0d1410, 75-75 #352879,#608269, 76-149 #352879,#0d1410,
|9: 0-0 d,#152019, 1-28 d,#0d1410, 29-29 #959595,#6c6c6c, 30-31 #6c6c6c,#959595, 32-35 #959595,#6c6c6c, 36-36 #6c6c6c,#959595, 37-38 #959595,#6c6c6c, 39-42 #6c6c6c,#959595, 43-43 #6c6c6c,#352879, 44-44 #352879,#6c6c6c, 45-46 #352879,#352879, 47-74 #352879,#0d1410, 75-75 #352879,#608269, 76-149 #352879,#0d1410,
|10: 0-0 d,#152019, 1-28 d,#0d1410, 29-30 #959595,#6c6c6c, 31-31 #6c6c6c,#959595, 32-32 #959595,#6c6c6c, 33-33 #6c6c6c,#959595, 34-34 #959595,#6c6c6c, 35-36 #6c6c6c,#959595, 37-39 #959595,#6c6c6c, 40-40 #6c6c6c,#959595, 41-41 #6c6c6c,#6c5eb5, 42-42 #352879,#6c5eb5, 43-46 #352879,#352879, 47-74 #352879,#0d1410, 75-75 #352879,#608269, 76-149 #352879,#0d1410,
@@ -52,8 +52,8 @@
|29: 0-0 d,#608269, 1-74 d,#0d1410, 75-75 d,#608269, 76-149 d,#0d1410,
|30: 0-0 d,#608269, 1-74 d,#0d1410, 75-75 d,#608269, 76-149 d,#0d1410,
== style term-palette grid=150x31
-|6: 0-1 d,#add38a, 2-2 d,#314738, 3-72 #becfc4,#314738, 73-74 #dfbce5,#314738, 75-75 #dfbce5,#608269, 76-149 #dfbce5,#0d1410,
-|7: 0-2 d,#314738, 3-8 #dfbce5,#314738, 9-74 #becfc4,#314738, 75-75 #becfc4,#608269, 76-149 #becfc4,#0d1410,
+|6: 0-1 d,#add38a, 2-2 d,#314738, 3-71 #becfc4,#314738, 72-74 #dfbce5,#314738, 75-75 #dfbce5,#608269, 76-149 #dfbce5,#0d1410,
+|7: 0-2 d,#314738, 3-7 #dfbce5,#314738, 8-74 #becfc4,#314738, 75-75 #becfc4,#608269, 76-149 #becfc4,#0d1410,
|8: 0-0 d,#152019, 1-65 d,#0d1410, 66-66 d,#1d2824, 67-74 #b2c3b8,#1d2824, 75-75 #b2c3b8,#608269, 76-149 #b2c3b8,#0d1410,
|9: 0-0 d,#152019, 1-29 d,#0d1410, 30-33 p8,p4, 34-34 p4,p8, 35-35 p8,p4, 36-36 p4,p8, 37-43 p8,p4, 44-44 p8,p12, 45-45 p12,p8, 46-74 p12,#0d1410, 75-75 p12,#608269, 76-149 p12,#0d1410,
|10: 0-0 d,#152019, 1-29 d,#0d1410, 30-30 p4,p8, 31-31 p8,p4, 32-32 p4,p8, 33-41 p8,p4, 42-43 p12,p8, 44-45 p12,p12, 46-74 p12,#0d1410, 75-75 p12,#608269, 76-149 p12,#0d1410,
@@ -64,7 +64,7 @@
|15: 0-0 d,#152019, 1-29 d,#0d1410, 30-30 p4,p8, 31-31 p8,p4, 32-32 p8,p12, 33-33 p12,p8, 34-45 p12,p12, 46-74 p12,#0d1410, 75-75 p12,#608269, 76-149 p12,#0d1410,
|16: 0-0 d,#152019, 1-29 d,#0d1410, 30-30 p8,p12, 31-31 p12,p8, 32-45 p12,p12, 46-74 p12,#0d1410, 75-75 p12,#608269, 76-149 p12,#0d1410,
== snap no-ascii grid=150x31 cursor=11,8
-|6: img petscii:off palette:terminal ascii:off /tmp/pardes-snap/images/cwd/p
+|6: img petscii:on palette:terminal ascii:off /tmp/pardes-snap/images/cwd/pi
|8: Ascii
|9: ██████████████🬝🬹
|10: ██████🬛█████🬝▄
@@ -74,14 +74,14 @@
|14: ████🬝▄
|15: │█🬝▄
|16: 🬝🬹
-== snap tag-edit grid=400x31 cursor=87,6
+== snap tag-edit grid=400x31 cursor=86,6
|Newcol Joincol Find Grep Help Changelog Tutor Dump Themes Config Debug Exit
| New Tty Find Grep Joincol Delcol New Tty Find Grep Joincol Delcol
| /tmp/pardes-snap/images/cwd Tty+bash Save Mode Filter Collapse Del /tmp/pardes-snap/images/cwd Tty+bash Save Mode Filter Collapse Del
| ls ls
| pic.ppm pic.ppm
|
-| img petscii:off palette:terminal ascii:off /tmp/pardes-snap/images/cwd/pic.ppm Zork Tty Collapse Del
+| img petscii:on palette:terminal ascii:off /tmp/pardes-snap/images/cwd/pic.ppm Zork Tty Collapse Del
| ███╱█🬻██🬺██🬻███╱██🬴▄
| 🬬██╱███╱🬻🬝🬻🬬████🬝🬵█
| █╲█🬴████╲╱█🬝██▟▄█
diff --git a/test/snapshots/tagbottomimage.golden b/test/snapshots/tagbottomimage.golden
index 2bf9231e..ce6948bf 100644
--- a/test/snapshots/tagbottomimage.golden
+++ b/test/snapshots/tagbottomimage.golden
@@ -5,7 +5,7 @@
| ls
| pic.ppm
|
-| img petscii:off palette:commodore ascii:on /tmp/pardes-snap/tagbottomimage/cwd/pic.ppm Tty Collapse Del
+| img petscii:on palette:commodore ascii:on /tmp/pardes-snap/tagbottomimage/cwd/pic.ppm Tty Collapse Del
| 4*🬹~F~N🬰|G🬏▚Y~KF🬴s<fcSf🬰b^🬘J%🬝ZH|S_"Z}╲%'"qA🬗a🬝🬻
| 8jDStG▄40e~.>>T&zZ/🬻iTY=`S~╳bkZR37v🬦🬵d4QHZ8X▛▟
| ^🬪🬛$}DrydNU&wsz=`*r🬒🬓🬳🬟*Y🬴G6🬧f🬮/>t🬧u🬲1Rg1t🬝🬻█
@@ -59,7 +59,7 @@
|27: P4🬜1🬝~█
|28: 🬮G🬝🬹
|29: 🬭▟█
-|30: img petscii:off palette:commodore ascii:on /tmp/pardes-snap/tagbottomimage/cwd/pic.ppm Tty Collapse Del
+|30: img petscii:on palette:commodore ascii:on /tmp/pardes-snap/tagbottomimage/cwd/pic.ppm Tty Collapse Del
== style img-bottom grid=150x31
|0: 0-149 #b2c3b8,#1d2824,
|1: 0-1 d,#887455, 2-2 d,#314738, 3-149 #becfc4,#314738,
@@ -91,7 +91,7 @@
|27: 0-0 d,#152019, 1-52 d,#0d1410, 53-54 #959595,#6c6c6c, 55-56 #6c6c6c,#959595, 57-57 #6c6c6c,#352879, 58-58 #959595,#352879, 59-59 #352879,#6c5eb5, 60-98 #352879,#352879, 99-149 #352879,#0d1410,
|28: 0-0 d,#152019, 1-52 d,#0d1410, 53-54 #959595,#6c6c6c, 55-55 #6c6c6c,#352879, 56-56 #352879,#6c6c6c, 57-98 #352879,#352879, 99-149 #352879,#0d1410,
|29: 0-0 d,#152019, 1-52 d,#0d1410, 53-53 #352879,#6c6c6c, 54-54 #352879,#959595, 55-55 #352879,#6c5eb5, 56-98 #352879,#352879, 99-149 #352879,#0d1410,
-|30: 0-1 d,#add38a, 2-2 d,#314738, 3-81 #becfc4,#314738, 82-89 #dfbce5,#314738, 90-149 #becfc4,#314738,
+|30: 0-1 d,#add38a, 2-2 d,#314738, 3-80 #becfc4,#314738, 81-88 #dfbce5,#314738, 89-149 #becfc4,#314738,
== snap search-prompt grid=150x31 cursor=149,6
|6: /ZZ
== snap del-image grid=150x31 cursor=5,7