From 951aa00c63522b6b2e3bdeba0e2383fea5096c95 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 15 Aug 2023 11:00:22 -0700 Subject: [PATCH] terminal: move to new modes struct --- src/Surface.zig | 34 ++++++------- src/renderer/Metal.zig | 2 +- src/terminal/Terminal.zig | 91 +++++++++++++--------------------- src/terminal/ansi.zig | 100 -------------------------------------- src/terminal/main.zig | 4 +- src/terminal/stream.zig | 36 ++++++++++---- src/termio/Exec.zig | 87 ++++++++++++--------------------- 7 files changed, 112 insertions(+), 242 deletions(-) diff --git a/src/Surface.zig b/src/Surface.zig index 4af32922e..a2b10fe1b 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -742,7 +742,7 @@ fn clipboardPaste( log.warn("error scrolling to bottom err={}", .{err}); }; - break :bracketed self.io.terminal.modes.bracketed_paste; + break :bracketed self.io.terminal.modes.get(.bracketed_paste); }; if (bracketed) { @@ -1024,8 +1024,8 @@ pub fn charCallback( try self.io.terminal.scrollViewport(.{ .bottom = {} }); break :critical .{ - .alt_esc_prefix = self.io.terminal.modes.alt_esc_prefix, - .modify_other_keys = self.io.terminal.modes.modify_other_keys, + .alt_esc_prefix = self.io.terminal.modes.get(.alt_esc_prefix), + .modify_other_keys = self.io.terminal.flags.modify_other_keys_2, }; }; @@ -1178,9 +1178,9 @@ pub fn keyCallback( // We'll need to know these values here on. self.renderer_state.mutex.lock(); - const cursor_key_application = self.io.terminal.modes.cursor_keys; - const keypad_key_application = self.io.terminal.modes.keypad_keys; - const modify_other_keys = self.io.terminal.modes.modify_other_keys; + const cursor_key_application = self.io.terminal.modes.get(.cursor_keys); + const keypad_key_application = self.io.terminal.modes.get(.keypad_keys); + const modify_other_keys = self.io.terminal.flags.modify_other_keys_2; self.renderer_state.mutex.unlock(); // Check if we're processing a function key. @@ -1355,7 +1355,7 @@ pub fn focusCallback(self: *Surface, focused: bool) !void { // Notify the app about focus in/out if it is requesting it { self.renderer_state.mutex.lock(); - const focus_event = self.io.terminal.modes.focus_event; + const focus_event = self.io.terminal.modes.get(.focus_event); self.renderer_state.mutex.unlock(); if (focus_event) { @@ -1479,7 +1479,7 @@ pub fn scrollCallback( // If we have an active mouse reporting mode, clear the selection. // The selection can occur if the user uses the shift mod key to // override mouse grabbing from the window. - if (self.io.terminal.modes.mouse_event != .none) { + if (self.io.terminal.flags.mouse_event != .none) { self.setSelection(null); } @@ -1488,8 +1488,8 @@ pub fn scrollCallback( // (1) alt screen (2) no explicit mouse reporting and (3) alt // scroll mode enabled. if (self.io.terminal.active_screen == .alternate and - self.io.terminal.modes.mouse_event == .none and - self.io.terminal.modes.mouse_alternate_scroll) + self.io.terminal.flags.mouse_event == .none and + self.io.terminal.modes.get(.mouse_alternate_scroll)) { if (y.delta_unsigned > 0) { const seq = if (y.delta < 0) "\x1bOA" else "\x1bOB"; @@ -1550,7 +1550,7 @@ fn mouseReport( // do we want to not report mouse events at all outside the surface? // Depending on the event, we may do nothing at all. - switch (self.io.terminal.modes.mouse_event) { + switch (self.io.terminal.flags.mouse_event) { .none => return, // X10 only reports clicks with mouse button 1, 2, 3. We verify @@ -1585,7 +1585,7 @@ fn mouseReport( if (button == null) { // Null button means motion without a button pressed acc = 3; - } else if (action == .release and self.io.terminal.modes.mouse_format != .sgr) { + } else if (action == .release and self.io.terminal.flags.mouse_format != .sgr) { // Release is 3. It is NOT 3 in SGR mode because SGR can tell // the application what button was released. acc = 3; @@ -1601,7 +1601,7 @@ fn mouseReport( } // X10 doesn't have modifiers - if (self.io.terminal.modes.mouse_event != .x10) { + if (self.io.terminal.flags.mouse_event != .x10) { if (mods.shift) acc += 4; if (mods.super) acc += 8; if (mods.ctrl) acc += 16; @@ -1613,7 +1613,7 @@ fn mouseReport( break :code acc; }; - switch (self.io.terminal.modes.mouse_format) { + switch (self.io.terminal.flags.mouse_format) { .x10 => { if (viewport_point.x > 222 or viewport_point.y > 222) { log.info("X10 mouse format can only encode X/Y up to 223", .{}); @@ -1784,7 +1784,7 @@ pub fn mouseButtonCallback( defer self.renderer_state.mutex.unlock(); // Report mouse events if enabled - if (self.io.terminal.modes.mouse_event != .none) report: { + if (self.io.terminal.flags.mouse_event != .none) report: { // Shift overrides mouse "grabbing" in the window, taken from Kitty. if (mods.shift) break :report; @@ -1922,7 +1922,7 @@ pub fn cursorPosCallback( defer self.renderer_state.mutex.unlock(); // Do a mouse report - if (self.io.terminal.modes.mouse_event != .none) report: { + if (self.io.terminal.flags.mouse_event != .none) report: { // Shift overrides mouse "grabbing" in the window, taken from Kitty. if (self.mouse.mods.shift) break :report; @@ -2224,7 +2224,7 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !void log.warn("error scrolling to bottom err={}", .{err}); }; - break :normal !self.io.terminal.modes.cursor_keys; + break :normal !self.io.terminal.modes.get(.cursor_keys); }; if (normal) { diff --git a/src/renderer/Metal.zig b/src/renderer/Metal.zig index f116e94fd..5dfe5e4f7 100644 --- a/src/renderer/Metal.zig +++ b/src/renderer/Metal.zig @@ -564,7 +564,7 @@ pub fn render( self.config.background = bg; self.config.foreground = fg; } - if (state.terminal.modes.reverse_colors) { + if (state.terminal.modes.get(.reverse_colors)) { self.config.background = fg; self.config.foreground = bg; } diff --git a/src/terminal/Terminal.zig b/src/terminal/Terminal.zig index ff9b0c8f3..ca35f659f 100644 --- a/src/terminal/Terminal.zig +++ b/src/terminal/Terminal.zig @@ -12,6 +12,7 @@ const assert = std.debug.assert; const Allocator = std.mem.Allocator; const ansi = @import("ansi.zig"); +const modes = @import("modes.zig"); const charsets = @import("charsets.zig"); const csi = @import("csi.zig"); const sgr = @import("sgr.zig"); @@ -77,45 +78,27 @@ color_palette: color.Palette = color.default, /// char CSI (ESC [ b). previous_char: ?u21 = null, -/// Modes - This isn't exhaustive, since some modes (i.e. cursor origin) -/// are applied to the cursor and others aren't boolean yes/no. -modes: packed struct { - const Self = @This(); - - cursor_keys: bool = false, // 1 - insert: bool = false, // 4 - reverse_colors: bool = false, // 5, - origin: bool = false, // 6 - autowrap: bool = true, // 7 - - deccolm: bool = false, // 3, - deccolm_supported: bool = false, // 40 - keypad_keys: bool = false, // 66 - alt_esc_prefix: bool = true, // 1036 - - focus_event: bool = false, // 1004 - mouse_alternate_scroll: bool = true, // 1007 - mouse_event: MouseEvents = .none, - mouse_format: MouseFormat = .x10, - - bracketed_paste: bool = false, // 2004 - - // This is set via ESC[4;2m. Any other modify key mode just sets - // this to false. - modify_other_keys: bool = false, +/// The modes that this terminal currently has active. +modes: modes.ModeState = .{}, +/// These are just a packed set of flags we may set on the terminal. +flags: packed struct { // This isn't a mode, this is set by OSC 133 using the "A" event. // If this is true, it tells us that the shell supports redrawing // the prompt and that when we resize, if the cursor is at a prompt, // then we should clear the screen below and allow the shell to redraw. shell_redraws_prompt: bool = false, - test { - // We have this here so that we explicitly fail when we change the - // size of modes. The size of modes is NOT particularly important, - // we just want to be mentally aware when it happens. - try std.testing.expectEqual(4, @sizeOf(Self)); - } + // This is set via ESC[4;2m. Any other modify key mode just sets + // this to false and we act in mode 1 by default. + modify_other_keys_2: bool = false, + + /// The mouse event mode and format. These are set to the last + /// set mode in modes. You can't get the right event/format to use + /// based on modes alone because modes don't show you what order + /// this was called so we have to track it separately. + mouse_event: MouseEvents = .none, + mouse_format: MouseFormat = .x10, } = .{}, /// State required for all charset operations. @@ -285,10 +268,10 @@ pub fn deccolm(self: *Terminal, alloc: Allocator, mode: DeccolmMode) !void { // bit. If the mode "?40" is set, then "?3" (DECCOLM) is supported. This // doesn't exactly match VT100 semantics but modern terminals no longer // blindly accept mode 3 since its so weird in modern practice. - if (!self.modes.deccolm_supported) return; + if (!self.modes.get(.enable_mode_3)) return; // Enable it - self.modes.deccolm = mode == .@"132_cols"; + self.modes.set(.@"132_column", mode == .@"132_cols"); // Resize -- we can set cols to 0 because deccolm will force it try self.resize(alloc, 0, self.rows); @@ -300,14 +283,6 @@ pub fn deccolm(self: *Terminal, alloc: Allocator, mode: DeccolmMode) !void { // TODO: left/right margins } -/// Allows or disallows deccolm. -pub fn setDeccolmSupported(self: *Terminal, v: bool) void { - const tracy = trace(@src()); - defer tracy.end(); - - self.modes.deccolm_supported = v; -} - /// Resize the underlying terminal. pub fn resize(self: *Terminal, alloc: Allocator, cols_req: usize, rows: usize) !void { const tracy = trace(@src()); @@ -316,8 +291,8 @@ pub fn resize(self: *Terminal, alloc: Allocator, cols_req: usize, rows: usize) ! // If we have deccolm supported then we are fixed at either 80 or 132 // columns depending on if mode 3 is set or not. // TODO: test - const cols: usize = if (self.modes.deccolm_supported) - if (self.modes.deccolm) 132 else 80 + const cols: usize = if (self.modes.get(.enable_mode_3)) + if (self.modes.get(.@"132_column")) 132 else 80 else cols_req; @@ -349,13 +324,13 @@ pub fn resize(self: *Terminal, alloc: Allocator, cols_req: usize, rows: usize) ! }; } -/// If modes.shell_redraws_prompt is true and we're on the primary screen, +/// If shell_redraws_prompt is true and we're on the primary screen, /// then this will clear the screen from the cursor down if the cursor is /// on a prompt in order to allow the shell to redraw the prompt. fn clearPromptForResize(self: *Terminal) void { assert(self.active_screen == .primary); - if (!self.modes.shell_redraws_prompt) return; + if (!self.flags.shell_redraws_prompt) return; // We need to find the first y that is a prompt. If we find any line // that is NOT a prompt (or input -- which is part of a prompt) then @@ -693,13 +668,16 @@ pub fn print(self: *Terminal, c: u21) !void { self.previous_char = c; // If we're soft-wrapping, then handle that first. - if (self.screen.cursor.pending_wrap and self.modes.autowrap) + if (self.screen.cursor.pending_wrap and self.modes.get(.autowrap)) try self.printWrap(); // If we have insert mode enabled then we need to handle that. We // only do insert mode if we're not at the end of the line. - if (self.modes.insert and self.screen.cursor.x + width < self.cols) + if (self.modes.get(.insert) and + self.screen.cursor.x + width < self.cols) + { self.insertBlanks(width); + } switch (width) { // Single cell is very easy: just write in the cell @@ -962,7 +940,7 @@ pub fn setCursorPos(self: *Terminal, row_req: usize, col_req: usize) void { y_offset: usize = 0, x_max: usize, y_max: usize, - } = if (self.modes.origin) .{ + } = if (self.modes.get(.origin)) .{ .x_offset = 0, // TODO: left/right margins .y_offset = self.scrolling_region.top, .x_max = self.cols, // TODO: left/right margins @@ -994,7 +972,7 @@ pub fn setCursorColAbsolute(self: *Terminal, col_req: usize) void { // TODO: test - assert(!self.modes.origin); // TODO + assert(!self.modes.get(.origin)); // TODO if (self.status_display != .main) return; // TODO @@ -1582,6 +1560,7 @@ pub fn fullReset(self: *Terminal) void { self.eraseDisplay(.scrollback); self.eraseDisplay(.complete); self.modes = .{}; + self.flags = .{}; self.tabstops.reset(0); self.screen.cursor = .{}; self.screen.saved_cursor = .{}; @@ -1890,7 +1869,7 @@ test "Terminal: setCursorPosition" { try testing.expect(!t.screen.cursor.pending_wrap); // Origin mode - t.modes.origin = true; + t.modes.set(.origin, true); // No change without a scroll region t.setCursorPos(81, 81); @@ -2340,7 +2319,7 @@ test "Terminal: insert mode with space" { for ("hello") |c| try t.print(c); t.setCursorPos(1, 2); - t.modes.insert = true; + t.modes.set(.insert, true); try t.print('X'); { @@ -2357,7 +2336,7 @@ test "Terminal: insert mode doesn't wrap pushed characters" { for ("hello") |c| try t.print(c); t.setCursorPos(1, 2); - t.modes.insert = true; + t.modes.set(.insert, true); try t.print('X'); { @@ -2373,7 +2352,7 @@ test "Terminal: insert mode does nothing at the end of the line" { defer t.deinit(alloc); for ("hello") |c| try t.print(c); - t.modes.insert = true; + t.modes.set(.insert, true); try t.print('X'); { @@ -2390,7 +2369,7 @@ test "Terminal: insert mode with wide characters" { for ("hello") |c| try t.print(c); t.setCursorPos(1, 2); - t.modes.insert = true; + t.modes.set(.insert, true); try t.print('😀'); // 0x1F600 { @@ -2406,7 +2385,7 @@ test "Terminal: insert mode with wide characters at end" { defer t.deinit(alloc); for ("well") |c| try t.print(c); - t.modes.insert = true; + t.modes.set(.insert, true); try t.print('😀'); // 0x1F600 { diff --git a/src/terminal/ansi.zig b/src/terminal/ansi.zig index 543f40ada..eb40b32a0 100644 --- a/src/terminal/ansi.zig +++ b/src/terminal/ansi.zig @@ -42,106 +42,6 @@ pub const RenditionAspect = enum(u16) { _, }; -/// Modes that can be set with with Set Mode (SM) (ESC [ h). The enum -/// values correspond to the `?`-prefixed modes, since those are the ones -/// of primary interest. The enum value is the mode value. -pub const Mode = enum(u16) { - /// This control function selects the sequences the arrow keys send. - /// You can use the four arrow keys to move the cursor through the current - /// page or to send special application commands. - /// - /// If the DECCKM function is set, then the arrow keys send application - /// sequences to the host. - /// - /// If the DECCKM function is reset, then the arrow keys send ANSI cursor - /// sequences to the host. - cursor_keys = 1, - - /// Change terminal wide between 80 and 132 column mode. When set - /// (with ?40 set), resizes terminal to 132 columns and keeps it that - /// wide. When unset, resizes to 80 columns. - @"132_column" = 3, - - /// Insert mode. This mode writes a character and pushes all existing - /// characters to the right. The existing contents are never wrapped. - insert = 4, - - /// Reverses the foreground and background colors of all cells. - reverse_colors = 5, - - /// If set, the origin of the coordinate system is relative to the - /// current scroll region. If set the cursor is moved to the top left of - /// the current scroll region. - origin = 6, - - /// Enable or disable automatic line wrapping. - autowrap = 7, - - /// Click-only (press) mouse reporting. - mouse_event_x10 = 9, - - /// Set whether the cursor is visible or not. - cursor_visible = 25, - - /// Enables or disables mode ?3. If disabled, the terminal will resize - /// to the size of the window. If enabled, this will take effect when - /// mode ?3 is set or unset. - enable_mode_3 = 40, - - /// DECNKM. Sets application keypad mode if enabled. - keypad_keys = 66, - - /// "Normal" mouse events: click/release, scroll - mouse_event_normal = 1000, - - /// Same as normal mode but also send events for mouse motion - /// while the button is pressed when the cell in the grid changes. - mouse_event_button = 1002, - - /// Same as button mode but doesn't require a button to be pressed - /// to track mouse movement. - mouse_event_any = 1003, - - /// Send focus in/out events. - focus_event = 1004, - - /// Report mouse position in the utf8 format to support larger screens. - mouse_format_utf8 = 1005, - - /// Report mouse position in the SGR format. - mouse_format_sgr = 1006, - - /// Report mouse scroll events as cursor up/down keys. Any other mouse - /// mode overrides this. - mouse_alternate_scroll = 1007, - - /// Report mouse position in the urxvt format. - mouse_format_urxvt = 1015, - - /// Report mouse position in the SGR format as pixels, instead of cells. - mouse_format_sgr_pixels = 1016, - - /// The alt key sends esc as a prefix before any character. On by default. - alt_esc_prefix = 1036, - - /// altSendsEscape xterm (https://invisible-island.net/xterm/manpage/xterm.html) - alt_sends_escape = 1039, - - /// Alternate screen mode with save cursor and clear on enter. - alt_screen_save_cursor_clear_enter = 1049, - - /// Bracket clipboard paste contents in delimiter sequences. - /// - /// When pasting from the (e.g. system) clipboard add "ESC [ 2 0 0 ~" - /// before the clipboard contents and "ESC [ 2 0 1 ~" after the clipboard - /// contents. This allows applications to distinguish clipboard contents - /// from manually typed text. - bracketed_paste = 2004, - - // Non-exhaustive so that @intToEnum never fails for unsupported modes. - _, -}; - /// The device attribute request type (ESC [ c). pub const DeviceAttributeReq = enum { primary, // Blank diff --git a/src/terminal/main.zig b/src/terminal/main.zig index 547ef61da..3de537656 100644 --- a/src/terminal/main.zig +++ b/src/terminal/main.zig @@ -7,6 +7,7 @@ const csi = @import("csi.zig"); const sgr = @import("sgr.zig"); pub const point = @import("point.zig"); pub const color = @import("color.zig"); +pub const modes = @import("modes.zig"); pub const parse_table = @import("parse_table.zig"); pub const Charset = charsets.Charset; @@ -20,7 +21,7 @@ pub const Stream = stream.Stream; pub const CursorStyle = ansi.CursorStyle; pub const DeviceAttributeReq = ansi.DeviceAttributeReq; pub const DeviceStatusReq = ansi.DeviceStatusReq; -pub const Mode = ansi.Mode; +pub const Mode = modes.Mode; pub const ModifyKeyFormat = ansi.ModifyKeyFormat; pub const StatusLineType = ansi.StatusLineType; pub const StatusDisplay = ansi.StatusDisplay; @@ -36,5 +37,4 @@ pub usingnamespace if (builtin.target.isWasm()) struct { test { @import("std").testing.refAllDecls(@This()); - _ = @import("modes.zig"); } diff --git a/src/terminal/stream.zig b/src/terminal/stream.zig index ea3b2a736..47a44c57e 100644 --- a/src/terminal/stream.zig +++ b/src/terminal/stream.zig @@ -4,6 +4,7 @@ const Parser = @import("Parser.zig"); const ansi = @import("ansi.zig"); const charsets = @import("charsets.zig"); const csi = @import("csi.zig"); +const modes = @import("modes.zig"); const osc = @import("osc.zig"); const sgr = @import("sgr.zig"); const trace = @import("tracy").trace; @@ -426,14 +427,30 @@ pub fn Stream(comptime Handler: type) type { // SM - Set Mode 'h' => if (@hasDecl(T, "setMode")) { - for (action.params) |mode| - try self.handler.setMode(@enumFromInt(mode), true); + for (action.params) |mode| { + if (modes.hasSupport(mode)) { + try self.handler.setMode( + @enumFromInt(mode), + true, + ); + } else { + log.warn("unimplemented mode: {}", .{mode}); + } + } } else log.warn("unimplemented CSI callback: {}", .{action}), // RM - Reset Mode 'l' => if (@hasDecl(T, "setMode")) { - for (action.params) |mode| - try self.handler.setMode(@enumFromInt(mode), false); + for (action.params) |mode| { + if (modes.hasSupport(mode)) { + try self.handler.setMode( + @enumFromInt(mode), + false, + ); + } else { + log.warn("unimplemented mode: {}", .{mode}); + } + } } else log.warn("unimplemented CSI callback: {}", .{action}), // SGR - Select Graphic Rendition @@ -896,20 +913,19 @@ test "stream: cursor right (CUF)" { test "stream: set mode (SM) and reset mode (RM)" { const H = struct { - mode: ansi.Mode = @as(ansi.Mode, @enumFromInt(0)), - - pub fn setMode(self: *@This(), mode: ansi.Mode, v: bool) !void { - self.mode = @as(ansi.Mode, @enumFromInt(0)); + mode: modes.Mode = @as(modes.Mode, @enumFromInt(1)), + pub fn setMode(self: *@This(), mode: modes.Mode, v: bool) !void { + self.mode = @as(modes.Mode, @enumFromInt(1)); if (v) self.mode = mode; } }; var s: Stream(H) = .{ .handler = .{} }; try s.nextSlice("\x1B[?6h"); - try testing.expectEqual(@as(ansi.Mode, .origin), s.handler.mode); + try testing.expectEqual(@as(modes.Mode, .origin), s.handler.mode); try s.nextSlice("\x1B[?6l"); - try testing.expectEqual(@as(ansi.Mode, @enumFromInt(0)), s.handler.mode); + try testing.expectEqual(@as(modes.Mode, @enumFromInt(1)), s.handler.mode); } test "stream: restore mode" { diff --git a/src/termio/Exec.zig b/src/termio/Exec.zig index 64c4dfa96..ffdffc238 100644 --- a/src/termio/Exec.zig +++ b/src/termio/Exec.zig @@ -1119,7 +1119,7 @@ const StreamHandler = struct { } pub fn setCursorRow(self: *StreamHandler, row: u16) !void { - if (self.terminal.modes.origin) { + if (self.terminal.modes.get(.origin)) { // TODO log.err("setCursorRow: implement origin mode", .{}); unreachable; @@ -1184,10 +1184,10 @@ const StreamHandler = struct { } pub fn setModifyKeyFormat(self: *StreamHandler, format: terminal.ModifyKeyFormat) !void { - self.terminal.modes.modify_other_keys = false; + self.terminal.flags.modify_other_keys_2 = false; switch (format) { .other_keys => |v| switch (v) { - .numeric => self.terminal.modes.modify_other_keys = true, + .numeric => self.terminal.flags.modify_other_keys_2 = true, else => {}, }, else => {}, @@ -1199,38 +1199,19 @@ const StreamHandler = struct { // terminal locks because it is only called from process() which // grabs the lock. + // We first always set the raw mode on our mode state. + self.terminal.modes.set(mode, enabled); + + // And then some modes require additional processing. switch (mode) { - .cursor_keys => { - self.terminal.modes.cursor_keys = enabled; - }, + // Schedule a render since we changed colors + .reverse_colors => try self.queueRender(), - .keypad_keys => { - self.terminal.modes.keypad_keys = enabled; - }, + // Origin resets cursor pos + .origin => self.terminal.setCursorPos(1, 1), - .insert => { - self.terminal.modes.insert = enabled; - }, - - .reverse_colors => { - self.terminal.modes.reverse_colors = enabled; - - // Schedule a render since we changed colors - try self.queueRender(); - }, - - .origin => { - self.terminal.modes.origin = enabled; - self.terminal.setCursorPos(1, 1); - }, - - .autowrap => { - self.terminal.modes.autowrap = enabled; - }, - - .cursor_visible => { - self.ev.renderer_state.cursor.visible = enabled; - }, + // We need to update our renderer state for this mode + .cursor_visible => self.ev.renderer_state.cursor.visible = enabled, .alt_screen_save_cursor_clear_enter => { const opts: terminal.Terminal.AlternateScreenOptions = .{ @@ -1247,15 +1228,13 @@ const StreamHandler = struct { try self.queueRender(); }, - .bracketed_paste => self.terminal.modes.bracketed_paste = enabled, - - .enable_mode_3 => { - // Disable deccolm - self.terminal.setDeccolmSupported(enabled); - - // Force resize back to the window size - self.terminal.resize(self.alloc, self.grid_size.columns, self.grid_size.rows) catch |err| - log.err("error updating terminal size: {}", .{err}); + // Force resize back to the window size + .enable_mode_3 => self.terminal.resize( + self.alloc, + self.grid_size.columns, + self.grid_size.rows, + ) catch |err| { + log.err("error updating terminal size: {}", .{err}); }, .@"132_column" => try self.terminal.deccolm( @@ -1263,21 +1242,17 @@ const StreamHandler = struct { if (enabled) .@"132_cols" else .@"80_cols", ), - .mouse_event_x10 => self.terminal.modes.mouse_event = if (enabled) .x10 else .none, - .mouse_event_normal => self.terminal.modes.mouse_event = if (enabled) .normal else .none, - .mouse_event_button => self.terminal.modes.mouse_event = if (enabled) .button else .none, - .mouse_event_any => self.terminal.modes.mouse_event = if (enabled) .any else .none, + .mouse_event_x10 => self.terminal.flags.mouse_event = if (enabled) .x10 else .none, + .mouse_event_normal => self.terminal.flags.mouse_event = if (enabled) .normal else .none, + .mouse_event_button => self.terminal.flags.mouse_event = if (enabled) .button else .none, + .mouse_event_any => self.terminal.flags.mouse_event = if (enabled) .any else .none, - .mouse_format_utf8 => self.terminal.modes.mouse_format = if (enabled) .utf8 else .x10, - .mouse_format_sgr => self.terminal.modes.mouse_format = if (enabled) .sgr else .x10, - .mouse_format_urxvt => self.terminal.modes.mouse_format = if (enabled) .urxvt else .x10, - .mouse_format_sgr_pixels => self.terminal.modes.mouse_format = if (enabled) .sgr_pixels else .x10, + .mouse_format_utf8 => self.terminal.flags.mouse_format = if (enabled) .utf8 else .x10, + .mouse_format_sgr => self.terminal.flags.mouse_format = if (enabled) .sgr else .x10, + .mouse_format_urxvt => self.terminal.flags.mouse_format = if (enabled) .urxvt else .x10, + .mouse_format_sgr_pixels => self.terminal.flags.mouse_format = if (enabled) .sgr_pixels else .x10, - .mouse_alternate_scroll => self.terminal.modes.mouse_alternate_scroll = enabled, - .focus_event => self.terminal.modes.focus_event = enabled, - .alt_esc_prefix => self.terminal.modes.alt_esc_prefix = enabled, - - else => if (enabled) log.warn("unimplemented mode: {}", .{mode}), + else => {}, } } @@ -1323,7 +1298,7 @@ const StreamHandler = struct { const pos: struct { x: usize, y: usize, - } = if (self.terminal.modes.origin) .{ + } = if (self.terminal.modes.get(.origin)) .{ // TODO: what do we do if cursor is outside scrolling region? .x = self.terminal.screen.cursor.x, .y = self.terminal.screen.cursor.y -| self.terminal.scrolling_region.top, @@ -1464,7 +1439,7 @@ const StreamHandler = struct { pub fn promptStart(self: *StreamHandler, aid: ?[]const u8, redraw: bool) !void { _ = aid; self.terminal.markSemanticPrompt(.prompt); - self.terminal.modes.shell_redraws_prompt = redraw; + self.terminal.flags.shell_redraws_prompt = redraw; } pub fn promptEnd(self: *StreamHandler) !void {