diff --git a/src/Window.zig b/src/Window.zig index 3930f21ba..a9aafa5ca 100644 --- a/src/Window.zig +++ b/src/Window.zig @@ -815,6 +815,24 @@ fn charCallback(window: glfw.Window, codepoint: u21) void { .clear_selection = {}, }, .{ .forever = {} }); + // Scroll to the bottom + _ = win.io_thread.mailbox.push(.{ + .scroll_viewport = .{ .bottom = {} }, + }, .{ .forever = {} }); + + // Write the char to the pty + var data: termio.message.IO.SmallWriteArray = undefined; + data[0] = @intCast(u8, codepoint); + _ = win.io_thread.mailbox.push(.{ + .small_write = .{ + .data = data, + .len = 1, + }, + }, .{ .forever = {} }); + + // After sending all our messages we have to notify our IO thread + win.io_thread.wakeup.send() catch {}; + // TODO: the stuff below goes away with IO thread if (win.terminal.selection != null) { diff --git a/src/main.zig b/src/main.zig index 1f92efbe1..a985416cb 100644 --- a/src/main.zig +++ b/src/main.zig @@ -196,6 +196,7 @@ test { _ = @import("font/main.zig"); _ = @import("renderer.zig"); _ = @import("terminal/Terminal.zig"); + _ = @import("termio.zig"); _ = @import("input.zig"); // Libraries diff --git a/src/termio/Exec.zig b/src/termio/Exec.zig index 8762cc56f..47675b16b 100644 --- a/src/termio/Exec.zig +++ b/src/termio/Exec.zig @@ -3,6 +3,7 @@ pub const Exec = @This(); const std = @import("std"); const builtin = @import("builtin"); +const assert = std.debug.assert; const Allocator = std.mem.Allocator; const termio = @import("../termio.zig"); const Command = @import("../Command.zig"); @@ -42,6 +43,9 @@ renderer_wakeup: libuv.Async, /// The cached grid size whenever a resize is called. grid_size: renderer.GridSize, +/// The data associated with the currently running thread. +data: ?*EventData, + /// Initialize the exec implementation. This will also start the child /// process. pub fn init(alloc: Allocator, opts: termio.Options) !Exec { @@ -100,6 +104,7 @@ pub fn init(alloc: Allocator, opts: termio.Options) !Exec { .renderer_state = opts.renderer_state, .renderer_wakeup = opts.renderer_wakeup, .grid_size = opts.grid_size, + .data = null, }; } @@ -115,6 +120,8 @@ pub fn deinit(self: *Exec) void { } pub fn threadEnter(self: *Exec, loop: libuv.Loop) !ThreadData { + assert(self.data == null); + // Get a copy to our allocator const alloc_ptr = loop.getData(Allocator).?; const alloc = alloc_ptr.*; @@ -146,7 +153,10 @@ pub fn threadEnter(self: *Exec, loop: libuv.Loop) !ThreadData { }; errdefer ev_data_ptr.deinit(); - // Return our data + // Store our data so our callbacks can access it + self.data = ev_data_ptr; + + // Return our thread data return ThreadData{ .alloc = alloc, .ev = ev_data_ptr, @@ -154,8 +164,9 @@ pub fn threadEnter(self: *Exec, loop: libuv.Loop) !ThreadData { } pub fn threadExit(self: *Exec, data: ThreadData) void { - _ = self; _ = data; + + self.data = null; } /// Resize the terminal. @@ -199,6 +210,17 @@ pub fn clearSelection(self: *Exec) !void { } } +pub fn scrollViewport(self: *Exec, scroll: terminal.Terminal.ScrollViewport) !void { + self.renderer_state.mutex.lock(); + defer self.renderer_state.mutex.unlock(); + + try self.terminal.scrollViewport(scroll); +} + +pub inline fn queueWrite(self: *Exec, data: []const u8) !void { + try self.data.?.queueWrite(data); +} + const ThreadData = struct { /// Allocator used for the event data alloc: Allocator, diff --git a/src/termio/Thread.zig b/src/termio/Thread.zig index d0dd76cfc..c05f3dbb8 100644 --- a/src/termio/Thread.zig +++ b/src/termio/Thread.zig @@ -163,6 +163,8 @@ fn drainMailbox(self: *Thread) !void { switch (message) { .resize => |v| try self.impl.resize(v.grid_size, v.screen_size), .clear_selection => try self.impl.clearSelection(), + .scroll_viewport => |v| try self.impl.scrollViewport(v), + .small_write => |v| try self.impl.queueWrite(v.data[0..v.len]), } } } diff --git a/src/termio/message.zig b/src/termio/message.zig index 966e5ccb6..b80ae2e4f 100644 --- a/src/termio/message.zig +++ b/src/termio/message.zig @@ -1,8 +1,11 @@ +const std = @import("std"); const renderer = @import("../renderer.zig"); const terminal = @import("../terminal/main.zig"); /// The messages that can be sent to an IO thread. pub const IO = union(enum) { + pub const SmallWriteArray = [22]u8; + /// Resize the window. resize: struct { grid_size: renderer.GridSize, @@ -11,7 +14,19 @@ pub const IO = union(enum) { /// Clear the selection clear_selection: void, - // - // /// Scroll the viewport - // scroll_viewport: terminal.Terminal.ScrollViewport, + + /// Scroll the viewport + scroll_viewport: terminal.Terminal.ScrollViewport, + + /// Write where the data fits in the union. + small_write: struct { + data: [22]u8, + len: u8, + }, }; + +test { + // Ensure we don't grow our IO message size without explicitly wanting to. + const testing = std.testing; + try testing.expectEqual(@as(usize, 24), @sizeOf(IO)); +}