summaryrefslogtreecommitdiff
path: root/src/tagline.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-29 09:52:33 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:16 -0300
commita72d0c6650242a9b02858de7020e9a4ae387ebba (patch)
tree8f3d44da4e32ad85bf7abf52c2852dbe62a7904f /src/tagline.zig
parentad3403adb72e3457eb76d6b3fc91cf8df3d738ae (diff)
downloadpardes-a72d0c6650242a9b02858de7020e9a4ae387ebba.tar.gz
pardes-a72d0c6650242a9b02858de7020e9a4ae387ebba.zip
A name shows its own backslash as \\, and a terminal tag never carries a raw newline
With `\n` for a newline and `\xNN` for a bad byte, a name holding a backslash and an n read back as one holding a newline. Names in /index, the log and a terminal's tag now double their own backslashes; and a terminal's directory with a newline no longer breaks its tag. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/tagline.zig')
-rw-r--r--src/tagline.zig21
1 files changed, 16 insertions, 5 deletions
diff --git a/src/tagline.zig b/src/tagline.zig
index d024be4e..5f95b2a0 100644
--- a/src/tagline.zig
+++ b/src/tagline.zig
@@ -112,6 +112,17 @@ pub fn revealHeader(p: *Pardes) void {
}
}
+/// A terminal's directory as its tag shows it: one line, as /index shows
+/// it (a newline `\n`), never a raw newline breaking the tag.
+fn shownDir(arena: std.mem.Allocator, pane: *Pane) ![]const u8 {
+ const dir = pane.cwdSlice();
+ if (std.mem.indexOfAny(u8, dir, "\n\\\x7f") == null and for (dir) |c| {
+ if (c < ' ') break false;
+ } else true) return dir;
+ const out = try arena.alloc(u8, dir.len * 4 + 4);
+ return pardes.ctlfs.events.shown(dir, out);
+}
+
/// 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.
@@ -133,19 +144,19 @@ pub fn pathPrefix(arena: std.mem.Allocator, pane: *Pane) ![]const u8 {
var idbuf: [48]u8 = undefined;
const id = exec.replId(&idbuf, pane);
const gap = if (id.len > 0) " " else "";
- if (!pane.command_done) return std.fmt.allocPrint(arena, "{s} ({s}{s}) running{s}{s}", .{ pane.cwdSlice(), shown, more, gap, id });
- if (pane.command_status) |n| return std.fmt.allocPrint(arena, "{s} ({s}{s}) exit {d}{s}{s}", .{ pane.cwdSlice(), shown, more, n, gap, id });
- return std.fmt.allocPrint(arena, "{s} ({s}{s}) exit ?{s}{s}", .{ pane.cwdSlice(), shown, more, gap, id });
+ if (!pane.command_done) return std.fmt.allocPrint(arena, "{s} ({s}{s}) running{s}{s}", .{ (try shownDir(arena, pane)), shown, more, gap, id });
+ if (pane.command_status) |n| return std.fmt.allocPrint(arena, "{s} ({s}{s}) exit {d}{s}{s}", .{ (try shownDir(arena, pane)), shown, more, n, gap, id });
+ return std.fmt.allocPrint(arena, "{s} ({s}{s}) exit ?{s}{s}", .{ (try shownDir(arena, pane)), shown, more, gap, id });
}
// A bound REPL says what it is bound as, beside its Tty word.
if (pane.repl != null) {
var idbuf: [48]u8 = undefined;
- return std.fmt.allocPrint(arena, "{s} {s}", .{ pane.cwdSlice(), exec.replId(&idbuf, pane) });
+ return std.fmt.allocPrint(arena, "{s} {s}", .{ (try shownDir(arena, pane)), exec.replId(&idbuf, pane) });
}
// Unsaved text shows on the grip, as acme's modbutton does, not as a
// mark in the text: the prefix is the name alone.
if (pane.file) |f| return if (pane.prompt == .name) pane.input.own orelse f.path else f.path;
- return pane.cwdSlice();
+ return (try shownDir(arena, pane));
}
pub fn tagPrefix(p: *Pardes, pane: *Pane) ![]u8 {