diff --git a/src/widgets/terminal/Terminal.zig b/src/widgets/terminal/Terminal.zig index df27ba6..b65aca0 100644 --- a/src/widgets/terminal/Terminal.zig +++ b/src/widgets/terminal/Terminal.zig @@ -109,15 +109,14 @@ pub fn spawn(self: *Terminal) !void { self.thread = try std.Thread.spawn(.{}, Terminal.run, .{self}); } -/// resize the screen. Locks access to the back screen. Should only be called from the main thread +/// resize the screen. Locks access to the back screen. Should only be called from the main thread. +/// This is safe to call every render cycle: there is a guard to only perform a resize if the size +/// of the window has changed. pub fn resize(self: *Terminal, ws: Winsize) !void { // don't deinit with no size change if (ws.cols == self.front_screen.width and ws.rows == self.front_screen.height) - { - std.log.debug("resize requested but no change", .{}); return; - } self.back_mutex.lock(); defer self.back_mutex.unlock(); @@ -181,9 +180,9 @@ fn run(self: *Terminal) !void { const event = try parser.parseReader(reader); self.back_mutex.lock(); defer self.back_mutex.unlock(); + switch (event) { .print => |str| { - std.log.err("print: {s}", .{str}); var iter = grapheme.Iterator.init(str, &self.unicode.grapheme_data); while (iter.next()) |g| { const bytes = g.bytes(str); @@ -192,6 +191,9 @@ fn run(self: *Terminal) !void { } }, .c0 => |b| try self.handleC0(b), + .escape => |str| std.log.err("unhandled escape: {s}", .{str}), + .ss2 => |ss2| std.log.err("unhandled ss2: {c}", .{ss2}), + .ss3 => |ss3| std.log.err("unhandled ss3: {c}", .{ss3}), .csi => |seq| { switch (seq.final) { 'B' => { // CUD @@ -219,10 +221,11 @@ fn run(self: *Terminal) !void { self.back_screen.sgr(seq); } }, - else => {}, + else => std.log.err("unhandled CSI: {}", .{seq}), } }, - else => {}, + .osc => |osc| std.log.err("unhandled osc: {s}", .{osc}), + .apc => |apc| std.log.err("unhandled apc: {s}", .{apc}), } } } @@ -230,6 +233,7 @@ fn run(self: *Terminal) !void { inline fn handleC0(self: *Terminal, b: ansi.C0) !void { switch (b) { .NUL, .SOH, .STX => {}, + .EOT => {}, // we send EOT to quit the read thread .ENQ => {}, .BEL => self.pending_events.bell.store(true, .unordered), .BS => self.back_screen.cursorLeft(1), diff --git a/src/widgets/terminal/ansi.zig b/src/widgets/terminal/ansi.zig index fbdbe36..5bceb94 100644 --- a/src/widgets/terminal/ansi.zig +++ b/src/widgets/terminal/ansi.zig @@ -1,3 +1,5 @@ +const std = @import("std"); + /// Control bytes. See man 7 ascii pub const C0 = enum(u8) { NUL = 0x00, @@ -52,6 +54,40 @@ pub const CSI = struct { pub fn iterator(self: CSI, comptime T: type) ParamIterator(T) { return .{ .bytes = self.params }; } + + pub fn format( + self: CSI, + comptime layout: []const u8, + opts: std.fmt.FormatOptions, + writer: anytype, + ) !void { + _ = layout; + _ = opts; + if (self.private_marker == null and self.intermediate == null) + try std.fmt.format(writer, "CSI {s} {c}", .{ + self.params, + self.final, + }) + else if (self.private_marker != null and self.intermediate == null) + try std.fmt.format(writer, "CSI {c} {s} {c}", .{ + self.private_marker.?, + self.params, + self.final, + }) + else if (self.private_marker == null and self.intermediate != null) + try std.fmt.format(writer, "CSI {s} {c} {c}", .{ + self.params, + self.intermediate.?, + self.final, + }) + else + try std.fmt.format(writer, "CSI {c} {s} {c} {c}", .{ + self.private_marker.?, + self.params, + self.intermediate.?, + self.final, + }); + } }; pub fn ParamIterator(T: type) type {