From 367c532596cce7f6a79dd4296c08b0b2d3875646 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Tue, 24 Feb 2026 19:12:59 +0100 Subject: [PATCH] refactor(terminal): route input to terminal_view when it is focused --- src/tui/mainview.zig | 8 ++++++++ src/tui/terminal_view.zig | 36 ++++++++++++++++++++++++++++++++++++ src/tui/tui.zig | 13 +++++++++++++ 3 files changed, 57 insertions(+) diff --git a/src/tui/mainview.zig b/src/tui/mainview.zig index e611785..e4f7b94 100644 --- a/src/tui/mainview.zig +++ b/src/tui/mainview.zig @@ -981,6 +981,14 @@ const cmds = struct { } pub const open_terminal_meta: Meta = .{ .description = "Open terminal", .arguments = &.{.string} }; + pub fn focus_terminal(self: *Self, _: Ctx) Result { + if (self.get_panel_view(terminal_view)) |vt| + vt.focus() + else + try self.toggle_panel_view(terminal_view, .enable); + } + pub const focus_terminal_meta: Meta = .{ .description = "Focus terminal panel" }; + pub fn close_find_in_files_results(self: *Self, _: Ctx) Result { if (self.file_list_type == .find_in_files) try self.toggle_panel_view(filelist_view, .disable); diff --git a/src/tui/terminal_view.zig b/src/tui/terminal_view.zig index 73150f4..d16633e 100644 --- a/src/tui/terminal_view.zig +++ b/src/tui/terminal_view.zig @@ -12,6 +12,7 @@ const Widget = @import("Widget.zig"); const WidgetList = @import("WidgetList.zig"); const MessageFilter = @import("MessageFilter.zig"); const tui = @import("tui.zig"); +const input = @import("input"); pub const name = @typeName(Self); @@ -30,6 +31,7 @@ vt: Terminal, env: std.process.EnvMap, write_buf: [4096]u8, poll_timer: ?tp.Cancellable = null, +focused: bool = false, pub fn create(allocator: Allocator, parent: Plane) !Widget { return create_with_args(allocator, parent, .{}); @@ -121,7 +123,41 @@ pub fn create_with_args(allocator: Allocator, parent: Plane, ctx: command.Contex return container.widget(); } +pub fn receive(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool { + if (!self.focused) return false; + var evtype: u8 = 0; + var keycode: u21 = 0; + var shifted: u21 = 0; + var text: []const u8 = ""; + var mods: u8 = 0; + if (!(try m.match(.{ "I", tp.extract(&evtype), tp.extract(&keycode), tp.extract(&shifted), tp.extract(&text), tp.extract(&mods) }))) + return false; + // Only forward press and repeat events; ignore releases. + if (evtype != input.event.press and evtype != input.event.repeat) return true; + const key: vaxis.Key = .{ + .codepoint = keycode, + .shifted_codepoint = if (shifted != keycode) shifted else null, + .mods = @bitCast(mods), + .text = if (text.len > 0) text else null, + }; + self.vt.update(.{ .key_press = key }) catch |e| + std.log.err("terminal_view: input failed: {}", .{e}); + tui.need_render(@src()); + return true; +} + +pub fn focus(self: *Self) void { + self.focused = true; + tui.set_keyboard_focus(Widget.to(self)); +} + +pub fn unfocus(self: *Self) void { + self.focused = false; + tui.release_keyboard_focus(Widget.to(self)); +} + pub fn deinit(self: *Self, allocator: Allocator) void { + if (self.focused) tui.release_keyboard_focus(Widget.to(self)); tui.message_filters().remove_ptr(self); if (self.poll_timer) |*t| { t.cancel() catch {}; diff --git a/src/tui/tui.zig b/src/tui/tui.zig index 574b714..756ccfc 100644 --- a/src/tui/tui.zig +++ b/src/tui/tui.zig @@ -842,6 +842,19 @@ pub fn set_focus_by_mouse_event() FocusAction { return mv.focus_view_by_widget(self.hover_focus orelse return .notfound); } +pub fn set_keyboard_focus(w: Widget) void { + const self = current(); + if (self.keyboard_focus) |prev| prev.unfocus(); + self.keyboard_focus = w; +} + +pub fn release_keyboard_focus(w: Widget) void { + const self = current(); + if (self.keyboard_focus) |cur| if (cur.ptr == w.ptr) { + self.keyboard_focus = null; + }; +} + fn send_widgets(self: *Self, from: tp.pid_ref, m: tp.message) error{Exit}!bool { const frame = tracy.initZone(@src(), .{ .name = "tui widgets" }); defer frame.deinit();