diff --git a/src/tui/editor.zig b/src/tui/editor.zig index 1c7f439..cd4c823 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -6470,6 +6470,10 @@ pub const Editor = struct { state.work_root = try state.work_root.delete_range(sel, buf_a_, null, self.metrics); } + fn is_filter_running(self: *const Self) bool { + return self.filter_ != null; + } + fn filter_stdout(self: *Self, bytes: []const u8) !void { const state = if (self.filter_) |*s| s else return error.Stop; errdefer self.filter_deinit(); @@ -6877,13 +6881,13 @@ pub const EditorWidget = struct { try self.mouse_drag_event(event, @enumFromInt(btn), y, x, ypx, xpx); } else if (try m.match(.{ "scroll_to", tp.extract(&pos) })) { self.editor.scroll_to(pos); - } else if (try m.match(.{ "filter", "stdout", tp.extract(&bytes) })) { + } else if (self.editor.is_filter_running() and try m.match(.{ "filter", "stdout", tp.extract(&bytes) })) { self.editor.filter_stdout(bytes) catch {}; - } else if (try m.match(.{ "filter", "stderr", tp.extract(&bytes) })) { + } else if (self.editor.is_filter_running() and try m.match(.{ "filter", "stderr", tp.extract(&bytes) })) { try self.editor.filter_error(bytes); - } else if (try m.match(.{ "filter", "term", "error.FileNotFound", 1 })) { + } else if (self.editor.is_filter_running() and try m.match(.{ "filter", "term", "error.FileNotFound", 1 })) { try self.editor.filter_not_found(); - } else if (try m.match(.{ "filter", "term", tp.more })) { + } else if (self.editor.is_filter_running() and try m.match(.{ "filter", "term", tp.more })) { try self.editor.filter_done(); } else if (try m.match(.{ "A", tp.more })) { self.editor.add_match(m) catch {}; diff --git a/src/tui/mainview.zig b/src/tui/mainview.zig index d632f54..4360507 100644 --- a/src/tui/mainview.zig +++ b/src/tui/mainview.zig @@ -175,7 +175,7 @@ pub fn receive(self: *Self, from_: tp.pid_ref, m: tp.message) error{Exit}!bool { return true; } else if (try m.match(.{ "hover", tp.extract(&path), tp.string, tp.extract(&lines), tp.extract(&begin_line), tp.extract(&begin_pos), tp.extract(&end_line), tp.extract(&end_pos) })) { try self.set_info_content(lines, .replace); - if (self.get_active_editor()) |editor| + if (self.get_editor_for_file(path)) |editor| editor.add_hover_highlight(.{ .begin = .{ .row = begin_line, .col = begin_pos }, .end = .{ .row = end_line, .col = end_pos }, @@ -755,7 +755,7 @@ const cmds = struct { const buffer = self.buffer_manager.get_buffer_for_file(file_path) orelse return; - if (self.get_active_editor()) |editor| blk: { + if (self.get_editor_for_file(file_path)) |editor| blk: { const editor_buffer = editor.buffer orelse break :blk; if (buffer == editor_buffer) { try editor.save_file(.{}); @@ -827,7 +827,7 @@ const cmds = struct { const buffer = self.buffer_manager.get_buffer_for_file(file_path) orelse return; if (buffer.is_dirty()) return tp.exit("unsaved changes"); - if (self.get_active_editor()) |editor| if (editor.buffer == buffer) + if (self.get_editor_for_buffer(buffer)) |editor| editor.close_file(.{}) catch |e| return e; self.buffer_manager.delete_buffer(buffer); const logger = log.logger("buffer"); @@ -844,10 +844,10 @@ const cmds = struct { const buffer = self.buffer_manager.get_buffer_for_file(file_path) orelse return; if (buffer.is_dirty()) return tp.exit("unsaved changes"); - if (self.get_active_editor()) |editor| if (editor.buffer == buffer) { + if (self.get_editor_for_buffer(buffer)) |editor| { editor.close_file(.{}) catch |e| return e; return; - }; + } _ = self.buffer_manager.close_buffer(buffer); tui.need_render(); } @@ -1022,11 +1022,11 @@ const cmds = struct { tp.extract(&sel.end.col), })) return error.InvalidAddDiagnosticArgument; file_path = project_manager.normalize_file_path(file_path); - if (self.get_active_editor()) |editor| if (std.mem.eql(u8, file_path, editor.file_path orelse "")) { + if (self.get_editor_for_file(file_path)) |editor| { try editor.add_diagnostic(file_path, source, code, message, severity, sel); if (!tui.config().show_local_diagnostics_in_panel) return; - }; + } try self.add_find_in_files_result( .diagnostics, file_path, @@ -1054,7 +1054,7 @@ const cmds = struct { tp.more, })) return error.InvalidAddDiagnosticArgument; file_path = project_manager.normalize_file_path(file_path); - if (self.get_active_editor()) |editor| if (std.mem.eql(u8, file_path, editor.file_path orelse "")) + if (self.get_editor_for_file(file_path)) |editor| try editor.add_completion(row, col, is_incomplete, ctx.args); } pub const add_completion_meta: Meta = .{ @@ -1169,8 +1169,6 @@ const cmds = struct { }; pub fn rename_symbol_item(self: *Self, ctx: Ctx) Result { - const editor = self.get_active_editor() orelse return; - const primary_cursor = editor.get_primary().cursor; var iter = ctx.args.buf; var len = try cbor.decodeArrayHeader(&iter); var first = true; @@ -1189,6 +1187,9 @@ const cmds = struct { if (!try cbor.matchString(&iter, &line_text)) return error.MissingArgument; file_path = project_manager.normalize_file_path(file_path); + const editor = self.get_editor_for_file(file_path) orelse continue; + const primary_cursor = editor.get_primary().cursor; + if (std.mem.eql(u8, file_path, editor.file_path orelse "")) { if (len == 1 and sel.begin.row == 0 and sel.begin.col == 0 and sel.end.row > 0) //probably a full file edit return editor.add_cursors_from_content_diff(new_text); @@ -1206,8 +1207,8 @@ const cmds = struct { .Information, ); } + try editor.set_primary_selection_from_cursor(primary_cursor); } - try editor.set_primary_selection_from_cursor(primary_cursor); } pub const rename_symbol_item_meta: Meta = .{ .arguments = &.{.array} }; pub const rename_symbol_item_elem_meta: Meta = .{ .arguments = &.{ .string, .integer, .integer, .integer, .integer, .string } }; @@ -1216,7 +1217,7 @@ const cmds = struct { var file_path: []const u8 = undefined; if (!try ctx.args.match(.{tp.extract(&file_path)})) return error.InvalidClearDiagnosticsArgument; file_path = project_manager.normalize_file_path(file_path); - if (self.get_active_editor()) |editor| if (std.mem.eql(u8, file_path, editor.file_path orelse "")) + if (self.get_editor_for_file(file_path)) |editor| editor.clear_diagnostics(); self.clear_find_in_files_results(.diagnostics); @@ -1376,10 +1377,10 @@ const cmds = struct { if (!try ctx.args.match(.{tp.extract(&buffer_ref)})) return error.InvalidShellOutputCompleteArgument; const buffer = self.buffer_manager.buffer_from_ref(buffer_ref) orelse return; - if (self.get_active_editor()) |editor| if (editor.buffer) |eb| if (eb == buffer) { + if (self.get_editor_for_buffer(buffer)) |editor| { editor.forced_mark_clean(.{}) catch {}; return; - }; + } buffer.mark_clean(); tui.need_render(); } @@ -1473,8 +1474,7 @@ fn no_lsp_error() void { logger.print("no LSP currently in use", .{}); } -pub fn handle_editor_event(self: *Self, _: tp.pid_ref, m: tp.message) tp.result { - const editor = self.get_active_editor() orelse return; +pub fn handle_editor_event(self: *Self, editor: *ed.Editor, m: tp.message) tp.result { var sel: ed.Selection = undefined; if (try m.match(.{ "E", "location", tp.more })) @@ -1579,6 +1579,16 @@ pub fn get_active_editor(self: *Self) ?*ed.Editor { return null; } +const ForEachEditorFunc = fn (*ed.Editor) void; + +pub fn foreach_editor(self: *Self, func: ForEachEditorFunc) void { + for (self.views.widgets.items) |*view| { + const editor = view.widget.get("editor") orelse continue; + if (editor.dynamic_cast(ed.EditorWidget)) |p| + func(&p.editor); + } +} + pub fn get_editor_for_buffer(self: *Self, buffer: *Buffer) ?*ed.Editor { for (self.views.widgets.items) |*view| { const editor = view.widget.get("editor") orelse continue; @@ -1698,11 +1708,29 @@ fn create_editor(self: *Self) !void { const editor = editor_widget.get("editor") orelse @panic("mainview editor not found"); if (self.top_bar) |*bar| editor.subscribe(EventHandler.to_unowned(bar)) catch @panic("subscribe unsupported"); if (self.bottom_bar) |*bar| editor.subscribe(EventHandler.to_unowned(bar)) catch @panic("subscribe unsupported"); - editor.subscribe(EventHandler.bind(self, handle_editor_event)) catch @panic("subscribe unsupported"); + const event_handler = try self.allocator.create(EditorEventHandler); + event_handler.* = .{ + .mainview = self, + .editor_widget = editor.dynamic_cast(ed.EditorWidget) orelse @panic("dynamic_cast(ed.EditorWidget) failed"), + }; + editor.subscribe(EventHandler.to_owned(event_handler)) catch @panic("subscribe unsupported"); try self.replace_active_view(editor_widget); tui.resize(); } +const EditorEventHandler = struct { + mainview: *Self, + editor_widget: *ed.EditorWidget, + + pub fn deinit(self: *@This()) void { + self.mainview.allocator.destroy(self); + } + + pub fn receive(self: *@This(), _: tp.pid_ref, m: tp.message) tp.result { + return handle_editor_event(self.mainview, &self.editor_widget.editor, m); + } +}; + fn toggle_logview_async(_: *Self) void { tp.self_pid().send(.{ "cmd", "toggle_logview" }) catch return; } @@ -2000,6 +2028,5 @@ pub fn vcs_content_update(self: *Self, m: tp.message) void { pub fn trigger_characters_update(self: *Self, m: tp.message) void { self.lsp_info.add_from_event(m.buf) catch return; - const editor = self.get_active_editor() orelse return; - editor.update_completion_triggers(); + self.foreach_editor(ed.Editor.update_completion_triggers); } diff --git a/src/tui/mode/overlay/buffer_palette.zig b/src/tui/mode/overlay/buffer_palette.zig index f561c0b..178eaeb 100644 --- a/src/tui/mode/overlay/buffer_palette.zig +++ b/src/tui/mode/overlay/buffer_palette.zig @@ -63,7 +63,11 @@ fn select(menu: **Type.MenuType, button: *Type.ButtonType, _: Type.Pos) void { var iter = button.opts.label; if (!(cbor.matchString(&iter, &file_path) catch false)) return; tp.self_pid().send(.{ "cmd", "exit_overlay_mode" }) catch |e| menu.*.opts.ctx.logger.err(module_name, e); - tp.self_pid().send(.{ "cmd", "navigate", .{ .file = file_path } }) catch |e| menu.*.opts.ctx.logger.err(module_name, e); + const cmd_ = switch (menu.*.opts.ctx.activate) { + .normal => "navigate", + .alternate => "navigate_split_vertical", + }; + tp.self_pid().send(.{ "cmd", cmd_, .{ .file = file_path } }) catch |e| menu.*.opts.ctx.logger.err(module_name, e); } pub fn delete_item(menu: *Type.MenuType, button: *Type.ButtonType) bool { diff --git a/src/tui/mode/overlay/palette.zig b/src/tui/mode/overlay/palette.zig index 20c91d6..1b4193b 100644 --- a/src/tui/mode/overlay/palette.zig +++ b/src/tui/mode/overlay/palette.zig @@ -29,6 +29,11 @@ pub const Placement = enum { primary_cursor, }; +pub const ActivateMode = enum { + normal, + alternate, +}; + pub fn Create(options: type) type { return struct { allocator: std.mem.Allocator, @@ -44,6 +49,7 @@ pub fn Create(options: type) type { initial_selected: ?usize = null, placement: Placement, quick_activate_enabled: bool = true, + activate: ActivateMode = .normal, items: usize = 0, view_rows: usize, @@ -580,6 +586,12 @@ pub fn Create(options: type) type { } pub const palette_menu_activate_meta: Meta = .{}; + pub fn palette_menu_activate_alternate(self: *Self, _: Ctx) Result { + self.activate = .alternate; + self.menu.activate_selected(); + } + pub const palette_menu_activate_alternate_meta: Meta = .{}; + pub fn palette_menu_activate_quick(self: *Self, _: Ctx) Result { if (!self.quick_activate_enabled) return; if (self.menu.selected orelse 0 > 0) self.menu.activate_selected(); diff --git a/src/tui/tui.zig b/src/tui/tui.zig index 49fdcac..2061852 100644 --- a/src/tui/tui.zig +++ b/src/tui/tui.zig @@ -1659,7 +1659,6 @@ const cmds = struct { self.rdr_.request_mouse_cursor_text(true); } pub const disable_jump_mode_meta: Meta = .{}; - }; pub const MiniMode = struct { @@ -2501,4 +2500,3 @@ pub fn jump_mode() bool { const self = current(); return self.jump_mode_; } -