summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-29 08:14:42 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:16 -0300
commita630f5e83ef9efabca790770112dcea689384631 (patch)
tree390d6e6b08cba9e0964d05af1f8d0005aba47c6c /src
parent2f1b7cd5fb82e619043ccb34826154a53e53c28e (diff)
downloadpardes-a630f5e83ef9efabca790770112dcea689384631.tar.gz
pardes-a630f5e83ef9efabca790770112dcea689384631.zip
A new terminal's greeting `ls` goes at its shell's first prompt or never
The greeting waited for any moment the cursor sat at a prompt's input, so where the first prompt was missed (a resize still pending, a line written before it), `ls` was typed later into whatever ran then. It is now sent only while nothing has run (pardes's marks saw no command start) and nothing is typed at the prompt; past that it is dropped, never typed late. A prompt drawn again for a resize is still the first. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src')
-rw-r--r--src/Terminal.zig21
-rw-r--r--src/pardes.zig18
2 files changed, 34 insertions, 5 deletions
diff --git a/src/Terminal.zig b/src/Terminal.zig
index 4808298e..32595d25 100644
--- a/src/Terminal.zig
+++ b/src/Terminal.zig
@@ -1013,6 +1013,27 @@ pub fn onAlternateScreen(pane: *const Pane) bool {
return state.vt.screens.active_key == .alternate;
}
+/// Whether a new terminal's greeting may be typed now: only at the shell's
+/// first prompt (pardes's own marks: no command started; a prompt drawn
+/// again for a resize is the same first prompt), with nothing
+/// typed at it and no program on the alternate screen. Any later moment is `.never`, for good: something has run or
+/// been typed first, and an `ls` then would go into it. A shell pardes
+/// cannot mark has no first prompt to find, and is never greeted.
+pub fn greeting(pane: *const Pane) enum { wait, now, never } {
+ if (comptime !enabled) return .never;
+ if (pane.fs.unmarked) return .never;
+ // Text typed into the edit buffer that stands in for the prompt row.
+ if (pane.ovl) |o| if (o.text.len > 0) return .never;
+ const state = pane.terminal orelse return .wait;
+ const marks = &state.stream.handler;
+ // (Not `declined`: bash's first prompt comes after a D of its own.)
+ if (marks.started > 0) return .never;
+ // At a prompt's input (ghostty's semantic marks, pardes's or the
+ // shell's own), before any command pardes's marks saw run.
+ if (!promptInputReady(pane)) return .wait;
+ return if (promptInputEmpty(pane)) .now else .never;
+}
+
pub fn promptInputReady(pane: *const Pane) bool {
if (comptime !enabled) return false;
const state = pane.terminal orelse return false;
diff --git a/src/pardes.zig b/src/pardes.zig
index 3a574dc9..de4d6abc 100644
--- a/src/pardes.zig
+++ b/src/pardes.zig
@@ -6686,11 +6686,19 @@ pub const Pardes = struct {
if (pane.file) |*file| file.syntax_dirty = true;
}
panes.Terminal.releasePendingCommandIfReady(p, id, pane);
- if (pane.greet and pane.isTerminal() and p.resize_count > 0 and panes.Terminal.promptInputReady(pane)) {
- p.emit(.{ .resize_pty = .{ .pane = @intCast(id), .cols = pane.cols, .rows = pane.rows } });
- p.emit(.{ .write = .{ .pane = @intCast(id), .bytes = .from("ls\r") } });
- pane.greet = false;
- }
+ // The greeting `ls` of a new terminal in a directory is typed at
+ // its shell's FIRST prompt, or never: typed later it would land
+ // in whatever runs then, or in the middle of a line someone
+ // typed (panes.Terminal.greeting).
+ if (pane.greet and pane.isTerminal() and p.resize_count > 0) switch (panes.Terminal.greeting(pane)) {
+ .wait => {},
+ .never => pane.greet = false,
+ .now => {
+ p.emit(.{ .resize_pty = .{ .pane = @intCast(id), .cols = pane.cols, .rows = pane.rows } });
+ p.emit(.{ .write = .{ .pane = @intCast(id), .bytes = .from("ls\r") } });
+ pane.greet = false;
+ },
+ };
}
}