Compare commits
6 commits
582d3d1066
...
4157638892
| Author | SHA1 | Date | |
|---|---|---|---|
| 4157638892 | |||
| f88f779410 | |||
| 3e265dade5 | |||
| 69b0885f4b | |||
| 61a509cf2f | |||
| 316b65a0f7 |
5 changed files with 154 additions and 84 deletions
|
|
@ -30,8 +30,8 @@
|
||||||
.hash = "fuzzig-0.1.1-Ji0xivxIAQBD0g8O_NV_0foqoPf3elsg9Sc3pNfdVH4D",
|
.hash = "fuzzig-0.1.1-Ji0xivxIAQBD0g8O_NV_0foqoPf3elsg9Sc3pNfdVH4D",
|
||||||
},
|
},
|
||||||
.vaxis = .{
|
.vaxis = .{
|
||||||
.url = "git+https://github.com/neurocyte/libvaxis?ref=main#03fe1b123afdaf879829da507f54e42780d4ec65",
|
.url = "git+https://github.com/neurocyte/libvaxis?ref=main#8561409c5cd0e1799118d188764ac3d6edae6445",
|
||||||
.hash = "vaxis-0.5.1-BWNV_EJOCQCOD5tzfVqOgDUSYfvBLrokxE0fr9MSb05q",
|
.hash = "vaxis-0.5.1-BWNV_MlsCQBt3YUcMDQoQIhq4I8rS2ElBX9rRjpktJBQ",
|
||||||
},
|
},
|
||||||
.zeit = .{
|
.zeit = .{
|
||||||
.url = "git+https://github.com/rockorager/zeit?ref=zig-0.15#ed2ca60db118414bda2b12df2039e33bad3b0b88",
|
.url = "git+https://github.com/rockorager/zeit?ref=zig-0.15#ed2ca60db118414bda2b12df2039e33bad3b0b88",
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ gutter_width_minimum: usize = 4,
|
||||||
gutter_width_maximum: usize = 8,
|
gutter_width_maximum: usize = 8,
|
||||||
enable_terminal_cursor: bool = true,
|
enable_terminal_cursor: bool = true,
|
||||||
enable_terminal_color_scheme: bool = false,
|
enable_terminal_color_scheme: bool = false,
|
||||||
|
terminal_scrollback_size: u16 = 500,
|
||||||
enable_sgr_pixel_mode_support: bool = true,
|
enable_sgr_pixel_mode_support: bool = true,
|
||||||
enable_modal_dim: bool = true,
|
enable_modal_dim: bool = true,
|
||||||
highlight_current_line: bool = true,
|
highlight_current_line: bool = true,
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,11 @@ pub fn parse(link: []const u8) error{InvalidFileLink}!Dest {
|
||||||
file.path = link;
|
file.path = link;
|
||||||
break :blk null;
|
break :blk null;
|
||||||
};
|
};
|
||||||
|
} else if (line_.len > 5 and std.mem.eql(u8, "line ", line_[0..5])) {
|
||||||
|
file.line = std.fmt.parseInt(usize, line_[5..], 10) catch blk: {
|
||||||
|
file.path = link;
|
||||||
|
break :blk null;
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
file.line = std.fmt.parseInt(usize, line_, 10) catch blk: {
|
file.line = std.fmt.parseInt(usize, line_, 10) catch blk: {
|
||||||
file.path = link;
|
file.path = link;
|
||||||
|
|
|
||||||
|
|
@ -600,7 +600,8 @@
|
||||||
["alt+shift+p", "open_command_palette"],
|
["alt+shift+p", "open_command_palette"],
|
||||||
["alt+x", "open_command_palette"],
|
["alt+x", "open_command_palette"],
|
||||||
["alt+!", "run_task"],
|
["alt+!", "run_task"],
|
||||||
["alt+f9", "panel_next_widget_style"]
|
["alt+f9", "panel_next_widget_style"],
|
||||||
|
["ctrl+shift+q", "quit_without_saving"]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,24 +25,16 @@ const Terminal = vaxis.widgets.Terminal;
|
||||||
|
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
plane: Plane,
|
plane: Plane,
|
||||||
vt: Terminal,
|
|
||||||
env: std.process.EnvMap,
|
|
||||||
write_buf: [4096]u8,
|
|
||||||
pty_pid: ?tp.pid = null,
|
|
||||||
focused: bool = false,
|
focused: bool = false,
|
||||||
cwd: std.ArrayListUnmanaged(u8) = .empty,
|
|
||||||
title: std.ArrayListUnmanaged(u8) = .empty,
|
|
||||||
input_mode: Mode,
|
input_mode: Mode,
|
||||||
hover: bool = false,
|
hover: bool = false,
|
||||||
|
vt: *Vt,
|
||||||
|
|
||||||
pub fn create(allocator: Allocator, parent: Plane) !Widget {
|
pub fn create(allocator: Allocator, parent: Plane) !Widget {
|
||||||
return create_with_args(allocator, parent, .{});
|
return create_with_args(allocator, parent, .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_with_args(allocator: Allocator, parent: Plane, ctx: command.Context) !Widget {
|
pub fn create_with_args(allocator: Allocator, parent: Plane, ctx: command.Context) !Widget {
|
||||||
const self = try allocator.create(Self);
|
|
||||||
errdefer allocator.destroy(self);
|
|
||||||
|
|
||||||
const container = try WidgetList.createHStyled(
|
const container = try WidgetList.createHStyled(
|
||||||
allocator,
|
allocator,
|
||||||
parent,
|
parent,
|
||||||
|
|
@ -77,8 +69,6 @@ pub fn create_with_args(allocator: Allocator, parent: Plane, ctx: command.Contex
|
||||||
} else {
|
} else {
|
||||||
try argv_list.append(allocator, env.get("SHELL") orelse "bash");
|
try argv_list.append(allocator, env.get("SHELL") orelse "bash");
|
||||||
}
|
}
|
||||||
const argv: []const []const u8 = argv_list.items;
|
|
||||||
const home = env.get("HOME") orelse "/tmp";
|
|
||||||
|
|
||||||
// Use the current plane dimensions for the initial pty size. The plane
|
// Use the current plane dimensions for the initial pty size. The plane
|
||||||
// starts at 0×0 before the first resize, so use a sensible fallback
|
// starts at 0×0 before the first resize, so use a sensible fallback
|
||||||
|
|
@ -86,43 +76,23 @@ pub fn create_with_args(allocator: Allocator, parent: Plane, ctx: command.Contex
|
||||||
const cols: u16 = @intCast(@max(80, plane.dim_x()));
|
const cols: u16 = @intCast(@max(80, plane.dim_x()));
|
||||||
const rows: u16 = @intCast(@max(24, plane.dim_y()));
|
const rows: u16 = @intCast(@max(24, plane.dim_y()));
|
||||||
|
|
||||||
// write_buf must outlive the Terminal because the pty writer holds a
|
if (global_vt == null) try Vt.init(allocator, argv_list.items, env, rows, cols);
|
||||||
// pointer into it. It lives inside Self so the lifetimes match.
|
|
||||||
self.write_buf = undefined;
|
const self = try allocator.create(Self);
|
||||||
const vt = try Terminal.init(
|
errdefer allocator.destroy(self);
|
||||||
allocator,
|
|
||||||
argv,
|
|
||||||
&env,
|
|
||||||
.{
|
|
||||||
.winsize = .{ .rows = rows, .cols = cols, .x_pixel = 0, .y_pixel = 0 },
|
|
||||||
.scrollback_size = 0,
|
|
||||||
.initial_working_directory = blk: {
|
|
||||||
const project = tp.env.get().str("project");
|
|
||||||
break :blk if (project.len > 0) project else home;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&self.write_buf,
|
|
||||||
);
|
|
||||||
|
|
||||||
self.* = .{
|
self.* = .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.plane = plane,
|
.plane = plane,
|
||||||
.vt = vt,
|
|
||||||
.env = env,
|
|
||||||
.write_buf = undefined, // managed via self.vt's pty_writer pointer
|
|
||||||
.pty_pid = null,
|
|
||||||
.input_mode = try keybind.mode("terminal", allocator, .{ .insert_command = "do_nothing" }),
|
.input_mode = try keybind.mode("terminal", allocator, .{ .insert_command = "do_nothing" }),
|
||||||
|
.vt = &global_vt.?,
|
||||||
};
|
};
|
||||||
|
|
||||||
try self.vt.spawn();
|
|
||||||
|
|
||||||
try tui.message_filters().add(MessageFilter.bind(self, receive_filter));
|
try tui.message_filters().add(MessageFilter.bind(self, receive_filter));
|
||||||
|
|
||||||
container.ctx = self;
|
container.ctx = self;
|
||||||
try container.add(Widget.to(self));
|
try container.add(Widget.to(self));
|
||||||
|
|
||||||
self.pty_pid = try pty.spawn(allocator, &self.vt);
|
|
||||||
|
|
||||||
return container.widget();
|
return container.widget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,6 +113,15 @@ pub fn receive(self: *Self, from: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
||||||
.same, .notfound => {},
|
.same, .notfound => {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (try m.match(.{ "B", input.event.press, @intFromEnum(input.mouse.BUTTON4), tp.more })) {
|
||||||
|
if (self.vt.vt.scroll(3)) tui.need_render(@src());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (try m.match(.{ "B", input.event.press, @intFromEnum(input.mouse.BUTTON5), tp.more })) {
|
||||||
|
if (self.vt.vt.scroll(-3)) tui.need_render(@src());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(try m.match(.{ "I", tp.more })
|
if (!(try m.match(.{ "I", tp.more })
|
||||||
// or
|
// or
|
||||||
// try m.match(.{ "B", tp.more }) or
|
// try m.match(.{ "B", tp.more }) or
|
||||||
|
|
@ -173,7 +152,8 @@ pub fn receive(self: *Self, from: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
||||||
.mods = @bitCast(modifiers),
|
.mods = @bitCast(modifiers),
|
||||||
.text = if (text.len > 0) text else null,
|
.text = if (text.len > 0) text else null,
|
||||||
};
|
};
|
||||||
self.vt.update(.{ .key_press = key }) catch |e|
|
self.vt.vt.scrollToBottom();
|
||||||
|
self.vt.vt.update(.{ .key_press = key }) catch |e|
|
||||||
std.log.err("terminal_view: input failed: {}", .{e});
|
std.log.err("terminal_view: input failed: {}", .{e});
|
||||||
tui.need_render(@src());
|
tui.need_render(@src());
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -195,22 +175,17 @@ pub fn unfocus(self: *Self) void {
|
||||||
|
|
||||||
pub fn deinit(self: *Self, allocator: Allocator) void {
|
pub fn deinit(self: *Self, allocator: Allocator) void {
|
||||||
if (self.focused) tui.release_keyboard_focus(Widget.to(self));
|
if (self.focused) tui.release_keyboard_focus(Widget.to(self));
|
||||||
self.cwd.deinit(self.allocator);
|
// if (state) |*p| {
|
||||||
self.title.deinit(self.allocator);
|
// p.deinit(self.allocator);
|
||||||
if (self.pty_pid) |pid| {
|
// state = null;
|
||||||
pid.send(.{ "pty_actor", "quit" }) catch {};
|
// }
|
||||||
pid.deinit();
|
|
||||||
self.pty_pid = null;
|
|
||||||
}
|
|
||||||
self.vt.deinit();
|
|
||||||
self.env.deinit();
|
|
||||||
self.plane.deinit();
|
self.plane.deinit();
|
||||||
allocator.destroy(self);
|
allocator.destroy(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(self: *Self, _: *const Widget.Theme) bool {
|
pub fn render(self: *Self, _: *const Widget.Theme) bool {
|
||||||
// Drain the vt event queue.
|
// Drain the vt event queue.
|
||||||
while (self.vt.tryEvent()) |event| {
|
while (self.vt.vt.tryEvent()) |event| {
|
||||||
switch (event) {
|
switch (event) {
|
||||||
.exited => |code| {
|
.exited => |code| {
|
||||||
self.show_exit_message(code);
|
self.show_exit_message(code);
|
||||||
|
|
@ -218,18 +193,18 @@ pub fn render(self: *Self, _: *const Widget.Theme) bool {
|
||||||
},
|
},
|
||||||
.redraw, .bell => {},
|
.redraw, .bell => {},
|
||||||
.pwd_change => |path| {
|
.pwd_change => |path| {
|
||||||
self.cwd.clearRetainingCapacity();
|
self.vt.cwd.clearRetainingCapacity();
|
||||||
self.cwd.appendSlice(self.allocator, path) catch {};
|
self.vt.cwd.appendSlice(self.allocator, path) catch {};
|
||||||
},
|
},
|
||||||
.title_change => |t| {
|
.title_change => |t| {
|
||||||
self.title.clearRetainingCapacity();
|
self.vt.title.clearRetainingCapacity();
|
||||||
self.title.appendSlice(self.allocator, t) catch {};
|
self.vt.title.appendSlice(self.allocator, t) catch {};
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Blit the terminal's front screen into our vaxis.Window.
|
// Blit the terminal's front screen into our vaxis.Window.
|
||||||
self.vt.draw(self.allocator, self.plane.window, self.focused) catch |e| {
|
self.vt.vt.draw(self.allocator, self.plane.window, self.focused) catch |e| {
|
||||||
std.log.err("terminal_view: draw failed: {}", .{e});
|
std.log.err("terminal_view: draw failed: {}", .{e});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -248,23 +223,13 @@ fn show_exit_message(self: *Self, code: u8) void {
|
||||||
w.writeAll("]\x1b[0m\r\n") catch {};
|
w.writeAll("]\x1b[0m\r\n") catch {};
|
||||||
var parser: pty.Parser = .{ .buf = .init(self.allocator) };
|
var parser: pty.Parser = .{ .buf = .init(self.allocator) };
|
||||||
defer parser.buf.deinit();
|
defer parser.buf.deinit();
|
||||||
_ = self.vt.processOutput(&parser, msg.written()) catch {};
|
_ = self.vt.vt.processOutput(&parser, msg.written()) catch {};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_resize(self: *Self, pos: Widget.Box) void {
|
pub fn handle_resize(self: *Self, pos: Widget.Box) void {
|
||||||
self.plane.move_yx(@intCast(pos.y), @intCast(pos.x)) catch return;
|
self.plane.move_yx(@intCast(pos.y), @intCast(pos.x)) catch return;
|
||||||
self.plane.resize_simple(@intCast(pos.h), @intCast(pos.w)) catch return;
|
self.plane.resize_simple(@intCast(pos.h), @intCast(pos.w)) catch return;
|
||||||
|
self.vt.resize(pos);
|
||||||
const cols: u16 = @intCast(@max(1, pos.w));
|
|
||||||
const rows: u16 = @intCast(@max(1, pos.h));
|
|
||||||
self.vt.resize(.{
|
|
||||||
.rows = rows,
|
|
||||||
.cols = cols,
|
|
||||||
.x_pixel = 0,
|
|
||||||
.y_pixel = 0,
|
|
||||||
}) catch |e| {
|
|
||||||
std.log.err("terminal_view: resize failed: {}", .{e});
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive_filter(_: *Self, _: tp.pid_ref, m: tp.message) MessageFilter.Error!bool {
|
fn receive_filter(_: *Self, _: tp.pid_ref, m: tp.message) MessageFilter.Error!bool {
|
||||||
|
|
@ -275,6 +240,70 @@ fn receive_filter(_: *Self, _: tp.pid_ref, m: tp.message) MessageFilter.Error!bo
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Vt = struct {
|
||||||
|
vt: Terminal,
|
||||||
|
env: std.process.EnvMap,
|
||||||
|
write_buf: [4096]u8,
|
||||||
|
pty_pid: ?tp.pid = null,
|
||||||
|
cwd: std.ArrayListUnmanaged(u8) = .empty,
|
||||||
|
title: std.ArrayListUnmanaged(u8) = .empty,
|
||||||
|
|
||||||
|
fn init(allocator: std.mem.Allocator, argv: []const []const u8, env: std.process.EnvMap, rows: u16, cols: u16) !void {
|
||||||
|
const home = env.get("HOME") orelse "/tmp";
|
||||||
|
|
||||||
|
global_vt = .{
|
||||||
|
.vt = undefined,
|
||||||
|
.env = env,
|
||||||
|
.write_buf = undefined, // managed via self.vt's pty_writer pointer
|
||||||
|
.pty_pid = null,
|
||||||
|
};
|
||||||
|
const self = &global_vt.?;
|
||||||
|
self.vt = try Terminal.init(
|
||||||
|
allocator,
|
||||||
|
argv,
|
||||||
|
&env,
|
||||||
|
.{
|
||||||
|
.winsize = .{ .rows = rows, .cols = cols, .x_pixel = 0, .y_pixel = 0 },
|
||||||
|
.scrollback_size = tui.config().terminal_scrollback_size,
|
||||||
|
.initial_working_directory = blk: {
|
||||||
|
const project = tp.env.get().str("project");
|
||||||
|
break :blk if (project.len > 0) project else home;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&self.write_buf,
|
||||||
|
);
|
||||||
|
|
||||||
|
try self.vt.spawn();
|
||||||
|
self.pty_pid = try pty.spawn(allocator, &self.vt);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deinit(self: *@This(), allocator: std.mem.Allocator) void {
|
||||||
|
self.cwd.deinit(allocator);
|
||||||
|
self.title.deinit(allocator);
|
||||||
|
if (self.pty_pid) |pid| {
|
||||||
|
pid.send(.{"quit"}) catch {};
|
||||||
|
pid.deinit();
|
||||||
|
self.pty_pid = null;
|
||||||
|
}
|
||||||
|
self.vt.deinit();
|
||||||
|
self.env.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resize(self: *@This(), pos: Widget.Box) void {
|
||||||
|
const cols: u16 = @intCast(@max(1, pos.w));
|
||||||
|
const rows: u16 = @intCast(@max(1, pos.h));
|
||||||
|
self.vt.resize(.{
|
||||||
|
.rows = rows,
|
||||||
|
.cols = cols,
|
||||||
|
.x_pixel = 0,
|
||||||
|
.y_pixel = 0,
|
||||||
|
}) catch |e| {
|
||||||
|
std.log.err("terminal: resize failed: {}", .{e});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var global_vt: ?Vt = null;
|
||||||
|
|
||||||
const pty = struct {
|
const pty = struct {
|
||||||
const Parser = Terminal.Parser;
|
const Parser = Terminal.Parser;
|
||||||
|
|
||||||
|
|
@ -321,16 +350,20 @@ const pty = struct {
|
||||||
errdefer self.deinit();
|
errdefer self.deinit();
|
||||||
|
|
||||||
if (try m.match(.{ "fd", "pty", "read_ready" })) {
|
if (try m.match(.{ "fd", "pty", "read_ready" })) {
|
||||||
try self.read_and_process();
|
self.read_and_process() catch |e| return switch (e) {
|
||||||
return;
|
error.Terminated => tp.exit_normal(),
|
||||||
}
|
error.InputOutput => tp.exit_normal(),
|
||||||
|
error.SendFailed => tp.exit_normal(),
|
||||||
if (try m.match(.{ "pty_actor", "quit" })) {
|
error.Unexpected => tp.exit_normal(),
|
||||||
|
};
|
||||||
|
} else if (try m.match(.{"quit"})) {
|
||||||
return tp.exit_normal();
|
return tp.exit_normal();
|
||||||
|
} else {
|
||||||
|
return tp.unexpected(m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_and_process(self: *@This()) tp.result {
|
fn read_and_process(self: *@This()) error{ Terminated, InputOutput, SendFailed, Unexpected }!void {
|
||||||
var buf: [4096]u8 = undefined;
|
var buf: [4096]u8 = undefined;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
@ -340,27 +373,57 @@ const pty = struct {
|
||||||
const code = self.vt.cmd.wait();
|
const code = self.vt.cmd.wait();
|
||||||
self.vt.event_queue.push(.{ .exited = code });
|
self.vt.event_queue.push(.{ .exited = code });
|
||||||
self.parent.send(.{ "terminal_view", "output" }) catch {};
|
self.parent.send(.{ "terminal_view", "output" }) catch {};
|
||||||
return tp.exit_normal();
|
return error.InputOutput;
|
||||||
|
},
|
||||||
|
error.SystemResources,
|
||||||
|
error.IsDir,
|
||||||
|
error.OperationAborted,
|
||||||
|
error.BrokenPipe,
|
||||||
|
error.ConnectionResetByPeer,
|
||||||
|
error.ConnectionTimedOut,
|
||||||
|
error.NotOpenForReading,
|
||||||
|
error.SocketNotConnected,
|
||||||
|
error.Canceled,
|
||||||
|
error.AccessDenied,
|
||||||
|
error.ProcessNotFound,
|
||||||
|
error.LockViolation,
|
||||||
|
error.Unexpected,
|
||||||
|
=> {
|
||||||
|
std.log.err("terminal_view: read unexpected: {}", .{e});
|
||||||
|
return error.Unexpected;
|
||||||
},
|
},
|
||||||
else => return tp.exit_error(e, @errorReturnTrace()),
|
|
||||||
};
|
};
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
const code = self.vt.cmd.wait();
|
const code = self.vt.cmd.wait();
|
||||||
self.vt.event_queue.push(.{ .exited = code });
|
self.vt.event_queue.push(.{ .exited = code });
|
||||||
self.parent.send(.{ "terminal_view", "output" }) catch {};
|
self.parent.send(.{ "terminal_view", "output" }) catch {};
|
||||||
return tp.exit_normal();
|
return error.Terminated;
|
||||||
}
|
}
|
||||||
|
|
||||||
const exited = self.vt.processOutput(&self.parser, buf[0..n]) catch |e|
|
defer self.parent.send(.{ "terminal_view", "output" }) catch {};
|
||||||
return tp.exit_error(e, @errorReturnTrace());
|
|
||||||
if (exited) {
|
switch (self.vt.processOutput(&self.parser, buf[0..n]) catch |e| switch (e) {
|
||||||
self.parent.send(.{ "terminal_view", "output" }) catch {};
|
error.WriteFailed,
|
||||||
return tp.exit_normal();
|
error.ReadFailed,
|
||||||
|
error.OutOfMemory,
|
||||||
|
error.Utf8InvalidStartByte,
|
||||||
|
=> {
|
||||||
|
std.log.err("terminal_view: processOutput unexpected: {}", .{e});
|
||||||
|
return error.Unexpected;
|
||||||
|
},
|
||||||
|
}) {
|
||||||
|
.exited => {
|
||||||
|
return error.Terminated;
|
||||||
|
},
|
||||||
|
.running => {},
|
||||||
}
|
}
|
||||||
// Notify parent that new output is available.
|
|
||||||
self.parent.send(.{ "terminal_view", "output" }) catch {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.fd.wait_read() catch |e| return tp.exit_error(e, @errorReturnTrace());
|
self.fd.wait_read() catch |e| switch (e) {
|
||||||
|
error.ThespianFileDescriptorWaitReadFailed => {
|
||||||
|
std.log.err("terminal_view: wait_read unexpected: {}", .{e});
|
||||||
|
return error.Unexpected;
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue