From 863c9aade5623f79ccfb9d3c69718bd12a8846c2 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Fri, 20 Feb 2026 11:40:12 +0100 Subject: [PATCH] refactor: update project file index on watcher events --- src/Project.zig | 34 ++++++++++++++++++++++++++++++++++ src/project_manager.zig | 25 ++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/Project.zig b/src/Project.zig index 817ada8..6103d11 100644 --- a/src/Project.zig +++ b/src/Project.zig @@ -777,6 +777,40 @@ fn loaded(self: *Self, parent: tp.pid_ref) OutOfMemoryError!void { parent.send(.{ "PRJ", "open_done", self.name, self.longest_file_path, self.files.items.len }) catch {}; } +pub fn file_added(self: *Self, file_path: []const u8) OutOfMemoryError!void { + for (self.files.items) |file| + if (std.mem.eql(u8, file.path, file_path)) return; + const file_type, const file_icon, const file_color = guess_file_type(file_path); + (try self.files.addOne(self.allocator)).* = .{ + .path = try self.allocator.dupe(u8, file_path), + .type = file_type, + .icon = file_icon, + .color = file_color, + .mtime = std.time.nanoTimestamp(), + }; + self.longest_file_path = @max(self.longest_file_path, file_path.len); + self.sort_files_by_mtime(); +} + +pub fn file_modified(self: *Self, file_path: []const u8) void { + for (self.files.items) |*file| { + if (!std.mem.eql(u8, file.path, file_path)) continue; + file.mtime = std.time.nanoTimestamp(); + self.sort_files_by_mtime(); + return; + } +} + +pub fn file_deleted(self: *Self, file_path: []const u8) void { + for (self.files.items, 0..) |file, i| { + if (!std.mem.eql(u8, file.path, file_path)) continue; + self.allocator.free(file.path); + _ = self.files.swapRemove(i); + self.sort_files_by_mtime(); + return; + } +} + pub fn update_mru(self: *Self, file_path: []const u8, row: usize, col: usize) OutOfMemoryError!void { defer self.sort_files_by_mtime(); try self.update_mru_internal(file_path, std.time.nanoTimestamp(), row, col); diff --git a/src/project_manager.zig b/src/project_manager.zig index a3e9eb5..bd56f5e 100644 --- a/src/project_manager.zig +++ b/src/project_manager.zig @@ -421,8 +421,11 @@ const Process = struct { var vcs_id: []const u8 = undefined; var eol_mode: Buffer.EolModeTag = @intFromEnum(Buffer.EolMode.lf); + var event_type: file_watcher.EventType = undefined; - if (try cbor.match(m.buf, .{ "walk_tree_entry", tp.extract(&project_directory), tp.more })) { + if (try cbor.match(m.buf, .{ "FW", "change", tp.extract(&path), tp.extract(&event_type) })) { + self.handle_file_watch_event(path, event_type); + } else if (try cbor.match(m.buf, .{ "walk_tree_entry", tp.extract(&project_directory), tp.more })) { if (self.projects.get(project_directory)) |project| project.walk_tree_entry(m) catch |e| self.logger.err("walk_tree_entry", e); } else if (try cbor.match(m.buf, .{ "walk_tree_done", tp.extract(&project_directory) })) { @@ -539,6 +542,26 @@ const Process = struct { } } + fn handle_file_watch_event(self: *Process, abs_path: []const u8, event_type: file_watcher.EventType) void { + std.log.debug("file_watch_event: {s} {s}", .{ @tagName(event_type), abs_path }); + var it = self.projects.iterator(); + while (it.next()) |entry| { + const dir = entry.key_ptr.*; + if (!std.mem.startsWith(u8, abs_path, dir)) continue; + if (abs_path.len <= dir.len or abs_path[dir.len] != std.fs.path.sep) continue; + const rel_path = abs_path[dir.len + 1 ..]; + const project = entry.value_ptr.*; + switch (event_type) { + .created => project.file_added(rel_path) catch |e| self.logger.err("file_watcher.file_added", e), + .modified => project.file_modified(rel_path), + .deleted => project.file_deleted(rel_path), + .renamed => project.file_deleted(rel_path), + } + return; + } + self.parent.send(.{ "FW", "change", abs_path, event_type }) catch {}; + } + fn open(self: *Process, project_directory: []const u8) (SpawnError || std.fs.Dir.OpenError)!void { if (self.projects.get(project_directory)) |project| { project.last_used = std.time.nanoTimestamp();