From ad44443bbac3dcf58fd15aa5a1810c8f1631f909 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Tue, 20 Jan 2026 12:48:44 +0100 Subject: [PATCH 1/7] build: update themes to add unfocused tab colors --- build.zig.zon | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.zig.zon b/build.zig.zon index dfc143b..7d3284a 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -22,8 +22,8 @@ .hash = "thespian-0.0.1-owFOjjMiBgCXFa9f0-RKTDgWwYzQp1Mnec_p6hsGXj_G", }, .themes = .{ - .url = "https://github.com/neurocyte/flow-themes/releases/download/master-870b0340c61ff0d14910d0f29be0857aed38e3d2/flow-themes.tar.gz", - .hash = "N-V-__8AANPpIwA9FUVFxIHNwdWgzLqyY0Y6Va1XsbROZMN9", + .url = "https://github.com/neurocyte/flow-themes/releases/download/master-c6c7f18cfb2e3945cd0b71dab24271465074dbc3/flow-themes.tar.gz", + .hash = "N-V-__8AAOKzJACguNxU76WX9M7RIhOYGuLnlasJ1-GDdhqT", }, .fuzzig = .{ .url = "https://github.com/fjebaker/fuzzig/archive/4251fe4230d38e721514394a485db62ee1667ff3.tar.gz", From abe15a973d686cb8aa5c087f7f2501a746b4c4db Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Tue, 20 Jan 2026 13:36:40 +0100 Subject: [PATCH 2/7] refactor: add mainview get_active_view and get_view_count functions --- src/tui/mainview.zig | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/tui/mainview.zig b/src/tui/mainview.zig index f6d4199..d1756d5 100644 --- a/src/tui/mainview.zig +++ b/src/tui/mainview.zig @@ -1590,6 +1590,14 @@ fn store_last_match_text(self: *Self, text: ?[]const u8) void { self.last_match_text = text; } +pub fn get_active_view(self: *const Self) usize { + return self.active_view; +} + +pub fn get_view_count(self: *const Self) usize { + return self.views.widgets.items.len; +} + pub fn get_active_editor(self: *Self) ?*ed.Editor { const active_view = self.views.get_at(self.active_view) orelse return null; const editor = active_view.get("editor") orelse return null; From 18f4d9cef39064c7eeaaa8d89f0d2d98310ebb3d Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Tue, 20 Jan 2026 13:46:49 +0100 Subject: [PATCH 3/7] refactor: add tab bar theme variables for unfocused tabs --- src/tui/status/tabs.zig | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/tui/status/tabs.zig b/src/tui/status/tabs.zig index 5af41a3..f9194e5 100644 --- a/src/tui/status/tabs.zig +++ b/src/tui/status/tabs.zig @@ -65,6 +65,24 @@ const @"style.config" = struct { selected_right_fg: colors = .active_bg, selected_right_bg: colors = .inactive_bg, + unfocused_active_fg: colors = .unfocused_active_fg, + unfocused_active_bg: colors = .unfocused_active_bg, + unfocused_active_left: []const u8 = "🭅", + unfocused_active_left_fg: colors = .unfocused_active_bg, + unfocused_active_left_bg: colors = .unfocused_inactive_bg, + unfocused_active_right: []const u8 = "🭐", + unfocused_active_right_fg: colors = .unfocused_active_bg, + unfocused_active_right_bg: colors = .unfocused_inactive_bg, + + unfocused_inactive_fg: colors = .unfocused_inactive_fg, + unfocused_inactive_bg: colors = .unfocused_inactive_bg, + unfocused_inactive_left: []const u8 = " ", + unfocused_inactive_left_fg: colors = .unfocused_inactive_fg, + unfocused_inactive_left_bg: colors = .unfocused_inactive_bg, + unfocused_inactive_right: []const u8 = " ", + unfocused_inactive_right_fg: colors = .unfocused_inactive_fg, + unfocused_inactive_right_bg: colors = .unfocused_inactive_bg, + file_type_icon: bool = true, include_files: []const u8 = "", @@ -888,6 +906,10 @@ const colors = enum { inactive_fg, selected_bg, selected_fg, + unfocused_active_bg, + unfocused_active_fg, + unfocused_inactive_bg, + unfocused_inactive_fg, Error, Warning, @@ -904,6 +926,10 @@ const colors = enum { .inactive_fg => theme.tab_inactive.fg, .selected_bg => theme.tab_selected.bg, .selected_fg => theme.tab_selected.fg, + .unfocused_active_bg => theme.tab_unfocused_active.bg, + .unfocused_active_fg => theme.tab_unfocused_active.fg, + .unfocused_inactive_bg => theme.tab_unfocused_inactive.bg, + .unfocused_inactive_fg => theme.tab_unfocused_inactive.fg, .Error => theme.editor_error.fg, .Warning => theme.editor_warning.fg, .Information => theme.editor_information.fg, From 95cb63c42a73478f730d3b6bf381b32d0d9bc42e Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Tue, 20 Jan 2026 13:48:06 +0100 Subject: [PATCH 4/7] refactor: render unfocused tabs with style from theme --- src/tui/status/tabs.zig | 76 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 2 deletions(-) diff --git a/src/tui/status/tabs.zig b/src/tui/status/tabs.zig index f9194e5..400f467 100644 --- a/src/tui/status/tabs.zig +++ b/src/tui/status/tabs.zig @@ -610,8 +610,14 @@ const Tab = struct { const mode: Mode = if (btn.hover) .selected else if (active) .active else .inactive; switch (mode) { .selected => self.render_selected(&btn.plane, btn.opts.label, btn.hover, theme, active), - .active => self.render_active(&btn.plane, btn.opts.label, btn.hover, theme), - .inactive => self.render_inactive(&btn.plane, btn.opts.label, btn.hover, theme), + .active => if (self.is_focused()) + self.render_active(&btn.plane, btn.opts.label, btn.hover, theme) + else + self.render_unfocused_active(&btn.plane, btn.opts.label, btn.hover, theme), + .inactive => if (self.is_focused()) + self.render_inactive(&btn.plane, btn.opts.label, btn.hover, theme) + else + self.render_unfocused_inactive(&btn.plane, btn.opts.label, btn.hover, theme), } } return false; @@ -733,6 +739,72 @@ const Tab = struct { plane.home(); } + fn render_unfocused_active(self: *@This(), plane: *Plane, label: []const u8, hover: bool, theme: *const Widget.Theme) void { + plane.set_base_style(theme.editor); + plane.erase(); + plane.home(); + plane.set_style(.{ + .fg = self.tab_style.inactive_fg.from_theme(theme), + .bg = self.tab_style.inactive_bg.from_theme(theme), + }); + plane.fill(" "); + plane.home(); + plane.set_style(.{ + .fg = self.tab_style.active_fg.from_theme(theme), + .bg = self.tab_style.active_bg.from_theme(theme), + }); + plane.fill(" "); + plane.home(); + + plane.set_style(.{ + .fg = self.tab_style.active_left_fg.from_theme(theme), + .bg = self.tab_style.active_left_bg.from_theme(theme), + }); + _ = plane.putstr(self.tab_style.unfocused_active_left) catch {}; + + plane.set_style(.{ + .fg = self.tab_style.unfocused_active_fg.from_theme(theme), + .bg = self.tab_style.active_bg.from_theme(theme), + }); + self.render_content(plane, label, hover, self.tab_style.unfocused_active_fg.from_theme(theme), theme); + + plane.set_style(.{ + .fg = self.tab_style.active_right_fg.from_theme(theme), + .bg = self.tab_style.active_right_bg.from_theme(theme), + }); + _ = plane.putstr(self.tab_style.unfocused_active_right) catch {}; + } + + fn render_unfocused_inactive(self: *@This(), plane: *Plane, label: []const u8, hover: bool, theme: *const Widget.Theme) void { + plane.set_base_style(theme.editor); + plane.erase(); + plane.home(); + plane.set_style(.{ + .fg = self.tab_style.inactive_fg.from_theme(theme), + .bg = self.tab_style.inactive_bg.from_theme(theme), + }); + plane.fill(" "); + plane.home(); + + plane.set_style(.{ + .fg = self.tab_style.inactive_left_fg.from_theme(theme), + .bg = self.tab_style.inactive_left_bg.from_theme(theme), + }); + _ = plane.putstr(self.tab_style.unfocused_inactive_left) catch {}; + + plane.set_style(.{ + .fg = self.tab_style.inactive_fg.from_theme(theme), + .bg = self.tab_style.inactive_bg.from_theme(theme), + }); + self.render_content(plane, label, hover, self.tab_style.unfocused_inactive_fg.from_theme(theme), theme); + + plane.set_style(.{ + .fg = self.tab_style.inactive_right_fg.from_theme(theme), + .bg = self.tab_style.inactive_right_bg.from_theme(theme), + }); + _ = plane.putstr(self.tab_style.unfocused_inactive_right) catch {}; + } + fn render_content(self: *@This(), plane: *Plane, label: []const u8, hover: bool, fg: ?Widget.Theme.Color, theme: *const Widget.Theme) void { const buffer_manager = tui.get_buffer_manager() orelse @panic("tabs no buffer manager"); const buffer_ = buffer_manager.buffer_from_ref(self.buffer_ref); From 6029c705e658b521ebbb78979063eeaaae2193c3 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Tue, 20 Jan 2026 13:48:40 +0100 Subject: [PATCH 5/7] fix: improve active and focused tab state tracking --- src/tui/status/tabs.zig | 72 +++++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 27 deletions(-) diff --git a/src/tui/status/tabs.zig b/src/tui/status/tabs.zig index 400f467..4a7b7ef 100644 --- a/src/tui/status/tabs.zig +++ b/src/tui/status/tabs.zig @@ -104,7 +104,7 @@ pub const TabBar = struct { widget_list_widget: Widget, event_handler: ?EventHandler, tabs: []TabBarTab = &[_]TabBarTab{}, - active_buffer_ref: ?usize = null, + active_focused_buffer_ref: ?usize = null, minimum_tabs_shown: usize, place_next: Placement = .atend, @@ -182,8 +182,6 @@ pub const TabBar = struct { } pub fn receive(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool { - const buffer_manager = tui.get_buffer_manager() orelse @panic("tabs no buffer manager"); - var file_path: []const u8 = undefined; var buffer_ref: usize = undefined; if (try m.match(.{"next_tab"})) { self.select_next_tab(); @@ -199,17 +197,21 @@ pub const TabBar = struct { self.place_next_tab(.before, buffer_ref); } else if (try m.match(.{ "place_next_tab", "atend" })) { self.place_next = .atend; - } else if (try m.match(.{ "E", "open", tp.extract(&file_path), tp.more })) { - self.active_buffer_ref = if (buffer_manager.get_buffer_for_file(file_path)) |buffer| - buffer_manager.buffer_to_ref(buffer) - else - null; + } else if (try m.match(.{ "E", "open", tp.more })) { + self.refresh_active_buffer(); } else if (try m.match(.{ "E", "close" })) { - self.active_buffer_ref = null; + self.refresh_active_buffer(); } return false; } + fn refresh_active_buffer(self: *Self) void { + const mv = tui.mainview() orelse @panic("tabs no main view"); + const buffer_manager = tui.get_buffer_manager() orelse @panic("tabs no buffer manager"); + const buffer = mv.get_active_buffer(); + self.active_focused_buffer_ref = if (buffer) |buf| buffer_manager.buffer_to_ref(buf) else null; + } + fn handle_event(self: *Self, from: tp.pid_ref, m: tp.message) tp.result { if (self.event_handler) |event_handler| try event_handler.send(from, m); if (try m.match(.{ "D", input.event.press, @intFromEnum(input.mouse.BUTTON1), tp.more })) { @@ -257,6 +259,7 @@ pub const TabBar = struct { } fn update_tab_widgets(self: *Self, drag_source: ?*Widget) !void { + const mv = tui.mainview() orelse @panic("tabs no main view"); const buffer_manager = tui.get_buffer_manager() orelse @panic("tabs no buffer manager"); var prev_widget_count: usize = 0; for (self.widget_list.widgets.items) |*split_widgetstate| if (split_widgetstate.widget.dynamic_cast(WidgetList)) |split| { @@ -274,11 +277,10 @@ pub const TabBar = struct { split.deinit(self.widget_list.allocator); }; - var max_view: usize = 0; - for (self.tabs) |tab| max_view = @max(max_view, tab.view orelse 0); + const views = mv.get_view_count(); var widget_count: usize = 0; - for (0..max_view + 1) |view| { + for (0..views) |view| { var first = true; var view_widget_list = try WidgetList.createH(self.allocator, self.widget_list.plane, "split", .dynamic); try self.widget_list.add(view_widget_list.widget()); @@ -295,8 +297,10 @@ pub const TabBar = struct { try view_widget_list.add(tab.widget); widget_count += 1; if (tab.widget.dynamic_cast(Tab.ButtonType)) |btn| { - if (buffer_manager.buffer_from_ref(tab.buffer_ref)) |buffer| + if (buffer_manager.buffer_from_ref(tab.buffer_ref)) |buffer| { try btn.update_label(Tab.name_from_buffer(buffer)); + btn.opts.ctx.view = buffer.get_last_view() orelse 0; + } } } } @@ -402,7 +406,7 @@ pub const TabBar = struct { for (split.widgets.items) |*widget_state| if (widget_state.widget.dynamic_cast(Tab.ButtonType)) |btn| { if (found_active) return btn.opts.ctx.buffer_ref; - if (btn.opts.ctx.buffer_ref == self.active_buffer_ref) + if (btn.opts.ctx.buffer_ref == self.active_focused_buffer_ref) found_active = true; }; return null; @@ -412,7 +416,7 @@ pub const TabBar = struct { var previous: ?usize = null; for (self.widget_list.widgets.items) |*split_widget| if (split_widget.widget.dynamic_cast(WidgetList)) |split| for (split.widgets.items) |*widget_state| if (widget_state.widget.dynamic_cast(Tab.ButtonType)) |btn| { - if (btn.opts.ctx.buffer_ref == self.active_buffer_ref) + if (btn.opts.ctx.buffer_ref == self.active_focused_buffer_ref) return previous; previous = btn.opts.ctx.buffer_ref; }; @@ -433,7 +437,7 @@ pub const TabBar = struct { fn move_tab_next(self: *Self) void { tp.trace(tp.channel.debug, .{"move_tab_next"}); - const this_idx = self.find_buffer_tab(self.active_buffer_ref orelse return) orelse return; + const this_idx = self.find_buffer_tab(self.active_focused_buffer_ref orelse return) orelse return; const other_buffer_ref = self.find_next_tab_buffer() orelse return; const other_idx = self.find_buffer_tab(other_buffer_ref) orelse return; self.move_tab_to(other_idx, this_idx); @@ -441,7 +445,7 @@ pub const TabBar = struct { fn move_tab_previous(self: *Self) void { tp.trace(tp.channel.debug, .{"move_tab_previous"}); - const this_idx = self.find_buffer_tab(self.active_buffer_ref orelse return) orelse return; + const this_idx = self.find_buffer_tab(self.active_focused_buffer_ref orelse return) orelse return; const other_buffer_ref = self.find_previous_tab_buffer() orelse return; const other_idx = self.find_buffer_tab(other_buffer_ref) orelse return; self.move_tab_to(other_idx, this_idx); @@ -460,16 +464,17 @@ pub const TabBar = struct { var src_tab = tabs.orderedRemove(src_idx); src_tab.view = new_view; - const active = src_tab.buffer_ref == self.active_buffer_ref; + const buffer = buffer_manager.buffer_from_ref(src_tab.buffer_ref); + const active = if (buffer) |buf| if (mv.get_editor_for_buffer(buf)) |_| true else false else false; tabs.insert(self.allocator, dst_idx, src_tab) catch @panic("OOM move_tab_to"); - if (new_view != old_view) blk: { - const buffer = buffer_manager.buffer_from_ref(src_tab.buffer_ref) orelse break :blk; - buffer.set_last_view(new_view); - if (mv.get_editor_for_buffer(buffer)) |editor| + if (new_view != old_view) if (buffer) |buf| { + buf.set_last_view(new_view); + if (mv.get_editor_for_buffer(buf)) |editor| editor.close_editor() catch {}; - } + }; + const drag_source, _ = tui.get_drag_source(); self.update_tab_widgets(drag_source) catch {}; if (active) @@ -547,6 +552,7 @@ pub const TabBar = struct { const Tab = struct { tabbar: *TabBar, buffer_ref: usize, + view: usize, tab_style: *const Style, close_pos: ?i32 = null, save_pos: ?i32 = null, @@ -564,7 +570,7 @@ const Tab = struct { const buffer_manager = tui.get_buffer_manager() orelse @panic("tabs no buffer manager"); const buffer = buffer_manager.buffer_from_ref(buffer_ref); return Button.create_widget(Tab, tabbar.allocator, tabbar.widget_list.plane, .{ - .ctx = .{ .tabbar = tabbar, .buffer_ref = buffer_ref, .tab_style = tab_style }, + .ctx = .{ .tabbar = tabbar, .buffer_ref = buffer_ref, .view = if (buffer) |buf| buf.get_last_view() orelse 0 else 0, .tab_style = tab_style }, .label = if (buffer) |buf| name_from_buffer(buf) else "???", .on_click = Tab.on_click, .on_click2 = Tab.on_click2, @@ -595,8 +601,19 @@ const Tab = struct { tp.self_pid().send(.{ "cmd", "close_buffer", .{buffer.get_file_path()} }) catch {}; } + fn is_active(self: *@This()) bool { + const mv = tui.mainview() orelse @panic("tabs no main view"); + const buffer_manager = tui.get_buffer_manager() orelse @panic("tabs no buffer manager"); + const buffer = buffer_manager.buffer_from_ref(self.buffer_ref) orelse return false; + return if (mv.get_editor_for_buffer(buffer)) |_| true else false; + } + + fn is_focused(self: *@This()) bool { + const mv = tui.mainview() orelse @panic("tabs no main view"); + return self.view == mv.get_active_view(); + } + fn render(self: *@This(), btn: *ButtonType, theme: *const Widget.Theme) bool { - const active = self.tabbar.active_buffer_ref == self.buffer_ref; if (btn.drag_pos) |pos| { self.render_dragging(&btn.plane, theme); const anchor: Widget.Pos = btn.drag_anchor orelse .{}; @@ -604,9 +621,10 @@ const Tab = struct { box.y = @intCast(@max(pos.y, anchor.y) - anchor.y); box.x = @intCast(@max(pos.x, anchor.x) - anchor.x); if (tui.top_layer(box.to_layer())) |top_layer| { - self.render_selected(top_layer, btn.opts.label, false, theme, active); + self.render_selected(top_layer, btn.opts.label, false, theme, self.is_active()); } } else { + const active = self.is_active(); const mode: Mode = if (btn.hover) .selected else if (active) .active else .inactive; switch (mode) { .selected => self.render_selected(&btn.plane, btn.opts.label, btn.hover, theme, active), @@ -859,7 +877,7 @@ const Tab = struct { fn layout(self: *@This(), btn: *ButtonType) Widget.Layout { const buffer_manager = tui.get_buffer_manager() orelse @panic("tabs no buffer manager"); const is_dirty = if (buffer_manager.buffer_from_ref(self.buffer_ref)) |buffer| buffer.is_dirty() else false; - const active = self.tabbar.active_buffer_ref == self.buffer_ref; + const active = self.is_active(); const len = btn.plane.egc_chunk_width(btn.opts.label, 0, 1); const len_padding = padding_len(btn.plane, self.tabbar.tab_style, active, is_dirty); return .{ .static = len + len_padding }; From 0992f08a941c7459f70fa787d707e1f27b3c3de4 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Tue, 20 Jan 2026 14:41:38 +0100 Subject: [PATCH 6/7] refactor: clean-up some unused stuff --- src/tui/mainview.zig | 2 +- src/tui/status/tabs.zig | 5 ----- src/tui/tui.zig | 7 +++---- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/tui/mainview.zig b/src/tui/mainview.zig index d1756d5..ff974da 100644 --- a/src/tui/mainview.zig +++ b/src/tui/mainview.zig @@ -1548,7 +1548,7 @@ pub fn location_update(self: *Self, editor: *ed.Editor, m: tp.message) tp.result } } -pub fn location_update_from_editor(self: *Self) void { +fn location_update_from_editor(self: *Self) void { const editor = self.get_active_editor() orelse return; const file_path = editor.file_path orelse return; const ephemeral = if (editor.buffer) |buffer| buffer.is_ephemeral() else false; diff --git a/src/tui/status/tabs.zig b/src/tui/status/tabs.zig index 4a7b7ef..0a8e4a6 100644 --- a/src/tui/status/tabs.zig +++ b/src/tui/status/tabs.zig @@ -916,11 +916,6 @@ const Tab = struct { try cbor.writeValue(writer, self.meta); try cbor.writeValue(writer, self.file_type_name); } - - fn extract_state(self: *@This(), iter: *[]const u8) !void { - _ = self; - _ = iter; - } }; const spacer = struct { diff --git a/src/tui/tui.zig b/src/tui/tui.zig index b579062..8c205c2 100644 --- a/src/tui/tui.zig +++ b/src/tui/tui.zig @@ -2096,13 +2096,12 @@ pub fn render_pointer_vcs(self: *renderer.Plane, vcs_status: u8, selected: bool) } } -pub fn render_file_item( +fn render_file_item( self: *renderer.Plane, file_path_: []const u8, icon: []const u8, color: u24, indicator: []const u8, - indicator_suffix: []const u8, matches_cbor: []const u8, active: bool, selected: bool, @@ -2130,7 +2129,7 @@ pub fn render_file_item( _ = self.print("{s} ", .{file_path_}) catch {}; self.set_style(style_hint); - _ = self.print_aligned_right(0, "{s}{s} ", .{ indicator, indicator_suffix }) catch {}; + _ = self.print_aligned_right(0, "{s} ", .{indicator}) catch {}; var iter = matches_cbor; var index: usize = 0; @@ -2157,7 +2156,7 @@ pub fn render_file_item_cbor(self: *renderer.Plane, file_item_cbor: []const u8, if (!(cbor.matchString(&iter, &indicator) catch false)) indicator = ""; if (!(cbor.matchValue(&iter, cbor.extract_cbor(&matches_cbor)) catch false)) @panic("invalid matches cbor"); - return render_file_item(self, file_path_, icon, color, indicator, &.{}, matches_cbor, active, selected, hover, theme_); + return render_file_item(self, file_path_, icon, color, indicator, matches_cbor, active, selected, hover, theme_); } pub fn render_file_vcs_item( From f34285d2aa0007dc2049f76fb098f23173d15302 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Tue, 20 Jan 2026 14:42:50 +0100 Subject: [PATCH 7/7] fix: properly handle closing editors in unfocused splits --- src/tui/mainview.zig | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/tui/mainview.zig b/src/tui/mainview.zig index ff974da..76f8556 100644 --- a/src/tui/mainview.zig +++ b/src/tui/mainview.zig @@ -1496,7 +1496,8 @@ pub fn handle_editor_event(self: *Self, editor: *ed.Editor, m: tp.message) tp.re if (try m.match(.{ "E", "close" })) { if (!self.closing_project) { - if (self.get_next_mru_buffer_for_view(self.active_view, .non_hidden)) |file_path| + const view = self.get_view_for_editor(editor) orelse return; + if (self.get_next_mru_buffer_for_view(view, .non_hidden)) |file_path| self.show_file_async(file_path) else { if (self.views.widgets.items.len == 1) @@ -1599,8 +1600,13 @@ pub fn get_view_count(self: *const Self) usize { } pub fn get_active_editor(self: *Self) ?*ed.Editor { - const active_view = self.views.get_at(self.active_view) orelse return null; - const editor = active_view.get("editor") orelse return null; + return self.get_editor_for_view(self.active_view); +} + +pub fn get_editor_for_view(self: *Self, view_idx: usize) ?*ed.Editor { + if (view_idx >= self.get_view_count()) return null; + const view = self.views.get_at(view_idx) orelse return null; + const editor = view.get("editor") orelse return null; if (editor.dynamic_cast(ed.EditorWidget)) |p| { return &p.editor; } @@ -1649,6 +1655,16 @@ pub fn get_view_for_file(self: *Self, file_path: []const u8) ?usize { return null; } +pub fn get_view_for_editor(self: *Self, editor: *ed.Editor) ?usize { + for (self.views.widgets.items, 0..) |*view, n| { + const widget = view.widget.get("editor") orelse continue; + if (widget.dynamic_cast(ed.EditorWidget)) |p| + if (&p.editor == editor) + return n; + } + return null; +} + pub fn get_file_for_view(self: *Self, view_: usize) ?[]const u8 { const view = self.views.get_at(view_) orelse return null; const editor = view.get("editor") orelse return null;