summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/fs.md5
-rw-r--r--src/Terminal.zig7
-rw-r--r--src/exec.zig6
-rw-r--r--src/pardes.zig5
4 files changed, 22 insertions, 1 deletions
diff --git a/docs/fs.md b/docs/fs.md
index 3efc5b36..ebc85f12 100644
--- a/docs/fs.md
+++ b/docs/fs.md
@@ -240,7 +240,10 @@ same tree without leaving the process.
which shows its output and then `exit N` (its tag reads `<dir> (<line>)
running`, then `exit N`), and stays. The directory's next command runs in
that pane once it is done, below what it showed, after a `% <line>` line;
- one still running gets a second pane. A command pane's own exec starts
+ one still running gets a second pane. Before the next command the pane
+ leaves any alternate screen and turns off the modes a program left on
+ (mouse reports, bracketed paste, a hidden cursor); a command that clears
+ the screen and its scrollback (`clear`, ED3) erases the history above it. A command pane's own exec starts
the next command there too. The log says `run <serial> <word>` and `exit
<serial> <N|?>`; `exec` reads back the command pane's serial; Kill ends
its whole process group; a line is at most 1 KB. A misspelled word is a
diff --git a/src/Terminal.zig b/src/Terminal.zig
index cd292e5f..e204b44c 100644
--- a/src/Terminal.zig
+++ b/src/Terminal.zig
@@ -932,6 +932,13 @@ test "raw terminal output needs no position tracking allocations" {
try std.testing.expectEqual(pins, pane.terminal.?.vt.screens.active.pages.countTrackedPins());
}
+/// A full-screen program has the emulator on its alternate screen.
+pub fn onAlternateScreen(pane: *const Pane) bool {
+ if (comptime !enabled) return false;
+ const state = pane.terminal orelse return false;
+ return state.vt.screens.active_key == .alternate;
+}
+
pub fn promptInputReady(pane: *const Pane) bool {
if (comptime !enabled) return false;
const state = pane.terminal orelse return false;
diff --git a/src/exec.zig b/src/exec.zig
index 86dba32a..8b058a12 100644
--- a/src/exec.zig
+++ b/src/exec.zig
@@ -427,6 +427,12 @@ fn runCommand(p: *Pardes, from: usize, line: []const u8) ?usize {
pane.command_done = false;
pane.command_status = null;
pane.body.mode = .tty;
+ // What the last program left the emulator in goes first: the
+ // alternate screen left (only if it is there: leaving restores a
+ // saved cursor), mouse reports and bracketed paste off, the cursor
+ // shown, then a soft reset (DECSTR) for the rest.
+ if (panes.Terminal.onAlternateScreen(pane)) panes.Terminal.feedOutput(p, pane, "\x1b[?1049l");
+ panes.Terminal.feedOutput(p, pane, "\x1b[?1000l\x1b[?1002l\x1b[?1003l\x1b[?1006l\x1b[?2004l\x1b[?25h\x1b[!p");
var buf: [command_max + 8]u8 = undefined;
const lead = if (panes.Terminal.gridCursor(pane).x != 0) "\r\n" else "";
panes.Terminal.feedOutput(p, pane, std.fmt.bufPrint(&buf, "{s}% {s}\r\n", .{ lead, line }) catch "%\r\n");
diff --git a/src/pardes.zig b/src/pardes.zig
index 74554e0d..97ba534a 100644
--- a/src/pardes.zig
+++ b/src/pardes.zig
@@ -1432,8 +1432,13 @@ test "a command pane shows how its command ended, and the next command there run
// Kill leaves a finished one be.
try std.testing.expect(p.executeBuiltinLine(0, "Kill make"));
while (p.nextEffect()) |effect| if (effect == .signal_pty and effect.signal_pty.pane == dst) return error.SignalledAFinishedCommand;
+ // A program that crashed out of its full screen leaves the emulator
+ // in its modes; the next command starts clear of them.
+ p.update(.{ .output = .{ .pane = @intCast(dst), .bytes = "\x1b[?1049h\x1b[?2004h\x1b[?1000h" } });
+ try std.testing.expect(panes.Terminal.bracketedPaste(pane));
// Done, the directory's next command runs there, below what it showed.
try std.testing.expectEqual(@as(?usize, dst), exec.execute(p, 1, "make test"));
+ try std.testing.expect(!panes.Terminal.bracketedPaste(pane));
var respawned = false;
while (p.nextEffect()) |effect| if (effect == .spawn and effect.spawn.pane == dst) {
respawned = true;