From 87d15eb1cdd1eeda21e81eade04b6db1d2fae525 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Sat, 6 Dec 2025 20:48:35 +0100 Subject: [PATCH 1/8] feat: add store_session_and_quit command --- src/tui/mainview.zig | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/tui/mainview.zig b/src/tui/mainview.zig index 0147369..5b057a6 100644 --- a/src/tui/mainview.zig +++ b/src/tui/mainview.zig @@ -355,6 +355,12 @@ const cmds = struct { } pub const quit_without_saving_meta: Meta = .{ .description = "Quit without saving" }; + pub fn store_session_and_quit(self: *Self, _: Ctx) Result { + try self.write_restore_info(); + try tp.self_pid().send("quit"); + } + pub const store_session_and_quit_meta: Meta = .{ .description = "Save session and quit" }; + pub fn open_project_cwd(self: *Self, _: Ctx) Result { if (try project_manager.open(".")) |state| try self.restore_state(state); From 7b9f3bf0c55193a977195ed5a970d946101c5f09 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Sat, 6 Dec 2025 21:10:30 +0100 Subject: [PATCH 2/8] fix: switch to stored project directory when restoring a session --- src/tui/mainview.zig | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/tui/mainview.zig b/src/tui/mainview.zig index 5b057a6..58f4046 100644 --- a/src/tui/mainview.zig +++ b/src/tui/mainview.zig @@ -795,9 +795,6 @@ const cmds = struct { pub const close_buffer_meta: Meta = .{ .arguments = &.{.string} }; pub fn restore_session(self: *Self, _: Ctx) Result { - if (tp.env.get().str("project").len == 0) { - try open_project_cwd(self, .{}); - } try self.create_editor(); try self.read_restore_info(); tui.need_render(); @@ -1671,6 +1668,8 @@ pub fn write_restore_info(self: *Self) WriteStateError!void { } pub fn write_state(self: *Self, writer: *std.Io.Writer) WriteStateError!void { + const current_project = tp.env.get().str("project"); + try cbor.writeValue(writer, current_project); if (self.get_active_editor()) |editor| { try cbor.writeValue(writer, editor.file_path); editor.update_meta(); @@ -1707,20 +1706,36 @@ fn read_restore_info(self: *Self) !void { const size = try file.readAll(buf); var iter: []const u8 = buf[0..size]; - try self.extract_state(&iter); + try self.extract_state(&iter, .with_project); } fn restore_state(self: *Self, state: []const u8) !void { var iter = state; - try self.extract_state(&iter); + try self.extract_state(&iter, .no_project); } -fn extract_state(self: *Self, iter: *[]const u8) !void { +fn extract_state(self: *Self, iter: *[]const u8, mode: enum { no_project, with_project }) !void { const logger = log.logger("extract_state"); defer logger.deinit(); tp.trace(tp.channel.debug, .{ "mainview", "extract" }); + var project_dir: []const u8 = undefined; var editor_file_path: ?[]const u8 = undefined; var prev_len = iter.len; + if (!try cbor.matchValue(iter, cbor.extract(&project_dir))) { + logger.print("restore project_dir failed", .{}); + return error.MatchStoredProjectFailed; + } + + switch (mode) { + .with_project => { + _ = try project_manager.open(project_dir); + tui.rdr().set_terminal_working_directory(project_dir); + if (self.top_bar) |bar| _ = try bar.msg(.{ "PRJ", "open" }); + if (self.bottom_bar) |bar| _ = try bar.msg(.{ "PRJ", "open" }); + }, + .no_project => {}, + } + if (!try cbor.matchValue(iter, cbor.extract(&editor_file_path))) { logger.print("restore editor_file_path failed", .{}); return error.MatchFilePathFailed; From 8442edc80ff3788aa0ae309451bc7a0355492514 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Sat, 6 Dec 2025 21:13:04 +0100 Subject: [PATCH 3/8] feat: add save_session command --- src/tui/mainview.zig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/tui/mainview.zig b/src/tui/mainview.zig index 58f4046..c05ecab 100644 --- a/src/tui/mainview.zig +++ b/src/tui/mainview.zig @@ -355,6 +355,11 @@ const cmds = struct { } pub const quit_without_saving_meta: Meta = .{ .description = "Quit without saving" }; + pub fn save_session(self: *Self, _: Ctx) Result { + try self.write_restore_info(); + } + pub const save_session_meta: Meta = .{ .description = "Save session" }; + pub fn store_session_and_quit(self: *Self, _: Ctx) Result { try self.write_restore_info(); try tp.self_pid().send("quit"); From de73875676f1cf4366d81a2c00d4aa4457632f4f Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Sat, 6 Dec 2025 21:14:30 +0100 Subject: [PATCH 4/8] refactor: rename save_session_and_quit command --- src/tui/mainview.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tui/mainview.zig b/src/tui/mainview.zig index c05ecab..c8eea67 100644 --- a/src/tui/mainview.zig +++ b/src/tui/mainview.zig @@ -360,11 +360,11 @@ const cmds = struct { } pub const save_session_meta: Meta = .{ .description = "Save session" }; - pub fn store_session_and_quit(self: *Self, _: Ctx) Result { + pub fn save_session_and_quit(self: *Self, _: Ctx) Result { try self.write_restore_info(); try tp.self_pid().send("quit"); } - pub const store_session_and_quit_meta: Meta = .{ .description = "Save session and quit" }; + pub const save_session_and_quit_meta: Meta = .{ .description = "Save session and quit" }; pub fn open_project_cwd(self: *Self, _: Ctx) Result { if (try project_manager.open(".")) |state| From 921c17de3c2d76a3b3487c7f4a882324286191a3 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Sat, 6 Dec 2025 21:42:56 +0100 Subject: [PATCH 5/8] feat: add auto_run_commands and auto_run_time_seconds config options --- src/config.zig | 3 +++ src/tui/tui.zig | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/src/config.zig b/src/config.zig index 4f87967..d04d97c 100644 --- a/src/config.zig +++ b/src/config.zig @@ -32,6 +32,9 @@ limit_auto_save_file_types: ?[]const []const u8 = null, // null means *all* enable_prefix_keyhints: bool = true, enable_auto_find: bool = true, +auto_run_time_seconds: usize = 360, //seconds +auto_run_commands: ?[]const []const u8 = null, // a list of simple commands + indent_size: usize = 4, tab_width: usize = 8, indent_mode: IndentMode = .auto, diff --git a/src/tui/tui.zig b/src/tui/tui.zig index f04f7d3..6ad0b07 100644 --- a/src/tui/tui.zig +++ b/src/tui/tui.zig @@ -87,6 +87,8 @@ color_scheme_locked: bool = false, hint_mode: HintMode = .prefix, last_palette: ?LastPalette = null, +auto_run_timer: ?tp.Cancellable = null, + const HintMode = enum { none, prefix, all }; const LastPalette = struct { @@ -257,9 +259,15 @@ fn init_delayed(self: *Self) command.Result { try cmds.enter_mode(self, command.Context.fmt(.{keybind.default_mode})); } } + self.start_auto_run_timer(); } fn deinit(self: *Self) void { + if (self.auto_run_timer) |*t| { + t.cancel() catch {}; + t.deinit(); + self.auto_run_timer = null; + } if (self.input_idle_timer) |*t| { t.cancel() catch {}; t.deinit(); @@ -346,6 +354,23 @@ fn update_mouse_idle_timer(self: *Self) void { self.mouse_idle_timer = tp.self_pid().delay_send_cancellable(self.allocator, "tui.mouse_idle_timer", delay, .{"MOUSE_IDLE"}) catch return; } +fn auto_run(self: *Self) void { + const auto_run_cmds = self.config_.auto_run_commands orelse return; + for (auto_run_cmds) |cmd| + command.executeName(cmd, .{}) catch |e| self.logger.print_err("autorun", "auto run command '{s}' failed: {t}", .{ cmd, e }); + self.start_auto_run_timer(); +} + +fn start_auto_run_timer(self: *Self) void { + const delay = std.time.us_per_s * @as(u64, self.config_.auto_run_time_seconds); + if (self.auto_run_timer) |*t| { + t.cancel() catch {}; + t.deinit(); + self.auto_run_timer = null; + } + self.auto_run_timer = tp.self_pid().delay_send_cancellable(self.allocator, "tui.auto_run_timer", delay, .{"AUTO_RUN"}) catch return; +} + fn receive(self: *Self, from: tp.pid_ref, m: tp.message) tp.result { const frame = tracy.initZone(@src(), .{ .name = "tui" }); defer frame.deinit(); @@ -510,6 +535,13 @@ fn receive_safe(self: *Self, from: tp.pid_ref, m: tp.message) !void { return; } + if (try m.match(.{"AUTO_RUN"})) { + if (self.auto_run_timer) |*t| t.deinit(); + self.auto_run_timer = null; + self.auto_run(); + return; + } + if (try m.match(.{ "fontface", "done" })) { return self.enter_overlay_mode(@import("mode/overlay/fontface_palette.zig").Type); } From 719eed4cfdd013fa3d5fba2216fd3b76ba319069 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Sat, 6 Dec 2025 21:46:09 +0100 Subject: [PATCH 6/8] feat: add save_session_quiet command and make save_session verbose --- src/tui/mainview.zig | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/tui/mainview.zig b/src/tui/mainview.zig index c8eea67..5db8785 100644 --- a/src/tui/mainview.zig +++ b/src/tui/mainview.zig @@ -356,10 +356,19 @@ const cmds = struct { pub const quit_without_saving_meta: Meta = .{ .description = "Quit without saving" }; pub fn save_session(self: *Self, _: Ctx) Result { + const logger = log.logger("session"); + defer logger.deinit(); + logger.print("saving session...", .{}); try self.write_restore_info(); + logger.print("session saved", .{}); } pub const save_session_meta: Meta = .{ .description = "Save session" }; + pub fn save_session_quiet(self: *Self, _: Ctx) Result { + try self.write_restore_info(); + } + pub const save_session_quiet_meta: Meta = .{}; + pub fn save_session_and_quit(self: *Self, _: Ctx) Result { try self.write_restore_info(); try tp.self_pid().send("quit"); From b87a58accc0ab4b72df360cf100a6a6bbb4691b2 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Sat, 6 Dec 2025 21:50:33 +0100 Subject: [PATCH 7/8] feat: add idle_commands config option --- src/config.zig | 1 + src/tui/tui.zig | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/config.zig b/src/config.zig index d04d97c..6f7f769 100644 --- a/src/config.zig +++ b/src/config.zig @@ -22,6 +22,7 @@ animation_max_lag: usize = 50, //milliseconds hover_time_ms: usize = 500, //milliseconds input_idle_time_ms: usize = 150, //milliseconds idle_actions: []const IdleAction = &default_actions, +idle_commands: ?[]const []const u8 = null, // a list of simple commands 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/tui.zig b/src/tui/tui.zig index 6ad0b07..aa960c1 100644 --- a/src/tui/tui.zig +++ b/src/tui/tui.zig @@ -318,6 +318,9 @@ fn handle_input_idle(self: *Self) void { var buf: [32]u8 = undefined; const m = tp.message.fmtbuf(&buf, .{"input_idle"}) catch return; _ = self.send_widgets(tp.self_pid(), m) catch return; + const idle_cmds = self.config_.idle_commands orelse return; + for (idle_cmds) |cmd| + command.executeName(cmd, .{}) catch |e| self.logger.print_err("idlerun", "idle run command '{s}' failed: {t}", .{ cmd, e }); } fn update_input_idle_timer(self: *Self) void { From 8b17eb98179ec297788fac675cf8e10977081d45 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Sat, 6 Dec 2025 22:03:52 +0100 Subject: [PATCH 8/8] feat: auto save session every two minutes --- src/config.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config.zig b/src/config.zig index 6f7f769..2b30ba5 100644 --- a/src/config.zig +++ b/src/config.zig @@ -33,8 +33,8 @@ limit_auto_save_file_types: ?[]const []const u8 = null, // null means *all* enable_prefix_keyhints: bool = true, enable_auto_find: bool = true, -auto_run_time_seconds: usize = 360, //seconds -auto_run_commands: ?[]const []const u8 = null, // a list of simple commands +auto_run_time_seconds: usize = 120, //seconds +auto_run_commands: ?[]const []const u8 = &.{"save_session_quiet"}, // a list of simple commands indent_size: usize = 4, tab_width: usize = 8,