diff --git a/src/Project.zig b/src/Project.zig index a12ff0f..e1ce93e 100644 --- a/src/Project.zig +++ b/src/Project.zig @@ -31,6 +31,7 @@ persistent: bool = false, logger: log.Logger, logger_lsp: log.Logger, logger_git: log.Logger, +last_used: i128, workspace: ?[]const u8 = null, @@ -100,6 +101,7 @@ pub fn init(allocator: std.mem.Allocator, name: []const u8) OutOfMemoryError!Sel .logger = log.logger("project"), .logger_lsp = log.logger("lsp"), .logger_git = log.logger("git"), + .last_used = std.time.nanoTimestamp(), }; } diff --git a/src/keybind/keybind.zig b/src/keybind/keybind.zig index 92f8a3f..4fe2d67 100644 --- a/src/keybind/keybind.zig +++ b/src/keybind/keybind.zig @@ -100,7 +100,7 @@ const Handler = struct { pub const Mode = struct { allocator: std.mem.Allocator, - input_handler: EventHandler, + input_handler: ?EventHandler, event_handler: ?EventHandler = null, mode: []const u8, @@ -121,11 +121,24 @@ pub const Mode = struct { } pub fn deinit(self: *Mode) void { - if (self.deinit_command) |deinit_command| - deinit_command.execute_const(); - self.allocator.free(self.mode); - self.input_handler.deinit(); + if (self.deinit_command) |deinit_command| deinit_command.execute_const(); if (self.event_handler) |eh| eh.deinit(); + if (self.input_handler) |ih| ih.deinit(); + self.allocator.free(self.mode); + + self.deinit_command = null; + self.event_handler = null; + self.input_handler = null; + self.mode = &.{}; + + self.name = ""; + self.line_numbers = .inherit; + self.keybind_hints = &.{}; + self.cursor_shape = null; + self.selection_style = .normal; + self.init_command = null; + self.deinit_command = null; + self.initialized = false; } }; diff --git a/src/project_manager.zig b/src/project_manager.zig index c5d380c..4cd1146 100644 --- a/src/project_manager.zig +++ b/src/project_manager.zig @@ -463,15 +463,16 @@ const Process = struct { } fn open(self: *Process, project_directory: []const u8) (SpawnError || std.fs.Dir.OpenError)!void { - if (self.projects.get(project_directory) == null) { + if (self.projects.get(project_directory)) |project| { + project.last_used = std.time.nanoTimestamp(); + self.logger.print("switched to: {s}", .{project_directory}); + } else { self.logger.print("opening: {s}", .{project_directory}); const project = try self.allocator.create(Project); project.* = try Project.init(self.allocator, project_directory); try self.projects.put(self.allocator, try self.allocator.dupe(u8, project_directory), project); self.restore_project(project) catch |e| self.logger.err("restore_project", e); project.query_git(); - } else { - self.logger.print("switched to: {s}", .{project_directory}); } } @@ -505,10 +506,35 @@ const Process = struct { return project.request_new_or_modified_files(from, max); } - fn request_recent_projects(self: *Process, from: tp.pid_ref, project_directory: []const u8) (ProjectError || Project.ClientError)!void { + fn request_recent_projects(self: *Process, from: tp.pid_ref, active_project: []const u8) (ProjectError || Project.ClientError)!void { var recent_projects: std.ArrayList(RecentProject) = .empty; defer recent_projects.deinit(self.allocator); - self.load_recent_projects(&recent_projects, project_directory) catch {}; + self.load_recent_projects(&recent_projects) catch {}; + for (recent_projects.items) |*recent_project| { + if (std.mem.eql(u8, active_project, recent_project.name)) { + recent_project.last_used = std.math.maxInt(i128); + break; + } + } else { + (try recent_projects.addOne(self.allocator)).* = .{ + .name = try self.allocator.dupe(u8, active_project), + .last_used = std.math.maxInt(i128), + }; + } + var iter = self.projects.iterator(); + while (iter.next()) |item| { + for (recent_projects.items) |*recent_project| { + if (std.mem.eql(u8, item.value_ptr.*.name, recent_project.name)) { + recent_project.last_used = item.value_ptr.*.last_used; + break; + } + } else { + (try recent_projects.addOne(self.allocator)).* = .{ + .name = try self.allocator.dupe(u8, item.value_ptr.*.name), + .last_used = item.value_ptr.*.last_used, + }; + } + } self.sort_projects_by_last_used(&recent_projects); var message: std.Io.Writer.Allocating = .init(self.allocator); defer message.deinit(); @@ -521,6 +547,7 @@ const Process = struct { try cbor.writeArrayHeader(writer, 2); try cbor.writeValue(writer, project.name); try cbor.writeValue(writer, if (self.projects.get(project.name)) |_| true else false); + self.allocator.free(project.name); } from.send_raw(.{ .buf = message.written() }) catch return error.ClientFailed; self.logger.print("{d} projects found", .{recent_projects.items.len}); @@ -755,7 +782,7 @@ const Process = struct { return stream.toOwnedSlice(); } - fn load_recent_projects(self: *Process, recent_projects: *std.ArrayList(RecentProject), project_directory: []const u8) !void { + fn load_recent_projects(self: *Process, recent_projects: *std.ArrayList(RecentProject)) !void { var path: std.Io.Writer.Allocating = .init(self.allocator); defer path.deinit(); const writer = &path.writer; @@ -768,7 +795,7 @@ const Process = struct { var iter = dir.iterate(); while (try iter.next()) |entry| { if (entry.kind != .file) continue; - try self.read_project_name(path.written(), entry.name, recent_projects, project_directory); + try self.read_project_name(path.written(), entry.name, recent_projects); } } @@ -777,7 +804,6 @@ const Process = struct { state_dir: []const u8, file_path: []const u8, recent_projects: *std.ArrayList(RecentProject), - project_directory: []const u8, ) !void { var path: std.Io.Writer.Allocating = .init(self.allocator); defer path.deinit(); @@ -795,10 +821,8 @@ const Process = struct { var iter: []const u8 = buffer; var name: []const u8 = undefined; - if (cbor.matchValue(&iter, tp.extract(&name)) catch return) { - const last_used = if (std.mem.eql(u8, project_directory, name)) std.math.maxInt(@TypeOf(stat.mtime)) else stat.mtime; - (try recent_projects.addOne(self.allocator)).* = .{ .name = try self.allocator.dupe(u8, name), .last_used = last_used }; - } + if (cbor.matchValue(&iter, tp.extract(&name)) catch return) + (try recent_projects.addOne(self.allocator)).* = .{ .name = try self.allocator.dupe(u8, name), .last_used = stat.mtime }; } fn sort_projects_by_last_used(_: *Process, recent_projects: *std.ArrayList(RecentProject)) void { diff --git a/src/tui/tui.zig b/src/tui/tui.zig index 917fc50..a465633 100644 --- a/src/tui/tui.zig +++ b/src/tui/tui.zig @@ -554,7 +554,7 @@ fn active_event_handler(self: *Self) ?EventHandler { fn dispatch_flush_input_event(self: *Self) error{ Exit, NoSpaceLeft }!void { var buf: [32]u8 = undefined; const mode = self.input_mode_ orelse return; - try mode.input_handler.send(tp.self_pid(), try tp.message.fmtbuf(&buf, .{"F"})); + if (mode.input_handler) |ih| try ih.send(tp.self_pid(), try tp.message.fmtbuf(&buf, .{"F"})); if (mode.event_handler) |eh| try eh.send(tp.self_pid(), try tp.message.fmtbuf(&buf, .{"F"})); } @@ -577,8 +577,8 @@ fn dispatch_input(ctx: *anyopaque, cbor_msg: []const u8) void { break :ret false; }) return; - if (self.input_mode_) |mode| - mode.input_handler.send(from, m) catch |e| self.logger.err("input handler", e); + if (self.input_mode_) |mode| if (mode.input_handler) |ih| + ih.send(from, m) catch |e| self.logger.err("input handler", e); } fn dispatch_mouse(ctx: *anyopaque, y: c_int, x: c_int, cbor_msg: []const u8) void {