diff options
Diffstat (limited to 'src/Terminal.zig')
| -rw-r--r-- | src/Terminal.zig | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/src/Terminal.zig b/src/Terminal.zig index 91c23305..76be29d0 100644 --- a/src/Terminal.zig +++ b/src/Terminal.zig @@ -659,6 +659,36 @@ test "replay restores terminal cells from the retained stream" { try std.testing.expectEqualSlices(u8, try replayBytes(pane, gpa), try replayBytes(restored, gpa)); } +test "a restored command pane comes back finished, its command not run again" { + if (comptime !enabled or pardes.isolated) return error.SkipZigTest; + const gpa = std.testing.allocator; + const p = try Pardes.init(gpa, .{ .tty_only = true, .cols = 60, .rows = 16 }); + defer p.deinit(); + while (p.nextEffect()) |_| {} + const cmd = p.freeSlot().?; + _ = try p.newCommand(cmd, "/tmp", "make test"); + feedOutput(p, p.panes[cmd].?, "ok\r\n"); + p.update(.{ .exited = .{ .pane = @intCast(cmd), .status = 2 } }); + try dump.dumpState(p); + const restored = try dump.initFromDump(gpa, .{ .tty_only = true, .cols = 60, .rows = 16 }, p.dump_out.?); + defer restored.deinit(); + var spawns: usize = 0; + while (restored.nextEffect()) |effect| switch (effect) { + .spawn => spawns += 1, + else => {}, + }; + try std.testing.expectEqual(@as(usize, 1), spawns); // the shell, not the command + const again = for (restored.panes) |slot| { + if (slot) |pane| if (pane.command != null) break pane; + } else return error.CommandPaneLost; + try std.testing.expectEqualStrings("make test", again.command.?); + try std.testing.expect(again.command_done); + try std.testing.expectEqual(@as(?u8, 2), again.command_status); + const text = try screenTextAlloc(again, gpa); + defer gpa.free(text); + try std.testing.expect(std.mem.indexOf(u8, text, "ok") != null); +} + test "a restored terminal keeps its history above a marker and gets a shell where it was" { if (comptime !enabled or pardes.isolated) return error.SkipZigTest; const gpa = std.testing.allocator; @@ -668,6 +698,7 @@ test "a restored terminal keeps its history above a marker and gets a shell wher const pane = p.panes[0].?; feedOutput(p, pane, "old output\r\n$ ls\r\n"); try pane.setOwnedCwd("/tmp"); + pane.shell = try gpa.dupe(u8, "bash"); // `Tty bash`: it comes back as bash try dump.dumpState(p); const restored = try dump.initFromDump(gpa, .{ .tty_only = true, .cols = 40, .rows = 12 }, p.dump_out.?); defer restored.deinit(); @@ -678,6 +709,8 @@ test "a restored terminal keeps its history above a marker and gets a shell wher }; try std.testing.expect(spawned); const again = restored.panes[0].?; + try std.testing.expectEqualStrings("bash", again.shell.?); + try std.testing.expect(again.command == null); try std.testing.expectEqual(.spawn, again.pending_command.wait); const text = try screenTextAlloc(again, gpa); defer gpa.free(text); @@ -961,6 +994,15 @@ pub const CommandOutput = struct { /// What the newest finished command printed: the screen text between its /// C and D marks, read from at most `max_rows` rows above its end, so a /// command that printed the whole history costs no more than its tail. +/// The shell exited in the middle of a command (its `exit 3`): no end mark +/// will come, so the command's output ends where the cursor is. +pub fn endOutputHere(pane: *Pane) void { + if (comptime !enabled) return; + const state = pane.terminal orelse return; + const marks = &state.stream.handler; + if (marks.phase == .running and marks.out_end == null) marks.pinCursor(&marks.out_end, true); +} + pub fn commandOutput(pane: *Pane, gpa: std.mem.Allocator, max_rows: usize) !CommandOutput { // Unless there is text to read, whether the nothing it printed is the // whole of it. @@ -1427,6 +1469,9 @@ pub fn dumpPane( .collapsed = pane.collapsed, .terminal = .{ .cwd = try arena.dupe(u8, pane.cwdSlice()), + .shell = try arena.dupe(u8, pane.shell orelse ""), + .command = try arena.dupe(u8, pane.command orelse ""), + .status = pane.command_status, .stream = try arena.dupe(u8, text), .stream_b64 = &.{}, .cursor = .{ .col = 0, .row = 0 }, @@ -1476,6 +1521,9 @@ pub fn dumpPane( .collapsed = pane.collapsed, .terminal = .{ .cwd = try arena.dupe(u8, pane.cwdSlice()), + .shell = try arena.dupe(u8, pane.shell orelse ""), + .command = try arena.dupe(u8, pane.command orelse ""), + .status = pane.command_status, .stream = stream[0..len], .stream_b64 = try dump.encodeBytes(arena, try screenVt(pane, arena)), .stream_is_screen = true, @@ -2111,6 +2159,8 @@ test "terminal Filter keys indexed truecolor OSC and background-only cells throu defer p.deinit(); while (p.nextEffect()) |_| {} const pane = p.panes[0].?; + pane.tag_expanded = false; // a one-row tag keeps this small screen's rows + p.sync(); try testing.expect(pane.tty_filter); pane.tty_filter = false; |
