Compare commits
8 commits
f68102e448
...
d98a40ab9e
| Author | SHA1 | Date | |
|---|---|---|---|
| d98a40ab9e | |||
| 49d4cda7ef | |||
| 7e7cb511a8 | |||
| 4bba8d9715 | |||
| 885c9682eb | |||
| 8a3cd776e9 | |||
| 424fd3efc3 | |||
| 519d8dd886 |
5 changed files with 104 additions and 19 deletions
|
|
@ -30,8 +30,8 @@
|
|||
.hash = "fuzzig-0.1.1-Ji0xivxIAQBD0g8O_NV_0foqoPf3elsg9Sc3pNfdVH4D",
|
||||
},
|
||||
.vaxis = .{
|
||||
.url = "git+https://github.com/neurocyte/libvaxis?ref=main#855da7eb7e0991b360e1dcb630691465b725c761",
|
||||
.hash = "vaxis-0.5.1-BWNV_OxtCQD40bC4JBVvCa4GjVRU4ESeFmYOUPcsuROG",
|
||||
.url = "git+https://github.com/neurocyte/libvaxis?ref=main#1f16837cc6444f9323ac21a7988860f6a424b9d0",
|
||||
.hash = "vaxis-0.5.1-BWNV_BazCQACrQg5CxqJoXx6A0SusCFlc8Rr-vgePzLr",
|
||||
},
|
||||
.zeit = .{
|
||||
.url = "git+https://github.com/rockorager/zeit?ref=zig-0.15#ed2ca60db118414bda2b12df2039e33bad3b0b88",
|
||||
|
|
|
|||
|
|
@ -40,8 +40,6 @@
|
|||
["ctrl+shift+f", "find_in_files"],
|
||||
["ctrl+shift+l", "toggle_panel"],
|
||||
["alt+shift+p", "open_command_palette"],
|
||||
["ctrl+shift+page_up", "terminal_scroll_up"],
|
||||
["ctrl+shift+page_down", "terminal_scroll_down"],
|
||||
["alt+n", "goto_next_file_or_diagnostic"],
|
||||
["alt+p", "goto_prev_file_or_diagnostic"],
|
||||
["alt+l", "toggle_panel"],
|
||||
|
|
@ -65,8 +63,8 @@
|
|||
["ctrl+shift+tab", "previous_tab"],
|
||||
["ctrl+page_down", "next_tab"],
|
||||
["ctrl+page_up", "previous_tab"],
|
||||
["ctrl+shift+page_down", "move_tab_next"],
|
||||
["ctrl+shift+page_up", "move_tab_previous"],
|
||||
["ctrl+shift+page_down", "move_tab_next_or_scroll_terminal_down"],
|
||||
["ctrl+shift+page_up", "move_tab_previous_or_scroll_terminal_up"],
|
||||
["ctrl+k e", "switch_buffers"],
|
||||
["alt+shift+v", "clipboard_history"],
|
||||
["ctrl+0", "reset_fontsize"],
|
||||
|
|
@ -353,6 +351,7 @@
|
|||
["alt+f9", "overlay_next_widget_style"],
|
||||
["alt+!", "add_task"],
|
||||
["ctrl+j", "toggle_panel"],
|
||||
["ctrl+shift+j", "toggle_maximize_panel"],
|
||||
["ctrl+q", "quit"],
|
||||
["ctrl+w", "close_file"],
|
||||
["ctrl+shift+f", "find_in_files"],
|
||||
|
|
@ -599,11 +598,13 @@
|
|||
["ctrl+8", "focus_split", 7],
|
||||
["ctrl+`", "focus_terminal"],
|
||||
["ctrl+j", "toggle_panel"],
|
||||
["ctrl+shift+page_down", "terminal_scroll_down"],
|
||||
["ctrl+shift+page_up", "terminal_scroll_up"],
|
||||
["ctrl+shift+j", "toggle_maximize_panel"],
|
||||
["ctrl+shift+p", "open_command_palette"],
|
||||
["alt+shift+p", "open_command_palette"],
|
||||
["alt+x", "open_command_palette"],
|
||||
["alt+!", "run_task"],
|
||||
["ctrl+shift+j", "toggle_maximize_panel"],
|
||||
["alt+f9", "panel_next_widget_style"],
|
||||
["ctrl+shift+q", "quit_without_saving"],
|
||||
["ctrl+alt+shift+r", "restart"]
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ const style = struct {
|
|||
\\open_recent_project
|
||||
\\find_in_files
|
||||
\\open_command_palette
|
||||
\\focus_terminal
|
||||
\\run_task
|
||||
\\add_task
|
||||
\\open_config
|
||||
|
|
@ -52,6 +53,7 @@ const style = struct {
|
|||
\\open_recent_project
|
||||
\\find_in_files
|
||||
\\open_command_palette
|
||||
\\focus_terminal
|
||||
\\run_task
|
||||
\\add_task
|
||||
\\open_config
|
||||
|
|
|
|||
|
|
@ -1014,7 +1014,7 @@ const cmds = struct {
|
|||
vt.focus();
|
||||
}
|
||||
}
|
||||
pub const focus_terminal_meta: Meta = .{ .description = "Focus terminal panel" };
|
||||
pub const focus_terminal_meta: Meta = .{ .description = "Terminal" };
|
||||
|
||||
pub fn close_find_in_files_results(self: *Self, _: Ctx) Result {
|
||||
if (self.file_list_type == .find_in_files)
|
||||
|
|
@ -1591,6 +1591,22 @@ const cmds = struct {
|
|||
}
|
||||
pub const move_tab_previous_meta: Meta = .{ .description = "Move tab to previous position" };
|
||||
|
||||
pub fn move_tab_next_or_scroll_terminal_down(self: *Self, _: Ctx) Result {
|
||||
if (self.is_panel_view_showing(terminal_view))
|
||||
try command.executeName("terminal_scroll_down", .{})
|
||||
else
|
||||
_ = try self.widgets_widget.msg(.{"move_tab_next"});
|
||||
}
|
||||
pub const move_tab_next_or_scroll_terminal_down_meta: Meta = .{ .description = "Move tab next or scroll terminal down" };
|
||||
|
||||
pub fn move_tab_previous_or_scroll_terminal_up(self: *Self, _: Ctx) Result {
|
||||
if (self.is_panel_view_showing(terminal_view))
|
||||
try command.executeName("terminal_scroll_up", .{})
|
||||
else
|
||||
_ = try self.widgets_widget.msg(.{"move_tab_previous"});
|
||||
}
|
||||
pub const move_tab_previous_or_scroll_terminal_up_meta: Meta = .{ .description = "Move tab previous or scroll terminal up" };
|
||||
|
||||
pub fn place_next_tab(self: *Self, ctx: Ctx) Result {
|
||||
var pos: enum { before, after } = undefined;
|
||||
var buffer_ref: Buffer.Ref = undefined;
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ pub fn shutdown(allocator: Allocator) void {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn render(self: *Self, _: *const Widget.Theme) bool {
|
||||
pub fn render(self: *Self, theme: *const Widget.Theme) bool {
|
||||
// Drain the vt event queue.
|
||||
while (self.vt.vt.tryEvent()) |event| {
|
||||
switch (event) {
|
||||
|
|
@ -206,9 +206,48 @@ pub fn render(self: *Self, _: *const Widget.Theme) bool {
|
|||
self.vt.title.clearRetainingCapacity();
|
||||
self.vt.title.appendSlice(self.allocator, t) catch {};
|
||||
},
|
||||
.color_change => |cc| {
|
||||
self.vt.app_fg = cc.fg;
|
||||
self.vt.app_bg = cc.bg;
|
||||
self.vt.app_cursor = cc.cursor;
|
||||
},
|
||||
.osc_copy => |text| {
|
||||
// Terminal app wrote to clipboard via OSC 52.
|
||||
// Add to flow clipboard history and forward to system clipboard.
|
||||
const owned = tui.clipboard_allocator().dupe(u8, text) catch break;
|
||||
tui.clipboard_clear_all();
|
||||
tui.clipboard_start_group();
|
||||
tui.clipboard_add_chunk(owned);
|
||||
tui.clipboard_send_to_system() catch {};
|
||||
},
|
||||
.osc_paste_request => {
|
||||
// Terminal app requested clipboard contents via OSC 52.
|
||||
// Assemble from flow clipboard history and respond.
|
||||
if (tui.clipboard_get_history()) |history| {
|
||||
var buf: std.Io.Writer.Allocating = .init(self.allocator);
|
||||
defer buf.deinit();
|
||||
var first = true;
|
||||
for (history) |chunk| {
|
||||
if (first) first = false else buf.writer.writeByte('\n') catch break;
|
||||
buf.writer.writeAll(chunk.text) catch break;
|
||||
}
|
||||
self.vt.vt.respondOsc52Paste(buf.written());
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Update the terminal's fg/bg color cache from the current theme so that
|
||||
// OSC 10/11 colour queries return accurate values.
|
||||
if (theme.editor.fg) |fg| {
|
||||
const c = fg.color;
|
||||
self.vt.vt.fg_color = .{ @truncate(c >> 16), @truncate(c >> 8), @truncate(c) };
|
||||
}
|
||||
if (theme.editor.bg) |bg| {
|
||||
const c = bg.color;
|
||||
self.vt.vt.bg_color = .{ @truncate(c >> 16), @truncate(c >> 8), @truncate(c) };
|
||||
}
|
||||
|
||||
// Blit the terminal's front screen into our vaxis.Window.
|
||||
self.vt.vt.draw(self.allocator, self.plane.window, self.focused) catch |e| {
|
||||
std.log.err("terminal_view: draw failed: {}", .{e});
|
||||
|
|
@ -276,6 +315,10 @@ const Vt = struct {
|
|||
pty_pid: ?tp.pid = null,
|
||||
cwd: std.ArrayListUnmanaged(u8) = .empty,
|
||||
title: std.ArrayListUnmanaged(u8) = .empty,
|
||||
/// App-specified override colours (from OSC 10/11/12). null = use theme.
|
||||
app_fg: ?[3]u8 = null,
|
||||
app_bg: ?[3]u8 = null,
|
||||
app_cursor: ?[3]u8 = null,
|
||||
|
||||
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";
|
||||
|
|
@ -363,17 +406,23 @@ const pty = struct {
|
|||
}
|
||||
|
||||
fn deinit(self: *@This()) void {
|
||||
std.log.debug("terminal: pty actor deinit (pid={?})", .{self.vt.cmd.pid});
|
||||
self.fd.deinit();
|
||||
self.parser.buf.deinit();
|
||||
self.parent.deinit();
|
||||
self.allocator.destroy(self);
|
||||
std.log.debug("terminal: pty destroyed", .{});
|
||||
}
|
||||
|
||||
fn start(self: *@This()) tp.result {
|
||||
errdefer self.deinit();
|
||||
self.fd = tp.file_descriptor.init("pty", self.pty_fd) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
self.fd.wait_read() catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
self.fd = tp.file_descriptor.init("pty", self.pty_fd) catch |e| {
|
||||
std.log.debug("terminal: pty fd init failed: {}", .{e});
|
||||
return tp.exit_error(e, @errorReturnTrace());
|
||||
};
|
||||
self.fd.wait_read() catch |e| {
|
||||
std.log.debug("terminal: pty initial wait_read failed: {}", .{e});
|
||||
return tp.exit_error(e, @errorReturnTrace());
|
||||
};
|
||||
tp.receive(&self.receiver);
|
||||
}
|
||||
|
||||
|
|
@ -382,14 +431,28 @@ const pty = struct {
|
|||
|
||||
if (try m.match(.{ "fd", "pty", "read_ready" })) {
|
||||
self.read_and_process() catch |e| return switch (e) {
|
||||
error.Terminated => tp.exit_normal(),
|
||||
error.InputOutput => tp.exit_normal(),
|
||||
error.SendFailed => tp.exit_normal(),
|
||||
error.Unexpected => tp.exit_normal(),
|
||||
error.Terminated => {
|
||||
std.log.debug("terminal: pty exiting: read loop terminated (process exited)", .{});
|
||||
return tp.exit_normal();
|
||||
},
|
||||
error.InputOutput => {
|
||||
std.log.debug("terminal: pty exiting: EIO on read (process exited)", .{});
|
||||
return tp.exit_normal();
|
||||
},
|
||||
error.SendFailed => {
|
||||
std.log.debug("terminal: pty exiting: send to parent failed", .{});
|
||||
return tp.exit_normal();
|
||||
},
|
||||
error.Unexpected => {
|
||||
std.log.debug("terminal: pty exiting: unexpected error (see preceding log)", .{});
|
||||
return tp.exit_normal();
|
||||
},
|
||||
};
|
||||
} else if (try m.match(.{"quit"})) {
|
||||
std.log.debug("terminal: pty exiting: received quit", .{});
|
||||
return tp.exit_normal();
|
||||
} else {
|
||||
std.log.debug("terminal: pty exiting: unexpected message", .{});
|
||||
return tp.unexpected(m);
|
||||
}
|
||||
}
|
||||
|
|
@ -402,6 +465,7 @@ const pty = struct {
|
|||
error.WouldBlock => break,
|
||||
error.InputOutput => {
|
||||
const code = self.vt.cmd.wait();
|
||||
std.log.debug("terminal: read EIO, process exited with code={d}", .{code});
|
||||
self.vt.event_queue.push(.{ .exited = code });
|
||||
self.parent.send(.{ "terminal_view", "output" }) catch {};
|
||||
return error.InputOutput;
|
||||
|
|
@ -420,12 +484,13 @@ const pty = struct {
|
|||
error.LockViolation,
|
||||
error.Unexpected,
|
||||
=> {
|
||||
std.log.err("terminal_view: read unexpected: {}", .{e});
|
||||
std.log.debug("terminal: read unexpected error: {} (pid={?})", .{ e, self.vt.cmd.pid });
|
||||
return error.Unexpected;
|
||||
},
|
||||
};
|
||||
if (n == 0) {
|
||||
const code = self.vt.cmd.wait();
|
||||
std.log.debug("terminal: read returned 0 bytes (EOF), process exited with code={d}", .{code});
|
||||
self.vt.event_queue.push(.{ .exited = code });
|
||||
self.parent.send(.{ "terminal_view", "output" }) catch {};
|
||||
return error.Terminated;
|
||||
|
|
@ -439,11 +504,12 @@ const pty = struct {
|
|||
error.OutOfMemory,
|
||||
error.Utf8InvalidStartByte,
|
||||
=> {
|
||||
std.log.err("terminal_view: processOutput unexpected: {}", .{e});
|
||||
std.log.debug("terminal: processOutput error: {} (pid={?})", .{ e, self.vt.cmd.pid });
|
||||
return error.Unexpected;
|
||||
},
|
||||
}) {
|
||||
.exited => {
|
||||
std.log.debug("terminal: processOutput returned .exited (process EOF)", .{});
|
||||
return error.Terminated;
|
||||
},
|
||||
.running => {},
|
||||
|
|
@ -452,7 +518,7 @@ const pty = struct {
|
|||
|
||||
self.fd.wait_read() catch |e| switch (e) {
|
||||
error.ThespianFileDescriptorWaitReadFailed => {
|
||||
std.log.err("terminal_view: wait_read unexpected: {}", .{e});
|
||||
std.log.debug("terminal: wait_read failed: {} (pid={?})", .{ e, self.vt.cmd.pid });
|
||||
return error.Unexpected;
|
||||
},
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue