diff --git a/src/terminal/stream.zig b/src/terminal/stream.zig index 2c237fbb0..d9ec4c59b 100644 --- a/src/terminal/stream.zig +++ b/src/terminal/stream.zig @@ -73,6 +73,8 @@ pub const Action = union(Key) { reset_mode: Mode, save_mode: Mode, restore_mode: Mode, + request_mode: Mode, + request_mode_unknown: RawMode, modify_key_format: ansi.ModifyKeyFormat, pub const Key = lib.Enum( @@ -121,6 +123,8 @@ pub const Action = union(Key) { "reset_mode", "save_mode", "restore_mode", + "request_mode", + "request_mode_unknown", "modify_key_format", }, ); @@ -180,6 +184,11 @@ pub const Action = union(Key) { return @bitCast(self.mode); } }; + + pub const RawMode = extern struct { + mode: u16, + ansi: bool, + }; }; /// Returns a type that can process a stream of tty control characters. @@ -1242,9 +1251,16 @@ pub fn Stream(comptime Handler: type) type { break :decrqm; } - if (@hasDecl(T, "requestMode")) { - try self.handler.requestMode(input.params[0], ansi_mode); - } else log.warn("unimplemented DECRQM callback: {f}", .{input}); + const mode_raw = input.params[0]; + const mode = modes.modeFromInt(mode_raw, ansi_mode); + if (mode) |m| { + try self.handler.vt(.request_mode, .{ .mode = m }); + } else { + try self.handler.vt(.request_mode_unknown, .{ + .mode = mode_raw, + .ansi = ansi_mode, + }); + } }, else => log.warn( diff --git a/src/termio/stream_handler.zig b/src/termio/stream_handler.zig index cb78ff264..644613626 100644 --- a/src/termio/stream_handler.zig +++ b/src/termio/stream_handler.zig @@ -253,6 +253,8 @@ pub const StreamHandler = struct { const v = self.terminal.modes.restore(value.mode); try self.setMode(value.mode, v); }, + .request_mode => try self.requestMode(value.mode), + .request_mode_unknown => try self.requestModeUnknown(value.mode, value.ansi), .modify_key_format => try self.setModifyKeyFormat(value), } } @@ -456,22 +458,32 @@ pub const StreamHandler = struct { } } - pub fn requestMode(self: *StreamHandler, mode_raw: u16, ansi: bool) !void { - // Get the mode value and respond. - const code: u8 = code: { - const mode = terminal.modes.modeFromInt(mode_raw, ansi) orelse break :code 0; - if (self.terminal.modes.get(mode)) break :code 1; - break :code 2; - }; + fn requestMode(self: *StreamHandler, mode: terminal.Mode) !void { + const tag: terminal.modes.ModeTag = @bitCast(@intFromEnum(mode)); + const code: u8 = if (self.terminal.modes.get(mode)) 1 else 2; var msg: termio.Message = .{ .write_small = .{} }; const resp = try std.fmt.bufPrint( &msg.write_small.data, "\x1B[{s}{};{}$y", + .{ + if (tag.ansi) "" else "?", + tag.value, + code, + }, + ); + msg.write_small.len = @intCast(resp.len); + self.messageWriter(msg); + } + + fn requestModeUnknown(self: *StreamHandler, mode_raw: u16, ansi: bool) !void { + var msg: termio.Message = .{ .write_small = .{} }; + const resp = try std.fmt.bufPrint( + &msg.write_small.data, + "\x1B[{s}{};0$y", .{ if (ansi) "" else "?", mode_raw, - code, }, ); msg.write_small.len = @intCast(resp.len);