From 961e5afe416626cbed181b863755e32af0ef6052 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Fri, 7 Jun 2024 22:12:28 +0200 Subject: [PATCH] feat: initial windows support --- build.zig | 1 + build.zig.version | 2 +- build.zig.zon | 8 +- src/main.zig | 32 ++- src/renderer/vaxis/renderer.zig | 368 ++++++++++++++++++++------------ src/tui/status/filestate.zig | 2 + src/tui/tui.zig | 79 +++---- 7 files changed, 290 insertions(+), 202 deletions(-) diff --git a/build.zig b/build.zig index a6eb66e..7a4f463 100644 --- a/build.zig +++ b/build.zig @@ -125,6 +125,7 @@ pub fn build(b: *std.Build) void { .{ .name = "theme", .module = themes_dep.module("theme") }, .{ .name = "cbor", .module = cbor_mod }, .{ .name = "log", .module = log_mod }, + .{ .name = "thespian", .module = thespian_mod }, }, }); diff --git a/build.zig.version b/build.zig.version index 3d2dcc1..54d1a4f 100644 --- a/build.zig.version +++ b/build.zig.version @@ -1 +1 @@ -0.13.0-dev.363+7fc3fb955 +0.13.0 diff --git a/build.zig.zon b/build.zig.zon index 158caf0..de61c26 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -16,8 +16,8 @@ .hash = "1220220dbc7fe91c1c54438193ca765cebbcb7d58f35cdcaee404a9d2245a42a4362", }, .thespian = .{ - .url = "https://github.com/neurocyte/thespian/archive/3121af2ec484841103eae059c79e4c3ddbec4149.tar.gz", - .hash = "1220794a8ca2f5e93e8dad61338f3bfd7a322f0c85635f367bc6cf0c178dcde70247", + .url = "https://github.com/neurocyte/thespian/archive/895d3dfb9ece213d614af97c9b636a0844e4e04b.tar.gz", + .hash = "122045ee52e7f37488d35d2c9c2f16d321267b27c8df05ce4d007c869f8d7d0e64a8", }, .themes = .{ .url = "https://github.com/neurocyte/flow-themes/releases/download/master-15e8cad1619429bf2547a6819b5b999510d5c1e5/flow-themes.tar.gz", @@ -32,8 +32,8 @@ .hash = "122019f077d09686b1ec47928ca2b4bf264422f3a27afc5b49dafb0129a4ceca0d01", }, .vaxis = .{ - .url = "https://github.com/neurocyte/libvaxis/archive/cba7e049dd22648bba6c0f4fab01eeeed2d69a5b.tar.gz", - .hash = "1220e9c7c197181bc3ac405266f1160826720675160ae3e2b38204322e901c4244d8", + .url = "https://github.com/neurocyte/libvaxis/archive/507b8d5dcaa3e2fc972739d8d9e9e2ef5a0634a3.tar.gz", + .hash = "1220caa1b2a6f2c638a304b9cb5db9bf3319c7d821832fae476871b720d7019cabdd", }, .zg = .{ .url = "git+https://codeberg.org/dude_the_builder/zg#c425c9c8511bf92e14b8b612d1d16e774b186f2e", diff --git a/src/main.zig b/src/main.zig index 9cea622..063fc15 100644 --- a/src/main.zig +++ b/src/main.zig @@ -73,12 +73,18 @@ pub fn main() anyerror!void { if (res.args.help != 0) return clap.help(std.io.getStdErr().writer(), clap.Help, ¶ms, .{}); - if (std.posix.getenv("JITDEBUG")) |_| thespian.install_debugger(); + if (builtin.os.tag != .windows) + if (std.posix.getenv("JITDEBUG")) |_| thespian.install_debugger(); if (res.args.@"debug-wait" != 0) { - std.debug.print("press return to start", .{}); - var buf: [10]u8 = undefined; - _ = std.c.read(0, &buf, @sizeOf(@TypeOf(buf))); + if (builtin.os.tag == .windows) { + std.debug.print("--debug-wait is not implemented on windows", .{}); + return error.DebugWaitFailed; + } else { + std.debug.print("press return to start", .{}); + var buf: [10]u8 = undefined; + _ = std.c.read(0, &buf, @sizeOf(@TypeOf(buf))); + } } if (c.setlocale(c.LC_ALL, "") == null) { @@ -351,15 +357,18 @@ pub fn get_config_dir() ![]const u8 { } fn get_app_config_dir(appname: []const u8) ![]const u8 { + const a = std.heap.c_allocator; const local = struct { var config_dir_buffer: [std.posix.PATH_MAX]u8 = undefined; var config_dir: ?[]const u8 = null; }; const config_dir = if (local.config_dir) |dir| dir - else if (std.posix.getenv("XDG_CONFIG_HOME")) |xdg| - try std.fmt.bufPrint(&local.config_dir_buffer, "{s}/{s}", .{ xdg, appname }) - else if (std.posix.getenv("HOME")) |home| ret: { + else if (std.process.getEnvVarOwned(a, "XDG_CONFIG_HOME") catch null) |xdg| ret: { + defer a.free(xdg); + break :ret try std.fmt.bufPrint(&local.config_dir_buffer, "{s}/{s}", .{ xdg, appname }); + } else if (std.process.getEnvVarOwned(a, "HOME") catch null) |home| ret: { + defer a.free(home); const dir = try std.fmt.bufPrint(&local.config_dir_buffer, "{s}/.config", .{home}); std.fs.makeDirAbsolute(dir) catch |e| switch (e) { error.PathAlreadyExists => {}, @@ -382,15 +391,18 @@ pub fn get_cache_dir() ![]const u8 { } fn get_app_cache_dir(appname: []const u8) ![]const u8 { + const a = std.heap.c_allocator; const local = struct { var cache_dir_buffer: [std.posix.PATH_MAX]u8 = undefined; var cache_dir: ?[]const u8 = null; }; const cache_dir = if (local.cache_dir) |dir| dir - else if (std.posix.getenv("XDG_CACHE_HOME")) |xdg| - try std.fmt.bufPrint(&local.cache_dir_buffer, "{s}/{s}", .{ xdg, appname }) - else if (std.posix.getenv("HOME")) |home| ret: { + else if (std.process.getEnvVarOwned(a, "XDG_CACHE_HOME") catch null) |xdg| ret: { + defer a.free(xdg); + break :ret try std.fmt.bufPrint(&local.cache_dir_buffer, "{s}/{s}", .{ xdg, appname }); + } else if (std.process.getEnvVarOwned(a, "HOME") catch null) |home| ret: { + defer a.free(home); const dir = try std.fmt.bufPrint(&local.cache_dir_buffer, "{s}/.cache", .{home}); std.fs.makeDirAbsolute(dir) catch |e| switch (e) { error.PathAlreadyExists => {}, diff --git a/src/renderer/vaxis/renderer.zig b/src/renderer/vaxis/renderer.zig index 2f6993d..313200f 100644 --- a/src/renderer/vaxis/renderer.zig +++ b/src/renderer/vaxis/renderer.zig @@ -2,8 +2,8 @@ const std = @import("std"); const cbor = @import("cbor"); const log = @import("log"); const Style = @import("theme").Style; - const vaxis = @import("vaxis"); +const builtin = @import("builtin"); pub const input = @import("input.zig"); @@ -40,6 +40,8 @@ dispatch_event: ?*const fn (ctx: *anyopaque, cbor_msg: []const u8) void = null, logger: log.Logger, +loop: Loop, + const Event = union(enum) { key_press: vaxis.Key, winsize: vaxis.Winsize, @@ -67,11 +69,13 @@ pub fn init(a: std.mem.Allocator, handler_ctx: *anyopaque, no_alternate: bool) ! .bracketed_paste_buffer = std.ArrayList(u8).init(a), .handler_ctx = handler_ctx, .logger = log.logger(log_name), + .loop = undefined, }; } pub fn deinit(self: *Self) void { panic_cleanup_tty = null; + self.loop.stop(); self.vx.deinit(self.a, self.tty.anyWriter()); self.tty.deinit(); self.bracketed_paste_buffer.deinit(); @@ -93,6 +97,9 @@ pub fn run(self: *Self) !void { try self.query_resize(); try self.vx.setBracketedPaste(self.tty.anyWriter(), true); try self.vx.queryTerminalSend(self.tty.anyWriter()); + + self.loop = Loop.init(&self.tty, &self.vx); + try self.loop.start(); } pub fn render(self: *Self) !void { @@ -102,7 +109,8 @@ pub fn render(self: *Self) !void { } pub fn query_resize(self: *Self) !void { - try self.resize(try vaxis.Tty.getWinsize(self.input_fd_blocking())); + if (builtin.os.tag != .windows) + try self.resize(try vaxis.Tty.getWinsize(self.input_fd_blocking())); } pub fn resize(self: *Self, ws: vaxis.Winsize) !void { @@ -133,69 +141,70 @@ pub fn leave_alternate_screen(self: *Self) void { self.vx.exitAltScreen() catch {}; } -pub fn process_input(self: *Self, input_: []const u8) !void { - var parser: vaxis.Parser = .{ - .grapheme_data = &self.vx.screen.unicode.grapheme_data, - }; - try self.input_buffer.appendSlice(input_); - var buf = self.input_buffer.items; - defer { - if (buf.len == 0) { - self.input_buffer.clearRetainingCapacity(); - } else { - const rest = self.a.alloc(u8, buf.len) catch |e| std.debug.panic("{any}", .{e}); - @memcpy(rest, buf); - self.input_buffer.deinit(); - self.input_buffer = std.ArrayList(u8).fromOwnedSlice(self.a, rest); - } - } - while (buf.len > 0) { - const result = try parser.parse(buf, self.a); - if (result.n == 0) - return; - buf = buf[result.n..]; - const event = result.event orelse continue; - switch (event) { - .key_press => |key_| { - try self.sync_mod_state(key_.codepoint, key_.mods); - const cbor_msg = try self.fmtmsg(.{ - "I", +pub fn process_input_event(self: *Self, input_: []const u8) !void { + const event = std.mem.bytesAsValue(vaxis.Event, input_); + switch (event.*) { + .key_press => |key_| { + try self.sync_mod_state(key_.codepoint, key_.mods); + const cbor_msg = try self.fmtmsg(.{ + "I", + event_type.PRESS, + key_.codepoint, + key_.shifted_codepoint orelse key_.codepoint, + key_.text orelse input.utils.key_id_string(key_.base_layout_codepoint orelse key_.codepoint), + @as(u8, @bitCast(key_.mods)), + }); + if (self.bracketed_paste and self.handle_bracketed_paste_input(cbor_msg) catch |e| { + self.bracketed_paste_buffer.clearAndFree(); + self.bracketed_paste = false; + return e; + }) {} else if (self.dispatch_input) |f| f(self.handler_ctx, cbor_msg); + }, + .key_release => |*key_| { + const cbor_msg = try self.fmtmsg(.{ + "I", + event_type.RELEASE, + key_.codepoint, + key_.shifted_codepoint orelse key_.codepoint, + key_.text orelse input.utils.key_id_string(key_.base_layout_codepoint orelse key_.codepoint), + @as(u8, @bitCast(key_.mods)), + }); + if (self.bracketed_paste) {} else if (self.dispatch_input) |f| f(self.handler_ctx, cbor_msg); + }, + .mouse => |mouse_| { + const mouse = self.vx.translateMouse(mouse_); + try self.sync_mod_state(0, .{ .ctrl = mouse.mods.ctrl, .shift = mouse.mods.shift, .alt = mouse.mods.alt }); + if (self.dispatch_mouse) |f| switch (mouse.type) { + .motion => f(self.handler_ctx, @intCast(mouse.row), @intCast(mouse.col), try self.fmtmsg(.{ + "M", + mouse.col, + mouse.row, + mouse.xoffset, + mouse.yoffset, + })), + .press => f(self.handler_ctx, @intCast(mouse.row), @intCast(mouse.col), try self.fmtmsg(.{ + "B", event_type.PRESS, - key_.codepoint, - key_.shifted_codepoint orelse key_.codepoint, - key_.text orelse input.utils.key_id_string(key_.base_layout_codepoint orelse key_.codepoint), - @as(u8, @bitCast(key_.mods)), - }); - if (self.bracketed_paste and self.handle_bracketed_paste_input(cbor_msg) catch |e| { - self.bracketed_paste_buffer.clearAndFree(); - self.bracketed_paste = false; - return e; - }) {} else if (self.dispatch_input) |f| f(self.handler_ctx, cbor_msg); - }, - .key_release => |*key_| { - const cbor_msg = try self.fmtmsg(.{ - "I", + @intFromEnum(mouse.button), + input.utils.button_id_string(@intFromEnum(mouse.button)), + mouse.col, + mouse.row, + mouse.xoffset, + mouse.yoffset, + })), + .release => f(self.handler_ctx, @intCast(mouse.row), @intCast(mouse.col), try self.fmtmsg(.{ + "B", event_type.RELEASE, - key_.codepoint, - key_.shifted_codepoint orelse key_.codepoint, - key_.text orelse input.utils.key_id_string(key_.base_layout_codepoint orelse key_.codepoint), - @as(u8, @bitCast(key_.mods)), - }); - if (self.bracketed_paste) {} else if (self.dispatch_input) |f| f(self.handler_ctx, cbor_msg); - }, - .mouse => |mouse_| { - const mouse = self.vx.translateMouse(mouse_); - try self.sync_mod_state(0, .{ .ctrl = mouse.mods.ctrl, .shift = mouse.mods.shift, .alt = mouse.mods.alt }); - if (self.dispatch_mouse) |f| switch (mouse.type) { - .motion => f(self.handler_ctx, @intCast(mouse.row), @intCast(mouse.col), try self.fmtmsg(.{ - "M", - mouse.col, - mouse.row, - mouse.xoffset, - mouse.yoffset, - })), - .press => f(self.handler_ctx, @intCast(mouse.row), @intCast(mouse.col), try self.fmtmsg(.{ - "B", + @intFromEnum(mouse.button), + input.utils.button_id_string(@intFromEnum(mouse.button)), + mouse.col, + mouse.row, + mouse.xoffset, + mouse.yoffset, + })), + .drag => if (self.dispatch_mouse_drag) |f_| + f_(self.handler_ctx, @intCast(mouse.row), @intCast(mouse.col), true, try self.fmtmsg(.{ + "D", event_type.PRESS, @intFromEnum(mouse.button), input.utils.button_id_string(@intFromEnum(mouse.button)), @@ -204,76 +213,54 @@ pub fn process_input(self: *Self, input_: []const u8) !void { mouse.xoffset, mouse.yoffset, })), - .release => f(self.handler_ctx, @intCast(mouse.row), @intCast(mouse.col), try self.fmtmsg(.{ - "B", - event_type.RELEASE, - @intFromEnum(mouse.button), - input.utils.button_id_string(@intFromEnum(mouse.button)), - mouse.col, - mouse.row, - mouse.xoffset, - mouse.yoffset, - })), - .drag => if (self.dispatch_mouse_drag) |f_| - f_(self.handler_ctx, @intCast(mouse.row), @intCast(mouse.col), true, try self.fmtmsg(.{ - "D", - event_type.PRESS, - @intFromEnum(mouse.button), - input.utils.button_id_string(@intFromEnum(mouse.button)), - mouse.col, - mouse.row, - mouse.xoffset, - mouse.yoffset, - })), - }; - }, - .focus_in => { - if (self.dispatch_event) |f| f(self.handler_ctx, try self.fmtmsg(.{"focus_in"})); - }, - .focus_out => { - if (self.dispatch_event) |f| f(self.handler_ctx, try self.fmtmsg(.{"focus_out"})); - }, - .paste_start => { - self.bracketed_paste = true; - self.bracketed_paste_buffer.clearRetainingCapacity(); - }, - .paste_end => try self.handle_bracketed_paste_end(), - .paste => |text| { - defer self.a.free(text); - if (self.dispatch_event) |f| f(self.handler_ctx, try self.fmtmsg(.{ "system_clipboard", text })); - }, - .color_report => {}, - .color_scheme => {}, - .winsize => |ws| try self.resize(ws), + }; + }, + .focus_in => { + if (self.dispatch_event) |f| f(self.handler_ctx, try self.fmtmsg(.{"focus_in"})); + }, + .focus_out => { + if (self.dispatch_event) |f| f(self.handler_ctx, try self.fmtmsg(.{"focus_out"})); + }, + .paste_start => { + self.bracketed_paste = true; + self.bracketed_paste_buffer.clearRetainingCapacity(); + }, + .paste_end => try self.handle_bracketed_paste_end(), + .paste => |text| { + defer self.a.free(text); + if (self.dispatch_event) |f| f(self.handler_ctx, try self.fmtmsg(.{ "system_clipboard", text })); + }, + .color_report => {}, + .color_scheme => {}, + .winsize => |ws| try self.resize(ws), - .cap_unicode => { - self.logger.print("unicode capability detected", .{}); - self.vx.caps.unicode = .unicode; - self.vx.screen.width_method = .unicode; - }, - .cap_sgr_pixels => { - self.logger.print("pixel mouse capability detected", .{}); - self.vx.caps.sgr_pixels = true; - }, - .cap_da1 => { - self.vx.enableDetectedFeatures(self.tty.anyWriter()) catch |e| self.logger.err("enable features", e); - try self.vx.setMouseMode(self.tty.anyWriter(), true); - }, - .cap_kitty_keyboard => { - self.logger.print("kitty keyboard capability detected", .{}); - self.vx.caps.kitty_keyboard = true; - }, - .cap_kitty_graphics => { - if (!self.vx.caps.kitty_graphics) { - self.vx.caps.kitty_graphics = true; - } - }, - .cap_rgb => { - self.logger.print("rgb capability detected", .{}); - self.vx.caps.rgb = true; - }, - .cap_color_scheme_updates => {}, - } + .cap_unicode => { + self.logger.print("unicode capability detected", .{}); + self.vx.caps.unicode = .unicode; + self.vx.screen.width_method = .unicode; + }, + .cap_sgr_pixels => { + self.logger.print("pixel mouse capability detected", .{}); + self.vx.caps.sgr_pixels = true; + }, + .cap_da1 => { + self.vx.enableDetectedFeatures(self.tty.anyWriter()) catch |e| self.logger.err("enable features", e); + try self.vx.setMouseMode(self.tty.anyWriter(), true); + }, + .cap_kitty_keyboard => { + self.logger.print("kitty keyboard capability detected", .{}); + self.vx.caps.kitty_keyboard = true; + }, + .cap_kitty_graphics => { + if (!self.vx.caps.kitty_graphics) { + self.vx.caps.kitty_graphics = true; + } + }, + .cap_rgb => { + self.logger.print("rgb capability detected", .{}); + self.vx.caps.rgb = true; + }, + .cap_color_scheme_updates => {}, } } @@ -379,3 +366,120 @@ fn send_sync_key(self: *Self, event_type_: usize, keypress: u32, key_string: []c }), ); } + +const Loop = struct { + tty: *vaxis.Tty, + vaxis: *vaxis.Vaxis, + pid: tp.pid, + + thread: ?std.Thread = null, + should_quit: bool = false, + cache: vaxis.GraphemeCache = .{}, + + const tp = @import("thespian"); + + pub fn init(tty: *vaxis.Tty, vaxis_: *vaxis.Vaxis) Loop { + return .{ + .tty = tty, + .vaxis = vaxis_, + .pid = tp.self_pid().clone(), + }; + } + + pub fn deinit(self: *Loop) void { + self.pid.deinit(); + } + + /// spawns the input thread to read input from the tty + pub fn start(self: *Loop) !void { + if (self.thread) |_| return; + self.thread = try std.Thread.spawn(.{}, Loop.ttyRun, .{ + self, + &self.vaxis.unicode.grapheme_data, + self.vaxis.opts.system_clipboard_allocator, + }); + } + + /// stops reading from the tty. + pub fn stop(self: *Loop) void { + self.should_quit = true; + // trigger a read + self.vaxis.deviceStatusReport(self.tty.anyWriter()) catch {}; + + if (self.thread) |thread| { + thread.join(); + self.thread = null; + self.should_quit = false; + } + } + + fn postEvent(self: *Loop, event: vaxis.Event) void { + switch (event) { + .key_press => |key_| { + var mut_key = key_; + if (key_.text) |text| + mut_key.text = self.cache.put(text); + }, + .key_release => |key_| { + var mut_key = key_; + if (key_.text) |text| + mut_key.text = self.cache.put(text); + }, + else => {}, + } + self.pid.send(.{ "VXS", std.mem.asBytes(&event) }) catch @panic("send VXS event failed"); + } + + /// read input from the tty. This is run in a separate thread + fn ttyRun( + self: *Loop, + grapheme_data: *const vaxis.grapheme.GraphemeData, + paste_allocator: ?std.mem.Allocator, + ) !void { + switch (builtin.os.tag) { + .windows => { + while (!self.should_quit) { + self.postEvent(try self.tty.nextEvent()); + } + }, + else => { + // get our initial winsize + const winsize = try vaxis.Tty.getWinsize(self.tty.fd); + if (@hasField(Event, "winsize")) { + self.postEvent(.{ .winsize = winsize }); + } + + var parser: vaxis.Parser = .{ + .grapheme_data = grapheme_data, + }; + + // initialize the read buffer + var buf: [1024]u8 = undefined; + var read_start: usize = 0; + // read loop + while (!self.should_quit) { + const n = try self.tty.read(buf[read_start..]); + var seq_start: usize = 0; + while (seq_start < n) { + const result = try parser.parse(buf[seq_start..n], paste_allocator); + if (result.n == 0) { + // copy the read to the beginning. We don't use memcpy because + // this could be overlapping, and it's also rare + const initial_start = seq_start; + while (seq_start < n) : (seq_start += 1) { + buf[seq_start - initial_start] = buf[seq_start]; + } + read_start = seq_start - initial_start + 1; + continue; + } + read_start = 0; + seq_start += result.n; + + const event = result.event orelse continue; + self.postEvent(event); + } + } + }, + } + } +}; diff --git a/src/tui/status/filestate.zig b/src/tui/status/filestate.zig index f5d0569..e22e8ad 100644 --- a/src/tui/status/filestate.zig +++ b/src/tui/status/filestate.zig @@ -3,6 +3,7 @@ const Allocator = std.mem.Allocator; const tp = @import("thespian"); const tracy = @import("tracy"); const root = @import("root"); +const builtin = @import("builtin"); const Plane = @import("renderer").Plane; const style = @import("renderer").style; @@ -217,6 +218,7 @@ fn show_project(self: *Self) void { } fn abbrv_home(self: *Self) void { + if (builtin.os.tag == .windows) return; if (!std.fs.path.isAbsolute(self.name)) return; const homedir = std.posix.getenv("HOME") orelse return; const homerelpath = std.fs.path.relative(self.a, homedir, self.name) catch return; diff --git a/src/tui/tui.zig b/src/tui/tui.zig index b3789ae..eec3671 100644 --- a/src/tui/tui.zig +++ b/src/tui/tui.zig @@ -6,6 +6,7 @@ const project_manager = @import("project_manager"); const build_options = @import("build_options"); const root = @import("root"); const tracy = @import("tracy"); +const builtin = @import("builtin"); pub const renderer = @import("renderer"); @@ -110,20 +111,19 @@ fn init(a: Allocator) !*Self { instance_ = self; defer instance_ = null; - try self.rdr.run(); - const n = self.rdr.stdplane(); - - try frame_clock.start(); - try InputReader.create(a, self.rdr.input_fd_blocking()); - self.rdr.handler_ctx = self; self.rdr.dispatch_input = dispatch_input; self.rdr.dispatch_mouse = dispatch_mouse; self.rdr.dispatch_mouse_drag = dispatch_mouse_drag; self.rdr.dispatch_event = dispatch_event; + try self.rdr.run(); + const n = self.rdr.stdplane(); + + try frame_clock.start(); try self.commands.init(self); errdefer self.deinit(); - try self.listen_sigwinch(); + if (builtin.os.tag != .windows) + try self.listen_sigwinch(); self.mainview = try mainview.create(a, n); try self.rdr.render(); try self.save_config(); @@ -176,6 +176,15 @@ fn receive(self: *Self, from: tp.pid_ref, m: tp.message) tp.result { } fn receive_safe(self: *Self, from: tp.pid_ref, m: tp.message) tp.result { + var input: []const u8 = undefined; + if (try m.match(.{ "VXS", tp.extract(&input) })) { + self.rdr.process_input_event(input) catch |e| return tp.exit_error(e); + try self.dispatch_flush_input_event(); + if (self.unrendered_input_events_count > 0 and !self.frame_clock_running) + need_render(); + return; + } + if (self.message_filters.filter(from, m) catch |e| return self.logger.err("filter", e)) return; @@ -205,13 +214,14 @@ fn receive_safe(self: *Self, from: tp.pid_ref, m: tp.message) tp.result { return; } - if (try m.match(.{"sigwinch"})) { - try self.listen_sigwinch(); - self.rdr.query_resize() catch |e| return self.logger.err("query_resize", e); - self.mainview.resize(Widget.Box.from(self.rdr.stdplane())); - need_render(); - return; - } + if (builtin.os.tag != .windows) + if (try m.match(.{"sigwinch"})) { + try self.listen_sigwinch(); + self.rdr.query_resize() catch |e| return self.logger.err("query_resize", e); + self.mainview.resize(Widget.Box.from(self.rdr.stdplane())); + need_render(); + return; + }; if (try m.match(.{"resize"})) { self.mainview.resize(Widget.Box.from(self.rdr.stdplane())); @@ -225,15 +235,6 @@ fn receive_safe(self: *Self, from: tp.pid_ref, m: tp.message) tp.result { return; } - var input: []const u8 = undefined; - if (try m.match(.{ "process_input", tp.extract(&input) })) { - self.rdr.process_input(input) catch |e| return tp.exit_error(e); - try self.dispatch_flush_input_event(); - if (self.unrendered_input_events_count > 0 and !self.frame_clock_running) - need_render(); - return; - } - if (try m.match(.{"render"})) { if (!self.frame_clock_running) self.render(std.time.microTimestamp()); @@ -775,35 +776,3 @@ pub const fallbacks: []const FallBack = &[_]FallBack{ .{ .ts = "repeat", .tm = "keyword.control.flow" }, .{ .ts = "field", .tm = "variable" }, }; - -const InputReader = struct { - a: std.mem.Allocator, - fd: std.posix.fd_t, - pid: tp.pid, - thread: std.Thread, - - fn create(a: std.mem.Allocator, fd: std.posix.fd_t) error{Exit}!void { - const self = a.create(InputReader) catch |e| return tp.exit_error(e); - self.* = .{ - .a = a, - .fd = fd, - .pid = tp.self_pid().clone(), - .thread = std.Thread.spawn(.{}, InputReader.start, .{self}) catch |e| return tp.exit_error(e), - }; - } - - fn deinit(self: *InputReader) void { - self.pid.deinit(); - self.a.destroy(self); - } - - fn start(self: *InputReader) void { - defer self.deinit(); - var buf: [4096]u8 = undefined; - while (true) { - const n = std.posix.read(self.fd, &buf) catch return; - if (n == 0) return; - self.pid.send(.{ "process_input", buf[0..n] }) catch {}; - } - } -};