feat: initial windows support
This commit is contained in:
parent
db4b3c48c4
commit
961e5afe41
7 changed files with 290 additions and 202 deletions
|
@ -125,6 +125,7 @@ pub fn build(b: *std.Build) void {
|
||||||
.{ .name = "theme", .module = themes_dep.module("theme") },
|
.{ .name = "theme", .module = themes_dep.module("theme") },
|
||||||
.{ .name = "cbor", .module = cbor_mod },
|
.{ .name = "cbor", .module = cbor_mod },
|
||||||
.{ .name = "log", .module = log_mod },
|
.{ .name = "log", .module = log_mod },
|
||||||
|
.{ .name = "thespian", .module = thespian_mod },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
0.13.0-dev.363+7fc3fb955
|
0.13.0
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
.hash = "1220220dbc7fe91c1c54438193ca765cebbcb7d58f35cdcaee404a9d2245a42a4362",
|
.hash = "1220220dbc7fe91c1c54438193ca765cebbcb7d58f35cdcaee404a9d2245a42a4362",
|
||||||
},
|
},
|
||||||
.thespian = .{
|
.thespian = .{
|
||||||
.url = "https://github.com/neurocyte/thespian/archive/3121af2ec484841103eae059c79e4c3ddbec4149.tar.gz",
|
.url = "https://github.com/neurocyte/thespian/archive/895d3dfb9ece213d614af97c9b636a0844e4e04b.tar.gz",
|
||||||
.hash = "1220794a8ca2f5e93e8dad61338f3bfd7a322f0c85635f367bc6cf0c178dcde70247",
|
.hash = "122045ee52e7f37488d35d2c9c2f16d321267b27c8df05ce4d007c869f8d7d0e64a8",
|
||||||
},
|
},
|
||||||
.themes = .{
|
.themes = .{
|
||||||
.url = "https://github.com/neurocyte/flow-themes/releases/download/master-15e8cad1619429bf2547a6819b5b999510d5c1e5/flow-themes.tar.gz",
|
.url = "https://github.com/neurocyte/flow-themes/releases/download/master-15e8cad1619429bf2547a6819b5b999510d5c1e5/flow-themes.tar.gz",
|
||||||
|
@ -32,8 +32,8 @@
|
||||||
.hash = "122019f077d09686b1ec47928ca2b4bf264422f3a27afc5b49dafb0129a4ceca0d01",
|
.hash = "122019f077d09686b1ec47928ca2b4bf264422f3a27afc5b49dafb0129a4ceca0d01",
|
||||||
},
|
},
|
||||||
.vaxis = .{
|
.vaxis = .{
|
||||||
.url = "https://github.com/neurocyte/libvaxis/archive/cba7e049dd22648bba6c0f4fab01eeeed2d69a5b.tar.gz",
|
.url = "https://github.com/neurocyte/libvaxis/archive/507b8d5dcaa3e2fc972739d8d9e9e2ef5a0634a3.tar.gz",
|
||||||
.hash = "1220e9c7c197181bc3ac405266f1160826720675160ae3e2b38204322e901c4244d8",
|
.hash = "1220caa1b2a6f2c638a304b9cb5db9bf3319c7d821832fae476871b720d7019cabdd",
|
||||||
},
|
},
|
||||||
.zg = .{
|
.zg = .{
|
||||||
.url = "git+https://codeberg.org/dude_the_builder/zg#c425c9c8511bf92e14b8b612d1d16e774b186f2e",
|
.url = "git+https://codeberg.org/dude_the_builder/zg#c425c9c8511bf92e14b8b612d1d16e774b186f2e",
|
||||||
|
|
24
src/main.zig
24
src/main.zig
|
@ -73,13 +73,19 @@ pub fn main() anyerror!void {
|
||||||
if (res.args.help != 0)
|
if (res.args.help != 0)
|
||||||
return clap.help(std.io.getStdErr().writer(), clap.Help, ¶ms, .{});
|
return clap.help(std.io.getStdErr().writer(), clap.Help, ¶ms, .{});
|
||||||
|
|
||||||
|
if (builtin.os.tag != .windows)
|
||||||
if (std.posix.getenv("JITDEBUG")) |_| thespian.install_debugger();
|
if (std.posix.getenv("JITDEBUG")) |_| thespian.install_debugger();
|
||||||
|
|
||||||
if (res.args.@"debug-wait" != 0) {
|
if (res.args.@"debug-wait" != 0) {
|
||||||
|
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", .{});
|
std.debug.print("press return to start", .{});
|
||||||
var buf: [10]u8 = undefined;
|
var buf: [10]u8 = undefined;
|
||||||
_ = std.c.read(0, &buf, @sizeOf(@TypeOf(buf)));
|
_ = std.c.read(0, &buf, @sizeOf(@TypeOf(buf)));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (c.setlocale(c.LC_ALL, "") == null) {
|
if (c.setlocale(c.LC_ALL, "") == null) {
|
||||||
return error.SetLocaleFailed;
|
return error.SetLocaleFailed;
|
||||||
|
@ -351,15 +357,18 @@ pub fn get_config_dir() ![]const u8 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_app_config_dir(appname: []const u8) ![]const u8 {
|
fn get_app_config_dir(appname: []const u8) ![]const u8 {
|
||||||
|
const a = std.heap.c_allocator;
|
||||||
const local = struct {
|
const local = struct {
|
||||||
var config_dir_buffer: [std.posix.PATH_MAX]u8 = undefined;
|
var config_dir_buffer: [std.posix.PATH_MAX]u8 = undefined;
|
||||||
var config_dir: ?[]const u8 = null;
|
var config_dir: ?[]const u8 = null;
|
||||||
};
|
};
|
||||||
const config_dir = if (local.config_dir) |dir|
|
const config_dir = if (local.config_dir) |dir|
|
||||||
dir
|
dir
|
||||||
else if (std.posix.getenv("XDG_CONFIG_HOME")) |xdg|
|
else if (std.process.getEnvVarOwned(a, "XDG_CONFIG_HOME") catch null) |xdg| ret: {
|
||||||
try std.fmt.bufPrint(&local.config_dir_buffer, "{s}/{s}", .{ xdg, appname })
|
defer a.free(xdg);
|
||||||
else if (std.posix.getenv("HOME")) |home| ret: {
|
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});
|
const dir = try std.fmt.bufPrint(&local.config_dir_buffer, "{s}/.config", .{home});
|
||||||
std.fs.makeDirAbsolute(dir) catch |e| switch (e) {
|
std.fs.makeDirAbsolute(dir) catch |e| switch (e) {
|
||||||
error.PathAlreadyExists => {},
|
error.PathAlreadyExists => {},
|
||||||
|
@ -382,15 +391,18 @@ pub fn get_cache_dir() ![]const u8 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_app_cache_dir(appname: []const u8) ![]const u8 {
|
fn get_app_cache_dir(appname: []const u8) ![]const u8 {
|
||||||
|
const a = std.heap.c_allocator;
|
||||||
const local = struct {
|
const local = struct {
|
||||||
var cache_dir_buffer: [std.posix.PATH_MAX]u8 = undefined;
|
var cache_dir_buffer: [std.posix.PATH_MAX]u8 = undefined;
|
||||||
var cache_dir: ?[]const u8 = null;
|
var cache_dir: ?[]const u8 = null;
|
||||||
};
|
};
|
||||||
const cache_dir = if (local.cache_dir) |dir|
|
const cache_dir = if (local.cache_dir) |dir|
|
||||||
dir
|
dir
|
||||||
else if (std.posix.getenv("XDG_CACHE_HOME")) |xdg|
|
else if (std.process.getEnvVarOwned(a, "XDG_CACHE_HOME") catch null) |xdg| ret: {
|
||||||
try std.fmt.bufPrint(&local.cache_dir_buffer, "{s}/{s}", .{ xdg, appname })
|
defer a.free(xdg);
|
||||||
else if (std.posix.getenv("HOME")) |home| ret: {
|
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});
|
const dir = try std.fmt.bufPrint(&local.cache_dir_buffer, "{s}/.cache", .{home});
|
||||||
std.fs.makeDirAbsolute(dir) catch |e| switch (e) {
|
std.fs.makeDirAbsolute(dir) catch |e| switch (e) {
|
||||||
error.PathAlreadyExists => {},
|
error.PathAlreadyExists => {},
|
||||||
|
|
|
@ -2,8 +2,8 @@ const std = @import("std");
|
||||||
const cbor = @import("cbor");
|
const cbor = @import("cbor");
|
||||||
const log = @import("log");
|
const log = @import("log");
|
||||||
const Style = @import("theme").Style;
|
const Style = @import("theme").Style;
|
||||||
|
|
||||||
const vaxis = @import("vaxis");
|
const vaxis = @import("vaxis");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
pub const input = @import("input.zig");
|
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,
|
logger: log.Logger,
|
||||||
|
|
||||||
|
loop: Loop,
|
||||||
|
|
||||||
const Event = union(enum) {
|
const Event = union(enum) {
|
||||||
key_press: vaxis.Key,
|
key_press: vaxis.Key,
|
||||||
winsize: vaxis.Winsize,
|
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),
|
.bracketed_paste_buffer = std.ArrayList(u8).init(a),
|
||||||
.handler_ctx = handler_ctx,
|
.handler_ctx = handler_ctx,
|
||||||
.logger = log.logger(log_name),
|
.logger = log.logger(log_name),
|
||||||
|
.loop = undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Self) void {
|
pub fn deinit(self: *Self) void {
|
||||||
panic_cleanup_tty = null;
|
panic_cleanup_tty = null;
|
||||||
|
self.loop.stop();
|
||||||
self.vx.deinit(self.a, self.tty.anyWriter());
|
self.vx.deinit(self.a, self.tty.anyWriter());
|
||||||
self.tty.deinit();
|
self.tty.deinit();
|
||||||
self.bracketed_paste_buffer.deinit();
|
self.bracketed_paste_buffer.deinit();
|
||||||
|
@ -93,6 +97,9 @@ pub fn run(self: *Self) !void {
|
||||||
try self.query_resize();
|
try self.query_resize();
|
||||||
try self.vx.setBracketedPaste(self.tty.anyWriter(), true);
|
try self.vx.setBracketedPaste(self.tty.anyWriter(), true);
|
||||||
try self.vx.queryTerminalSend(self.tty.anyWriter());
|
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 {
|
pub fn render(self: *Self) !void {
|
||||||
|
@ -102,6 +109,7 @@ pub fn render(self: *Self) !void {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn query_resize(self: *Self) !void {
|
pub fn query_resize(self: *Self) !void {
|
||||||
|
if (builtin.os.tag != .windows)
|
||||||
try self.resize(try vaxis.Tty.getWinsize(self.input_fd_blocking()));
|
try self.resize(try vaxis.Tty.getWinsize(self.input_fd_blocking()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,29 +141,9 @@ pub fn leave_alternate_screen(self: *Self) void {
|
||||||
self.vx.exitAltScreen() catch {};
|
self.vx.exitAltScreen() catch {};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_input(self: *Self, input_: []const u8) !void {
|
pub fn process_input_event(self: *Self, input_: []const u8) !void {
|
||||||
var parser: vaxis.Parser = .{
|
const event = std.mem.bytesAsValue(vaxis.Event, input_);
|
||||||
.grapheme_data = &self.vx.screen.unicode.grapheme_data,
|
switch (event.*) {
|
||||||
};
|
|
||||||
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_| {
|
.key_press => |key_| {
|
||||||
try self.sync_mod_state(key_.codepoint, key_.mods);
|
try self.sync_mod_state(key_.codepoint, key_.mods);
|
||||||
const cbor_msg = try self.fmtmsg(.{
|
const cbor_msg = try self.fmtmsg(.{
|
||||||
|
@ -274,7 +262,6 @@ pub fn process_input(self: *Self, input_: []const u8) !void {
|
||||||
},
|
},
|
||||||
.cap_color_scheme_updates => {},
|
.cap_color_scheme_updates => {},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fmtmsg(self: *Self, value: anytype) ![]const u8 {
|
fn fmtmsg(self: *Self, value: anytype) ![]const u8 {
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
@ -3,6 +3,7 @@ const Allocator = std.mem.Allocator;
|
||||||
const tp = @import("thespian");
|
const tp = @import("thespian");
|
||||||
const tracy = @import("tracy");
|
const tracy = @import("tracy");
|
||||||
const root = @import("root");
|
const root = @import("root");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
const Plane = @import("renderer").Plane;
|
const Plane = @import("renderer").Plane;
|
||||||
const style = @import("renderer").style;
|
const style = @import("renderer").style;
|
||||||
|
@ -217,6 +218,7 @@ fn show_project(self: *Self) void {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn abbrv_home(self: *Self) void {
|
fn abbrv_home(self: *Self) void {
|
||||||
|
if (builtin.os.tag == .windows) return;
|
||||||
if (!std.fs.path.isAbsolute(self.name)) return;
|
if (!std.fs.path.isAbsolute(self.name)) return;
|
||||||
const homedir = std.posix.getenv("HOME") orelse return;
|
const homedir = std.posix.getenv("HOME") orelse return;
|
||||||
const homerelpath = std.fs.path.relative(self.a, homedir, self.name) catch return;
|
const homerelpath = std.fs.path.relative(self.a, homedir, self.name) catch return;
|
||||||
|
|
|
@ -6,6 +6,7 @@ const project_manager = @import("project_manager");
|
||||||
const build_options = @import("build_options");
|
const build_options = @import("build_options");
|
||||||
const root = @import("root");
|
const root = @import("root");
|
||||||
const tracy = @import("tracy");
|
const tracy = @import("tracy");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
pub const renderer = @import("renderer");
|
pub const renderer = @import("renderer");
|
||||||
|
|
||||||
|
@ -110,19 +111,18 @@ fn init(a: Allocator) !*Self {
|
||||||
instance_ = self;
|
instance_ = self;
|
||||||
defer instance_ = null;
|
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.handler_ctx = self;
|
||||||
self.rdr.dispatch_input = dispatch_input;
|
self.rdr.dispatch_input = dispatch_input;
|
||||||
self.rdr.dispatch_mouse = dispatch_mouse;
|
self.rdr.dispatch_mouse = dispatch_mouse;
|
||||||
self.rdr.dispatch_mouse_drag = dispatch_mouse_drag;
|
self.rdr.dispatch_mouse_drag = dispatch_mouse_drag;
|
||||||
self.rdr.dispatch_event = dispatch_event;
|
self.rdr.dispatch_event = dispatch_event;
|
||||||
|
try self.rdr.run();
|
||||||
|
const n = self.rdr.stdplane();
|
||||||
|
|
||||||
|
try frame_clock.start();
|
||||||
try self.commands.init(self);
|
try self.commands.init(self);
|
||||||
errdefer self.deinit();
|
errdefer self.deinit();
|
||||||
|
if (builtin.os.tag != .windows)
|
||||||
try self.listen_sigwinch();
|
try self.listen_sigwinch();
|
||||||
self.mainview = try mainview.create(a, n);
|
self.mainview = try mainview.create(a, n);
|
||||||
try self.rdr.render();
|
try self.rdr.render();
|
||||||
|
@ -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 {
|
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))
|
if (self.message_filters.filter(from, m) catch |e| return self.logger.err("filter", e))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -205,13 +214,14 @@ fn receive_safe(self: *Self, from: tp.pid_ref, m: tp.message) tp.result {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (builtin.os.tag != .windows)
|
||||||
if (try m.match(.{"sigwinch"})) {
|
if (try m.match(.{"sigwinch"})) {
|
||||||
try self.listen_sigwinch();
|
try self.listen_sigwinch();
|
||||||
self.rdr.query_resize() catch |e| return self.logger.err("query_resize", e);
|
self.rdr.query_resize() catch |e| return self.logger.err("query_resize", e);
|
||||||
self.mainview.resize(Widget.Box.from(self.rdr.stdplane()));
|
self.mainview.resize(Widget.Box.from(self.rdr.stdplane()));
|
||||||
need_render();
|
need_render();
|
||||||
return;
|
return;
|
||||||
}
|
};
|
||||||
|
|
||||||
if (try m.match(.{"resize"})) {
|
if (try m.match(.{"resize"})) {
|
||||||
self.mainview.resize(Widget.Box.from(self.rdr.stdplane()));
|
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;
|
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 (try m.match(.{"render"})) {
|
||||||
if (!self.frame_clock_running)
|
if (!self.frame_clock_running)
|
||||||
self.render(std.time.microTimestamp());
|
self.render(std.time.microTimestamp());
|
||||||
|
@ -775,35 +776,3 @@ pub const fallbacks: []const FallBack = &[_]FallBack{
|
||||||
.{ .ts = "repeat", .tm = "keyword.control.flow" },
|
.{ .ts = "repeat", .tm = "keyword.control.flow" },
|
||||||
.{ .ts = "field", .tm = "variable" },
|
.{ .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 {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue