Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 15 additions & 7 deletions src/client.zig
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ pub fn attach(alloc: std.mem.Allocator, socket_path: []const u8) !Outcome {
try posix.tcsetattr(tty, .FLUSH, raw);
// Set by the outcome paths below when a held C-d may still be
// repeating; read by the deferred restore.
var drain_guard_ms: i64 = drain_guard_short_ms;
defer restoreTty(tty, saved, drain_guard_ms);
var eof_guard = false;
defer restoreTty(tty, saved, restore_sequence, eof_guard);
try protocol.writeAll(1, enter_sequence);

// Handshake with our current size.
Expand Down Expand Up @@ -156,15 +156,15 @@ pub fn attach(alloc: std.mem.Allocator, socket_path: []const u8) !Outcome {
.detached => {
if (std.mem.eql(u8, msg.payload, "stolen")) return .stolen;
if (std.mem.eql(u8, msg.payload, "detached-eof")) {
drain_guard_ms = drain_guard_eof_ms;
eof_guard = true;
}
return .detached;
},
.exit => {
// Sessions often end because the user typed
// C-d at the session's shell; treat the tail
// as EOF-dangerous.
drain_guard_ms = drain_guard_eof_ms;
eof_guard = true;
return .ended;
},
else => {},
Expand Down Expand Up @@ -245,15 +245,23 @@ const drain_guard_eof_ms = 800;
const drain_tail_ms = 100;
const drain_cap_ms = 1500;

fn restoreTty(tty: posix.fd_t, saved: posix.termios, guard_ms: i64) void {
/// Restore a raw client terminal: screen restore, input drain, then
/// the mode switch. Shared with boo ui, whose quit has the same held
/// command key and kitty release tail to absorb.
pub fn restoreTty(
tty: posix.fd_t,
saved: posix.termios,
restore: []const u8,
eof_guard: bool,
) void {
// Screen restore first: the user sees the detach immediately, and
// a kitty-mode terminal stops CSI-u key reporting as soon as the
// reset reaches it, so a still-held key repeats in legacy bytes
// that the drain below absorbs. Only then hand the tty back; the
// FLUSH discards anything that slips in between the last drained
// read and the mode switch.
protocol.writeAll(1, restore_sequence) catch {};
drainInput(tty, guard_ms);
protocol.writeAll(1, restore) catch {};
drainInput(tty, if (eof_guard) drain_guard_eof_ms else drain_guard_short_ms);
posix.tcsetattr(tty, .FLUSH, saved) catch {};
}

Expand Down
13 changes: 8 additions & 5 deletions src/daemon.zig
Original file line number Diff line number Diff line change
Expand Up @@ -269,11 +269,14 @@ pub const Daemon = struct {
try h.daemon.handleKeyCommand(h.conn, cmd);
}
};
// When the window runs the kitty keyboard protocol,
// the client's terminal mirrors it and sends the
// prefix key CSI-u encoded.
const kitty = if (self.liveWindow()) |w| w.kittyKeysActive() else false;
try self.key_parser.feed(msg.payload, kitty, Handler{ .daemon = self, .conn = conn });
// When the window runs the kitty keyboard protocol
// or modifyOtherKeys, the client's terminal mirrors
// it and sends the prefix key encoded.
const prot: keys.Protocols = if (self.liveWindow()) |w| .{
.kitty = w.kittyKeysActive(),
.modify = w.modifyKeysActive(),
} else .{};
try self.key_parser.feed(msg.payload, prot, Handler{ .daemon = self, .conn = conn });
},

.resize => {
Expand Down
Loading
Loading