From 5724739b519761e8a7898fd174c08ab020de37cf Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Mon, 4 Aug 2025 09:23:52 +0200 Subject: [PATCH 1/8] fix: don't log blank lines output by git to stderr --- src/git.zig | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/git.zig b/src/git.zig index 714ba86..1bf696d 100644 --- a/src/git.zig +++ b/src/git.zig @@ -168,7 +168,8 @@ pub fn status(context_: usize) Error!void { }.result, struct { fn result(_: usize, _: tp.pid_ref, output: []const u8) void { var it = std.mem.splitScalar(u8, output, '\n'); - while (it.next()) |line| std.log.err("{s}: {s}", .{ module_name, line }); + while (it.next()) |line| if (line.len > 0) + std.log.err("{s}: {s}", .{ module_name, line }); } }.result, exit_null(tag)); } @@ -183,7 +184,8 @@ fn git_line_output(context_: usize, comptime tag: []const u8, cmd: anytype) Erro }.result, struct { fn result(_: usize, _: tp.pid_ref, output: []const u8) void { var it = std.mem.splitScalar(u8, output, '\n'); - while (it.next()) |line| std.log.err("{s}: {s}", .{ module_name, line }); + while (it.next()) |line| if (line.len > 0) + std.log.err("{s}: {s}", .{ module_name, line }); } }.result, exit_null(tag)); } From 410a6aadce941f0547339ef334b2c695dc060d87 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Mon, 4 Aug 2025 09:47:24 +0200 Subject: [PATCH 2/8] fix: branch widget: don't call git status if there is no git workspace --- src/tui/status/branch.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tui/status/branch.zig b/src/tui/status/branch.zig index 3ad6457..940699d 100644 --- a/src/tui/status/branch.zig +++ b/src/tui/status/branch.zig @@ -66,8 +66,8 @@ fn on_click(self: *Self, _: *Button.State(Self)) void { command.executeName("show_git_status", .{}) catch {}; } -fn refresh_git_status(_: *Self) void { - git.status(0) catch {}; +fn refresh_git_status(self: *Self) void { + if (self.workspace_path) |_| git.status(0) catch {}; } pub fn receive(self: *Self, _: *Button.State(Self), _: tp.pid_ref, m: tp.message) error{Exit}!bool { From d2c9c558f0ee9009e24f1f61134b1e034479170f Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Mon, 4 Aug 2025 10:40:00 +0200 Subject: [PATCH 3/8] fix: don't call hover_at_abs unless we have a mouse event --- src/tui/editor.zig | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/tui/editor.zig b/src/tui/editor.zig index e432ab8..1ddd635 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -6043,6 +6043,7 @@ pub const EditorWidget = struct { hover_timer: ?tp.Cancellable = null, hover_x: c_int = -1, hover_y: c_int = -1, + hover_mouse_event: bool = false, const Self = @This(); const Commands = command.Collection(Editor); @@ -6109,8 +6110,10 @@ pub const EditorWidget = struct { const hover_y, const hover_x = self.editor.plane.abs_yx_to_rel(y, x); if (hover_y != self.hover_y or hover_x != self.hover_x) { self.hover_y, self.hover_x = .{ hover_y, hover_x }; - if (self.editor.jump_mode) + if (self.editor.jump_mode) { self.update_hover_timer(.init); + self.hover_mouse_event = true; + } } } else if (try m.match(.{ "B", tp.extract(&event), tp.extract(&btn), tp.any, tp.extract(&x), tp.extract(&y), tp.extract(&xpx), tp.extract(&ypx) })) { try self.mouse_click_event(event, @enumFromInt(btn), y, x, ypx, xpx); @@ -6138,7 +6141,7 @@ pub const EditorWidget = struct { } } else if (try m.match(.{"HOVER"})) { self.update_hover_timer(.fired); - if (self.hover_y >= 0 and self.hover_x >= 0) + if (self.hover_y >= 0 and self.hover_x >= 0 and self.hover_mouse_event) try self.editor.hover_at_abs(@intCast(self.hover_y), @intCast(self.hover_x)); } else if (try m.match(.{ "whitespace_mode", tp.extract(&bytes) })) { self.editor.render_whitespace = Editor.from_whitespace_mode(bytes); @@ -6155,6 +6158,7 @@ pub const EditorWidget = struct { self.hover_timer = null; } if (event == .init) { + self.hover_mouse_event = false; const delay_us: u64 = std.time.us_per_ms * 100; self.hover_timer = tp.self_pid().delay_send_cancellable(self.editor.allocator, "editor.hover_timer", delay_us, .{"HOVER"}) catch null; } From 032eb30c45491c063ee3ac1c7de0ddff8612c620 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Mon, 4 Aug 2025 10:53:46 +0200 Subject: [PATCH 4/8] fix: bump hover time to 500ms --- src/tui/editor.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tui/editor.zig b/src/tui/editor.zig index 1ddd635..9fa8948 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -6159,7 +6159,7 @@ pub const EditorWidget = struct { } if (event == .init) { self.hover_mouse_event = false; - const delay_us: u64 = std.time.us_per_ms * 100; + const delay_us: u64 = std.time.us_per_ms * 500; self.hover_timer = tp.self_pid().delay_send_cancellable(self.editor.allocator, "editor.hover_timer", delay_us, .{"HOVER"}) catch null; } } From dc69e8a45624aac530a20d6c48b7f3f91a400d33 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Mon, 4 Aug 2025 10:55:33 +0200 Subject: [PATCH 5/8] feat: make hover_time configurable --- src/config.zig | 1 + src/tui/editor.zig | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/config.zig b/src/config.zig index 7436e84..f2a65e6 100644 --- a/src/config.zig +++ b/src/config.zig @@ -17,6 +17,7 @@ whitespace_mode: []const u8 = "none", inline_diagnostics: bool = true, animation_min_lag: usize = 0, //milliseconds animation_max_lag: usize = 50, //milliseconds +hover_time_ms: usize = 500, //milliseconds enable_format_on_save: bool = false, restore_last_cursor_position: bool = true, follow_cursor_on_buffer_switch: bool = false, //scroll cursor into view on buffer switch diff --git a/src/tui/editor.zig b/src/tui/editor.zig index 9fa8948..f6943c7 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -6159,7 +6159,7 @@ pub const EditorWidget = struct { } if (event == .init) { self.hover_mouse_event = false; - const delay_us: u64 = std.time.us_per_ms * 500; + const delay_us: u64 = std.time.us_per_ms * tui.config().hover_time_ms; self.hover_timer = tp.self_pid().delay_send_cancellable(self.editor.allocator, "editor.hover_timer", delay_us, .{"HOVER"}) catch null; } } From f0b079b43bdf2bc28b2c3884085a1875e99c6a0b Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Mon, 4 Aug 2025 19:57:18 +0200 Subject: [PATCH 6/8] fix: regression in emacs mode fallback handling --- src/keybind/builtin/emacs.json | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/keybind/builtin/emacs.json b/src/keybind/builtin/emacs.json index b2a9c71..661a77d 100644 --- a/src/keybind/builtin/emacs.json +++ b/src/keybind/builtin/emacs.json @@ -1,5 +1,5 @@ { - "project": { + "normal": { "press": [ ["f4", "toggle_input_mode"], ["ctrl+0", "reset_fontsize"], @@ -7,17 +7,11 @@ ["ctrl+-", "adjust_fontsize", -1.0], ["ctrl+r", "find_file"], ["ctrl+h ctrl+a", "open_help"], - ["ctrl+x ctrl+f", "open_file"], - ["ctrl+x b", "open_recent"], ["ctrl+c ctrl+o", "open_recent_project"], ["ctrl+c g", "find_in_files"], ["alt+x", "open_command_palette"], - ["ctrl+x ctrl+c", "quit"] - ] - }, - "normal": { - "inherit": "project", - "press": [ + ["ctrl+x ctrl+c", "quit"], + ["ctrl+g", "cancel"], ["ctrl+_", "undo"], ["\u001f", "undo"], @@ -115,9 +109,21 @@ }, "home": { "on_match_failure": "ignore", - "inherit": "project", "press": [ - ["f", "change_fontface"] + ["f", "change_fontface"], + ["f4", "toggle_input_mode"], + ["ctrl+0", "reset_fontsize"], + ["ctrl+=", "adjust_fontsize", 1.0], + ["ctrl+-", "adjust_fontsize", -1.0], + ["ctrl+r", "find_file"], + ["ctrl+h ctrl+a", "open_help"], + ["ctrl+x ctrl+f", "open_file"], + ["ctrl+x ctrl+r", "open_recent"], + ["ctrl+x b", "switch_buffers"], + ["ctrl+c ctrl+o", "open_recent_project"], + ["ctrl+c g", "find_in_files"], + ["alt+x", "open_command_palette"], + ["ctrl+x ctrl+c", "quit"] ] } } From 4ee3dd4bba3763fc17d309054a67138ac8a33df1 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Mon, 4 Aug 2025 20:44:19 +0200 Subject: [PATCH 7/8] feat: allow open_file to open directories too Also, add the full project path to the path entry box. --- src/tui/mode/mini/open_file.zig | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/tui/mode/mini/open_file.zig b/src/tui/mode/mini/open_file.zig index de60c07..3eeb4b6 100644 --- a/src/tui/mode/mini/open_file.zig +++ b/src/tui/mode/mini/open_file.zig @@ -2,6 +2,7 @@ const std = @import("std"); const tp = @import("thespian"); const root = @import("root"); const command = @import("command"); +const project_manager = @import("project_manager"); const tui = @import("../../tui.zig"); @@ -10,6 +11,11 @@ pub const Type = @import("file_browser.zig").Create(@This()); pub const create = Type.create; pub fn load_entries(self: *Type) error{ Exit, OutOfMemory }!void { + var project_name_buf: [512]u8 = undefined; + const project_path = tp.env.get().str("project"); + const project_name = project_manager.abbreviate_home(&project_name_buf, project_path); + try self.file_path.appendSlice(project_name); + try self.file_path.append(std.fs.path.sep); const editor = tui.get_active_editor() orelse return; if (editor.file_path) |old_path| if (std.mem.lastIndexOf(u8, old_path, "/")) |pos| @@ -28,8 +34,15 @@ pub fn name(_: *Type) []const u8 { } pub fn select(self: *Type) void { - if (root.is_directory(self.file_path.items)) return; - if (self.file_path.items.len > 0) - tp.self_pid().send(.{ "cmd", "navigate", .{ .file = self.file_path.items } }) catch {}; + var buf = std.ArrayList(u8).init(self.allocator); + defer buf.deinit(); + const file_path = project_manager.expand_home(&buf, self.file_path.items); + if (root.is_directory(file_path)) { + tp.self_pid().send(.{ "cmd", "exit_overlay_mode" }) catch return; + tp.self_pid().send(.{ "cmd", "change_project", .{file_path} }) catch {}; + return; + } + if (file_path.len > 0) + tp.self_pid().send(.{ "cmd", "navigate", .{ .file = file_path } }) catch {}; command.executeName("exit_mini_mode", .{}) catch {}; } From a9380e0395bfa934abc6563775724760096566f1 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Mon, 4 Aug 2025 20:53:35 +0200 Subject: [PATCH 8/8] feat: make change_project call open_recent instead of jumping to last file --- src/tui/mainview.zig | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/tui/mainview.zig b/src/tui/mainview.zig index f32b90a..b0c2c03 100644 --- a/src/tui/mainview.zig +++ b/src/tui/mainview.zig @@ -337,8 +337,7 @@ const cmds = struct { tui.rdr().set_terminal_working_directory(project); if (self.top_bar) |bar| _ = try bar.msg(.{ "PRJ", "open" }); if (self.bottom_bar) |bar| _ = try bar.msg(.{ "PRJ", "open" }); - if (try project_manager.request_most_recent_file(self.allocator)) |file_path| - self.show_file_async_and_free(file_path); + tp.self_pid().send(.{ "cmd", "open_recent" }) catch return; } pub const change_project_meta: Meta = .{ .arguments = &.{.string} }; @@ -1224,11 +1223,6 @@ fn toggle_inputview_async(_: *Self) void { tp.self_pid().send(.{ "cmd", "toggle_inputview" }) catch return; } -fn show_file_async_and_free(self: *Self, file_path: []const u8) void { - defer self.allocator.free(file_path); - self.show_file_async(file_path); -} - fn show_file_async(_: *Self, file_path: []const u8) void { tp.self_pid().send(.{ "cmd", "navigate", .{ .file = file_path } }) catch return; }