diff --git a/src/Project.zig b/src/Project.zig index 946e23a..e71c915 100644 --- a/src/Project.zig +++ b/src/Project.zig @@ -19,10 +19,8 @@ const walk_tree = @import("walk_tree.zig"); allocator: std.mem.Allocator, name: []const u8, files: std.ArrayListUnmanaged(File) = .empty, -new_or_modified_files: std.ArrayListUnmanaged(FileVcsStatus) = .empty, pending: std.ArrayListUnmanaged(File) = .empty, longest_file_path: usize = 0, -longest_new_or_modified_file_path: usize = 0, open_time: i64, language_servers: std.StringHashMap(*const LSP), file_language_server_name: std.StringHashMap([]const u8), @@ -43,7 +41,6 @@ state: struct { current_branch: State = .none, workspace_files: State = .none, status: State = .none, - vcs_new_or_modified_files: State = .none, } = .{}, status: VcsStatus = .{}, @@ -69,14 +66,6 @@ const File = struct { visited: bool = false, }; -const FileVcsStatus = struct { - path: []const u8, - type: []const u8, - icon: []const u8, - color: u24, - vcs_status: u8, -}; - pub const FilePos = struct { row: usize = 0, col: usize = 0, @@ -116,8 +105,6 @@ pub fn deinit(self: *Self) void { self.allocator.free(p.key_ptr.*); p.value_ptr.*.term(); } - for (self.new_or_modified_files.items) |file| self.allocator.free(file.path); - self.new_or_modified_files.deinit(self.allocator); for (self.files.items) |file| self.allocator.free(file.path); self.files.deinit(self.allocator); self.pending.deinit(self.allocator); @@ -385,84 +372,6 @@ pub fn request_recent_files(self: *Self, from: tp.pid_ref, max: usize) ClientErr } } -fn simple_query_new_or_modified_files(self: *Self, from: tp.pid_ref, max: usize, query: []const u8) ClientError!usize { - var i: usize = 0; - defer from.send(.{ "PRJ", "new_or_modified_files_done", self.longest_file_path, query }) catch {}; - for (self.new_or_modified_files.items) |file| { - if (file.path.len < query.len) continue; - if (std.mem.indexOf(u8, file.path, query)) |idx| { - var matches = try self.allocator.alloc(usize, query.len); - defer self.allocator.free(matches); - var n: usize = 0; - while (n < query.len) : (n += 1) matches[n] = idx + n; - from.send(.{ "PRJ", "new_or_modified_files", self.longest_new_or_modified_file_path, file.path, file.type, file.icon, file.color, file.vcs_status, matches }) catch return error.ClientFailed; - i += 1; - if (i >= max) return i; - } - } - return i; -} - -pub fn query_new_or_modified_files(self: *Self, from: tp.pid_ref, max: usize, query: []const u8) ClientError!usize { - if (query.len < 3) - return self.simple_query_new_or_modified_files(from, max, query); - defer from.send(.{ "PRJ", "new_or_modified_files_done", self.longest_file_path, query }) catch {}; - - var searcher = try fuzzig.Ascii.init( - self.allocator, - 4096, // haystack max size - 4096, // needle max size - .{ .case_sensitive = false }, - ); - defer searcher.deinit(); - - const Match = struct { - path: []const u8, - type: []const u8, - icon: []const u8, - color: u24, - vcs_status: u8, - score: i32, - matches: []const usize, - }; - var matches: std.ArrayList(Match) = .empty; - - for (self.new_or_modified_files.items) |file| { - const match = searcher.scoreMatches(file.path, query); - if (match.score) |score| { - (try matches.addOne(self.allocator)).* = .{ - .path = file.path, - .type = file.type, - .icon = file.icon, - .color = file.color, - .vcs_status = file.vcs_status, - .score = score, - .matches = try self.allocator.dupe(usize, match.matches), - }; - } - } - if (matches.items.len == 0) return 0; - - const less_fn = struct { - fn less_fn(_: void, lhs: Match, rhs: Match) bool { - return lhs.score > rhs.score; - } - }.less_fn; - std.mem.sort(Match, matches.items, {}, less_fn); - - for (matches.items[0..@min(max, matches.items.len)]) |match| - from.send(.{ "PRJ", "new_or_modified_files", self.longest_new_or_modified_file_path, match.path, match.type, match.icon, match.color, match.vcs_status, match.matches }) catch return error.ClientFailed; - return @min(max, matches.items.len); -} - -pub fn request_new_or_modified_files(self: *Self, from: tp.pid_ref, max: usize) ClientError!void { - defer from.send(.{ "PRJ", "new_or_modified_files_done", self.longest_new_or_modified_file_path, "" }) catch {}; - for (self.new_or_modified_files.items, 0..) |file, i| { - from.send(.{ "PRJ", "new_or_modified_files", self.longest_new_or_modified_file_path, file.path, file.type, file.icon, file.color, file.vcs_status }) catch return error.ClientFailed; - if (i >= max) return; - } -} - fn simple_query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query: []const u8) ClientError!usize { var i: usize = 0; defer from.send(.{ "PRJ", "recent_done", self.longest_file_path, query }) catch {}; @@ -635,8 +544,6 @@ fn loaded(self: *Self, parent: tp.pid_ref) OutOfMemoryError!void { std.time.milliTimestamp() - self.open_time, }); - self.logger.print("vcs outstanding files: {d}", .{self.new_or_modified_files.items.len}); - parent.send(.{ "PRJ", "open_done", self.name, self.longest_file_path, self.files.items.len }) catch {}; } @@ -2173,13 +2080,6 @@ pub fn query_git(self: *Self) void { git.status(@intFromPtr(self)) catch { self.state.status = .failed; }; - // TODO: This needs to be invoked when there are identified changes in the fs - for (self.new_or_modified_files.items) |file| self.allocator.free(file.path); - self.new_or_modified_files.clearRetainingCapacity(); - self.state.vcs_new_or_modified_files = .running; - git.new_or_modified_files(@intFromPtr(self)) catch { - self.state.vcs_new_or_modified_files = .failed; - }; } fn start_walker(self: *Self) void { @@ -2193,7 +2093,6 @@ fn start_walker(self: *Self) void { pub fn process_git(self: *Self, parent: tp.pid_ref, m: tp.message) (OutOfMemoryError || error{Exit})!void { var value: []const u8 = undefined; var path: []const u8 = undefined; - var vcs_status: u8 = undefined; if (try m.match(.{ tp.any, tp.any, "status", tp.more })) { return self.process_status(m); } else if (try m.match(.{ tp.any, tp.any, "workspace_path", tp.null_ })) { @@ -2232,19 +2131,6 @@ pub fn process_git(self: *Self, parent: tp.pid_ref, m: tp.message) (OutOfMemoryE } else if (try m.match(.{ tp.any, tp.any, "workspace_files", tp.null_ })) { self.state.workspace_files = .done; try self.loaded(parent); - } else if (try m.match(.{ tp.any, tp.any, "new_or_modified_files", tp.null_ })) { - self.state.vcs_new_or_modified_files = .done; - try self.loaded(parent); - } else if (try m.match(.{ tp.any, tp.any, "new_or_modified_files", tp.extract(&vcs_status), tp.extract(&path) })) { - self.longest_new_or_modified_file_path = @max(self.longest_new_or_modified_file_path, path.len); - const file_type: []const u8, const file_icon: []const u8, const file_color: u24 = guess_file_type(path); - (try self.new_or_modified_files.addOne(self.allocator)).* = .{ - .path = try self.allocator.dupe(u8, path), - .type = file_type, - .icon = file_icon, - .color = file_color, - .vcs_status = vcs_status, - }; } else { self.logger_git.err("git", tp.unexpected(m)); } diff --git a/src/git.zig b/src/git.zig index 8cd2850..daf28c8 100644 --- a/src/git.zig +++ b/src/git.zig @@ -174,105 +174,6 @@ pub fn status(context_: usize) Error!void { }.result, exit_null(tag)); } -pub fn new_or_modified_files(context_: usize) Error!void { - const tag = @src().fn_name; - try git_err(context_, .{ - "--no-optional-locks", - "status", - "--porcelain=v2", - "--null", - }, struct { - fn result(context: usize, parent: tp.pid_ref, output: []const u8) void { - var it_ = std.mem.splitScalar(u8, output, 0); - var counter: u8 = 0; - - while (it_.next()) |line| { - var it = std.mem.splitScalar(u8, line, ' '); - const rec_type = if (it.next()) |type_tag| - std.meta.stringToEnum(StatusRecordType, type_tag) orelse { - if (type_tag.len > 0) - std.log.debug("found {s}, it happens when a file is renamed and not modified. Check `git --no-optional-locks status --porcelain=v2`", .{type_tag}); - continue; - } - else - return; - switch (rec_type) { - .@"1" => { // ordinary file: - const sub = it.next() orelse return; - const mH = it.next() orelse return; - var vcs_status: u8 = undefined; - if (sub[0] == 'A') { - // New staged file is shown as new - vcs_status = '+'; - } else if (sub[0] == 'M' or sub[1] == 'M') { - if (mH[0] == 'S') { - // We do not handle submodules, yet - continue; - } - vcs_status = '~'; - } else { - // We will not edit deleted files - continue; - } - - for (0..5) |_| { - _ = it.next() orelse return; - } - var path: std.ArrayListUnmanaged(u8) = .empty; - defer path.deinit(allocator); - while (it.next()) |path_part| { - if (path.items.len > 0) path.append(allocator, ' ') catch return; - path.appendSlice(allocator, path_part) catch return; - } - - parent.send(.{ module_name, context, tag, vcs_status, path.items }) catch {}; - counter += 1; - }, - .@"2" => { - const sub = it.next() orelse return; - if (sub[0] != 'R') { - continue; - } - // An staged file is editable - // renamed: - for (0..7) |_| { - _ = it.next() orelse return; - } - var path: std.ArrayListUnmanaged(u8) = .empty; - defer path.deinit(allocator); - while (it.next()) |path_part| { - if (path.items.len > 0) path.append(allocator, ' ') catch return; - path.appendSlice(allocator, path_part) catch return; - } - parent.send(.{ module_name, context, tag, '+', path.items }) catch {}; - counter += 1; - }, - .@"?" => { // untracked file: - var path: std.ArrayListUnmanaged(u8) = .empty; - defer path.deinit(allocator); - while (it.next()) |path_part| { - if (path.items.len > 0) path.append(allocator, ' ') catch return; - path.appendSlice(allocator, path_part) catch return; - } - parent.send(.{ module_name, context, tag, '+', path.items }) catch {}; - counter += 1; - }, - else => { - // Omit showing other statuses - }, - } - } - std.log.info("git: {} changed files", .{counter}); - } - }.result, struct { - fn result(_: usize, _: tp.pid_ref, output: []const u8) void { - var it = std.mem.splitScalar(u8, output, '\n'); - while (it.next()) |line| if (line.len > 0) - std.log.err("{s}: {s}", .{ module_name, line }); - } - }.result, exit_null(tag)); -} - fn git_line_output(context_: usize, comptime tag: []const u8, cmd: anytype) Error!void { try git_err(context_, cmd, struct { fn result(context: usize, parent: tp.pid_ref, output: []const u8) void { diff --git a/src/keybind/builtin/helix.json b/src/keybind/builtin/helix.json index 6282250..8fb3650 100644 --- a/src/keybind/builtin/helix.json +++ b/src/keybind/builtin/helix.json @@ -228,7 +228,6 @@ ["space R", "replace_selections_with_clipboard"], ["space ?", "open_command_palette"], ["space f", "find_file"], - ["space g", "show_vcs_status"], ["space b", "switch_buffers"], ["space j", "jumplist_picker"], ["space s", "symbol_picker"], diff --git a/src/project_manager.zig b/src/project_manager.zig index c5d380c..46cd226 100644 --- a/src/project_manager.zig +++ b/src/project_manager.zig @@ -98,20 +98,6 @@ pub fn request_recent_files(max: usize) (ProjectManagerError || ProjectError)!vo return send(.{ "request_recent_files", project, max }); } -pub fn request_new_or_modified_files(max: usize) (ProjectManagerError || ProjectError)!void { - const project = tp.env.get().str("project"); - if (project.len == 0) - return error.NoProject; - return send(.{ "request_new_or_modified_files", project, max }); -} - -pub fn request_sync_with_vcs() (ProjectManagerError || ProjectError)!void { - const project = tp.env.get().str("project"); - if (project.len == 0) - return error.NoProject; - return send(.{ "sync_with_vcs", project }); -} - pub fn request_recent_projects() (ProjectManagerError || ProjectError)!void { const project = tp.env.get().str("project"); return send(.{ "request_recent_projects", project }); @@ -124,13 +110,6 @@ pub fn query_recent_files(max: usize, query: []const u8) (ProjectManagerError || return send(.{ "query_recent_files", project, max, query }); } -pub fn query_new_or_modified_files(max: usize, query: []const u8) (ProjectManagerError || ProjectError)!void { - const project = tp.env.get().str("project"); - if (project.len == 0) - return error.NoProject; - return send(.{ "query_new_or_modified_files", project, max, query }); -} - pub fn request_path_files(max: usize, path: []const u8) (ProjectManagerError || ProjectError)!void { const project = tp.env.get().str("project"); if (project.len == 0) @@ -391,16 +370,10 @@ const Process = struct { self.request_n_most_recent_file(from, project_directory, n) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed; } else if (try cbor.match(m.buf, .{ "request_recent_files", tp.extract(&project_directory), tp.extract(&max) })) { self.request_recent_files(from, project_directory, max) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed; - } else if (try cbor.match(m.buf, .{ "request_new_or_modified_files", tp.extract(&project_directory), tp.extract(&max) })) { - self.request_new_or_modified_files(from, project_directory, max) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed; - } else if (try cbor.match(m.buf, .{ "sync_with_vcs", tp.extract(&project_directory) })) { - self.request_sync_with_vcs(from, project_directory) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed; } else if (try cbor.match(m.buf, .{ "request_recent_projects", tp.extract(&project_directory) })) { self.request_recent_projects(from, project_directory) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed; } else if (try cbor.match(m.buf, .{ "query_recent_files", tp.extract(&project_directory), tp.extract(&max), tp.extract(&query) })) { self.query_recent_files(from, project_directory, max, query) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed; - } else if (try cbor.match(m.buf, .{ "query_new_or_modified_files", tp.extract(&project_directory), tp.extract(&max), tp.extract(&query) })) { - self.query_new_or_modified_files(from, project_directory, max, query) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed; } else if (try cbor.match(m.buf, .{ "request_path_files", tp.extract(&project_directory), tp.extract(&max), tp.extract(&path) })) { self.request_path_files(from, project_directory, max, path) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed; } else if (try cbor.match(m.buf, .{ "request_tasks", tp.extract(&project_directory) })) { @@ -495,16 +468,6 @@ const Process = struct { return project.request_recent_files(from, max); } - fn request_sync_with_vcs(self: *Process, _: tp.pid_ref, project_directory: []const u8) (ProjectError || Project.ClientError)!void { - const project = self.projects.get(project_directory) orelse return error.NoProject; - return project.query_git(); - } - - fn request_new_or_modified_files(self: *Process, from: tp.pid_ref, project_directory: []const u8, max: usize) (ProjectError || Project.ClientError)!void { - const project = self.projects.get(project_directory) orelse return error.NoProject; - 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 { var recent_projects: std.ArrayList(RecentProject) = .empty; defer recent_projects.deinit(self.allocator); @@ -535,15 +498,6 @@ const Process = struct { self.logger.print("query \"{s}\" matched {d}/{d} in {d} ms", .{ query, matched, project.files.items.len, query_time }); } - fn query_new_or_modified_files(self: *Process, from: tp.pid_ref, project_directory: []const u8, max: usize, query: []const u8) (ProjectError || Project.ClientError)!void { - const project = self.projects.get(project_directory) orelse return error.NoProject; - const start_time = std.time.milliTimestamp(); - const matched = try project.query_new_or_modified_files(from, max, query); - const query_time = std.time.milliTimestamp() - start_time; - if (query_time > 250) - self.logger.print("query \"{s}\" matched {d}/{d} in {d} ms", .{ query, matched, project.files.items.len, query_time }); - } - fn request_path_files(self: *Process, from: tp.pid_ref, project_directory: []const u8, max: usize, path: []const u8) (ProjectError || SpawnError || std.fs.Dir.OpenError)!void { const project = self.projects.get(project_directory) orelse return error.NoProject; var buf: std.ArrayList(u8) = .empty; diff --git a/src/tui/mode/overlay/vcs_status.zig b/src/tui/mode/overlay/vcs_status.zig deleted file mode 100644 index 2ecfc41..0000000 --- a/src/tui/mode/overlay/vcs_status.zig +++ /dev/null @@ -1,391 +0,0 @@ -const std = @import("std"); -const tp = @import("thespian"); -const log = @import("log"); -const cbor = @import("cbor"); -const file_type_config = @import("file_type_config"); - -const Plane = @import("renderer").Plane; -const input = @import("input"); -const keybind = @import("keybind"); -const project_manager = @import("project_manager"); -const command = @import("command"); -const EventHandler = @import("EventHandler"); -const BufferManager = @import("Buffer").Manager; - -const tui = @import("../../tui.zig"); -const MessageFilter = @import("../../MessageFilter.zig"); -const Button = @import("../../Button.zig"); -const InputBox = @import("../../InputBox.zig"); -const Menu = @import("../../Menu.zig"); -const Widget = @import("../../Widget.zig"); -const ModalBackground = @import("../../ModalBackground.zig"); - -const Self = @This(); -const max_recent_files: usize = 25; -const widget_type: Widget.Type = .palette; - -allocator: std.mem.Allocator, -f: usize = 0, -modal: *ModalBackground.State(*Self), -menu: *MenuType, -inputbox: *InputBox.State(*Self), -logger: log.Logger, -query_pending: bool = false, -need_reset: bool = false, -need_select_first: bool = true, -longest: usize, -commands: Commands = undefined, -buffer_manager: ?*BufferManager, - -const inputbox_label = "Changed or untracked files"; -const MenuType = Menu.Options(*Self).MenuType; -const ButtonType = MenuType.ButtonType; - -pub fn create(allocator: std.mem.Allocator) !tui.Mode { - const mv = tui.mainview() orelse return error.NotFound; - const self = try allocator.create(Self); - errdefer allocator.destroy(self); - self.* = .{ - .allocator = allocator, - .modal = try ModalBackground.create(*Self, allocator, tui.mainview_widget(), .{ .ctx = self }), - .menu = try Menu.create(*Self, allocator, tui.plane(), .{ - .ctx = self, - .style = widget_type, - .on_render = on_render_menu, - .prepare_resize = prepare_resize_menu, - }), - .logger = log.logger(@typeName(Self)), - .inputbox = (try self.menu.add_header(try InputBox.create(*Self, self.allocator, self.menu.menu.parent, .{ - .ctx = self, - .label = inputbox_label, - .padding = 2, - .icon = "󰈞 ", - }))).dynamic_cast(InputBox.State(*Self)) orelse unreachable, - .buffer_manager = tui.get_buffer_manager(), - .longest = inputbox_label.len, - }; - try self.commands.init(self); - try tui.message_filters().add(MessageFilter.bind(self, receive_project_manager)); - self.query_pending = true; - try project_manager.request_new_or_modified_files(max_recent_files); - self.do_resize(); - try mv.floating_views.add(self.modal.widget()); - try mv.floating_views.add(self.menu.container_widget); - var mode = try keybind.mode("overlay/palette", allocator, .{ - .insert_command = "overlay_insert_bytes", - }); - mode.event_handler = EventHandler.to_owned(self); - mode.name = " status"; - return mode; -} - -pub fn deinit(self: *Self) void { - self.commands.deinit(); - tui.message_filters().remove_ptr(self); - if (tui.mainview()) |mv| { - mv.floating_views.remove(self.menu.container_widget); - mv.floating_views.remove(self.modal.widget()); - } - self.logger.deinit(); - self.allocator.destroy(self); -} - -inline fn menu_width(self: *Self) usize { - return @max(@min(self.longest + 3, max_menu_width()) + 5, inputbox_label.len + 2); -} - -inline fn menu_pos_x(self: *Self) usize { - const screen_width = tui.screen().w; - const width = self.menu_width(); - return if (screen_width <= width) 0 else (screen_width - width) / 2; -} - -inline fn max_menu_width() usize { - const width = tui.screen().w; - return @max(15, width - (width / 5)); -} - -fn on_render_menu(_: *Self, button: *ButtonType, theme: *const Widget.Theme, selected: bool) bool { - return tui.render_file_vcs_item_cbor(&button.plane, button.opts.label, button.active, selected, button.hover, theme); -} - -fn prepare_resize_menu(self: *Self, _: *MenuType, _: Widget.Box) Widget.Box { - return self.prepare_resize(); -} - -fn prepare_resize(self: *Self) Widget.Box { - const w = self.menu_width(); - const x = self.menu_pos_x(); - const h = self.menu.menu.widgets.items.len; - return .{ .y = 0, .x = x, .w = w, .h = h }; -} - -fn do_resize(self: *Self) void { - self.menu.resize(self.prepare_resize()); -} - -fn menu_action_open_file(menu: **MenuType, button: *ButtonType, _: Widget.Pos) void { - var file_path: []const u8 = undefined; - 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("navigate", e); - tp.self_pid().send(.{ "cmd", "navigate", .{ .file = file_path } }) catch |e| menu.*.opts.ctx.logger.err("navigate", e); -} - -fn add_item( - self: *Self, - file_name: []const u8, - file_icon: []const u8, - file_color: u24, - vcs_status: u8, - indicator: []const u8, - matches: ?[]const u8, -) !void { - var label: std.Io.Writer.Allocating = .init(self.allocator); - defer label.deinit(); - const writer = &label.writer; - try cbor.writeValue(writer, file_name); - try cbor.writeValue(writer, file_icon); - try cbor.writeValue(writer, file_color); - try cbor.writeValue(writer, indicator); - try cbor.writeValue(writer, vcs_status); - if (matches) |cb| _ = try writer.write(cb) else try cbor.writeValue(writer, &[_]usize{}); - try self.menu.add_item_with_handler(label.written(), menu_action_open_file); -} - -fn receive_project_manager(self: *Self, _: tp.pid_ref, m: tp.message) MessageFilter.Error!bool { - if (cbor.match(m.buf, .{ "PRJ", tp.more }) catch false) { - try self.process_project_manager(m); - return true; - } - return false; -} - -fn process_project_manager(self: *Self, m: tp.message) MessageFilter.Error!void { - var file_name: []const u8 = undefined; - var file_type: []const u8 = undefined; - var file_icon: []const u8 = undefined; - var file_color: u24 = undefined; - var vcs_status: u8 = undefined; - var matches: []const u8 = undefined; - var query: []const u8 = undefined; - if (try cbor.match(m.buf, .{ - "PRJ", - "new_or_modified_files", - tp.extract(&self.longest), - tp.extract(&file_name), - tp.extract(&file_type), - tp.extract(&file_icon), - tp.extract(&file_color), - tp.extract(&vcs_status), - tp.extract_cbor(&matches), - })) { - if (self.need_reset) self.reset_results(); - const indicator = if (self.buffer_manager) |bm| tui.get_file_state_indicator(bm, file_name) else ""; - try self.add_item(file_name, file_icon, file_color, vcs_status, indicator, matches); - self.do_resize(); - if (self.need_select_first) { - self.menu.select_down(); - self.need_select_first = false; - } - tui.need_render(); - } else if (try cbor.match(m.buf, .{ - "PRJ", - "new_or_modified_files", - tp.extract(&self.longest), - tp.extract(&file_name), - tp.extract(&file_type), - tp.extract(&file_icon), - tp.extract(&file_color), - tp.extract(&vcs_status), - })) { - if (self.need_reset) self.reset_results(); - const indicator = if (self.buffer_manager) |bm| tui.get_file_state_indicator(bm, file_name) else ""; - try self.add_item(file_name, file_icon, file_color, vcs_status, indicator, null); - self.do_resize(); - if (self.need_select_first) { - self.menu.select_down(); - self.need_select_first = false; - } - tui.need_render(); - } else if (try cbor.match(m.buf, .{ "PRJ", "new_or_modified_files_done", tp.extract(&self.longest), tp.extract(&query) })) { - self.query_pending = false; - self.need_reset = true; - if (!std.mem.eql(u8, self.inputbox.text.items, query)) - try self.start_query(); - } else if (try cbor.match(m.buf, .{ "PRJ", "open_done", tp.string, tp.extract(&self.longest), tp.any })) { - self.query_pending = false; - self.need_reset = true; - try self.start_query(); - } else { - self.logger.err("receive", tp.unexpected(m)); - } -} - -pub fn receive(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool { - var text: []const u8 = undefined; - - if (try m.match(.{ "system_clipboard", tp.extract(&text) })) { - self.insert_bytes(text) catch |e| return tp.exit_error(e, @errorReturnTrace()); - } - return false; -} - -fn reset_results(self: *Self) void { - self.need_reset = false; - self.menu.reset_items(); - self.menu.selected = null; - self.need_select_first = true; -} - -fn start_query(self: *Self) MessageFilter.Error!void { - if (self.query_pending) return; - self.query_pending = true; - try project_manager.query_new_or_modified_files(max_recent_files, self.inputbox.text.items); -} - -fn delete_word(self: *Self) !void { - if (std.mem.lastIndexOfAny(u8, self.inputbox.text.items, "/\\. -_")) |pos| { - self.inputbox.text.shrinkRetainingCapacity(pos); - } else { - self.inputbox.text.shrinkRetainingCapacity(0); - } - self.inputbox.cursor = tui.egc_chunk_width(self.inputbox.text.items, 0, 8); - return self.start_query(); -} - -fn delete_code_point(self: *Self) !void { - if (self.inputbox.text.items.len > 0) { - self.inputbox.text.shrinkRetainingCapacity(self.inputbox.text.items.len - tui.egc_last(self.inputbox.text.items).len); - self.inputbox.cursor = tui.egc_chunk_width(self.inputbox.text.items, 0, 8); - } - return self.start_query(); -} - -fn insert_code_point(self: *Self, c: u32) !void { - var buf: [6]u8 = undefined; - const bytes = try input.ucs32_to_utf8(&[_]u32{c}, &buf); - try self.inputbox.text.appendSlice(self.allocator, buf[0..bytes]); - self.inputbox.cursor = tui.egc_chunk_width(self.inputbox.text.items, 0, 8); - return self.start_query(); -} - -fn insert_bytes(self: *Self, bytes: []const u8) !void { - try self.inputbox.text.appendSlice(self.allocator, bytes); - self.inputbox.cursor = tui.egc_chunk_width(self.inputbox.text.items, 0, 8); - return self.start_query(); -} - -fn cmd(_: *Self, name_: []const u8, ctx: command.Context) tp.result { - try command.executeName(name_, ctx); -} - -fn msg(_: *Self, text: []const u8) tp.result { - return tp.self_pid().send(.{ "log", "home", text }); -} - -fn cmd_async(_: *Self, name_: []const u8) tp.result { - return tp.self_pid().send(.{ "cmd", name_ }); -} - -const Commands = command.Collection(cmds); -const cmds = struct { - pub const Target = Self; - const Ctx = command.Context; - const Meta = command.Metadata; - const Result = command.Result; - - pub fn palette_menu_down(self: *Self, _: Ctx) Result { - self.menu.select_down(); - } - pub const palette_menu_down_meta: Meta = .{}; - - pub fn palette_menu_up(self: *Self, _: Ctx) Result { - self.menu.select_up(); - } - pub const palette_menu_up_meta: Meta = .{}; - - pub fn palette_menu_pagedown(self: *Self, _: Ctx) Result { - self.menu.select_last(); - } - pub const palette_menu_pagedown_meta: Meta = .{}; - - pub fn palette_menu_pageup(self: *Self, _: Ctx) Result { - self.menu.select_first(); - } - pub const palette_menu_pageup_meta: Meta = .{}; - - pub fn palette_menu_bottom(self: *Self, _: Ctx) Result { - self.menu.select_last(); - } - pub const palette_menu_bottom_meta: Meta = .{}; - - pub fn palette_menu_top(self: *Self, _: Ctx) Result { - self.menu.select_first(); - } - pub const palette_menu_top_meta: Meta = .{}; - - pub fn palette_menu_activate(self: *Self, _: Ctx) Result { - self.menu.activate_selected(); - } - pub const palette_menu_activate_meta: Meta = .{}; - - pub fn palette_menu_activate_quick(self: *Self, _: Ctx) Result { - if (self.menu.selected orelse 0 > 0) self.menu.activate_selected(); - } - pub const palette_menu_activate_quick_meta: Meta = .{}; - - pub fn palette_menu_cancel(self: *Self, _: Ctx) Result { - try self.cmd("exit_overlay_mode", .{}); - } - pub const palette_menu_cancel_meta: Meta = .{}; - - pub fn overlay_delete_word_left(self: *Self, _: Ctx) Result { - self.delete_word() catch |e| return tp.exit_error(e, @errorReturnTrace()); - } - pub const overlay_delete_word_left_meta: Meta = .{ .description = "Delete word to the left" }; - - pub fn overlay_delete_backwards(self: *Self, _: Ctx) Result { - self.delete_code_point() catch |e| return tp.exit_error(e, @errorReturnTrace()); - } - pub const overlay_delete_backwards_meta: Meta = .{ .description = "Delete backwards" }; - - pub fn overlay_insert_code_point(self: *Self, ctx: Ctx) Result { - var egc: u32 = 0; - if (!try ctx.args.match(.{tp.extract(&egc)})) - return error.InvalidOpenRecentInsertCodePointArgument; - self.insert_code_point(egc) catch |e| return tp.exit_error(e, @errorReturnTrace()); - } - pub const overlay_insert_code_point_meta: Meta = .{ .arguments = &.{.integer} }; - - pub fn overlay_insert_bytes(self: *Self, ctx: Ctx) Result { - var bytes: []const u8 = undefined; - if (!try ctx.args.match(.{tp.extract(&bytes)})) - return error.InvalidOpenRecentInsertBytesArgument; - self.insert_bytes(bytes) catch |e| return tp.exit_error(e, @errorReturnTrace()); - } - pub const overlay_insert_bytes_meta: Meta = .{ .arguments = &.{.string} }; - - pub fn overlay_toggle_panel(self: *Self, _: Ctx) Result { - return self.cmd_async("toggle_panel"); - } - pub const overlay_toggle_panel_meta: Meta = .{}; - - pub fn overlay_toggle_inputview(self: *Self, _: Ctx) Result { - return self.cmd_async("toggle_inputview"); - } - pub const overlay_toggle_inputview_meta: Meta = .{}; - - pub fn overlay_next_widget_style(self: *Self, _: Ctx) Result { - tui.set_next_style(widget_type); - self.do_resize(); - tui.need_render(); - try tui.save_config(); - } - pub const overlay_next_widget_style_meta: Meta = .{}; - - pub fn mini_mode_paste(self: *Self, ctx: Ctx) Result { - return overlay_insert_bytes(self, ctx); - } - pub const mini_mode_paste_meta: Meta = .{ .arguments = &.{.string} }; -}; diff --git a/src/tui/status/branch.zig b/src/tui/status/branch.zig index ec8d7f6..140e090 100644 --- a/src/tui/status/branch.zig +++ b/src/tui/status/branch.zig @@ -56,7 +56,6 @@ pub fn ctx_deinit(self: *Self) void { fn on_click(self: *Self, _: *ButtonType, _: Widget.Pos) void { self.refresh_vcs_status(); - tui.sync_with_vcs() catch {}; command.executeName("show_vcs_status", .{}) catch {}; } diff --git a/src/tui/tui.zig b/src/tui/tui.zig index 2f050d1..8c9551c 100644 --- a/src/tui/tui.zig +++ b/src/tui/tui.zig @@ -1032,11 +1032,6 @@ const cmds = struct { } pub const open_recent_meta: Meta = .{ .description = "Open recent" }; - pub fn show_vcs_status(self: *Self, _: Ctx) Result { - return self.enter_overlay_mode(@import("mode/overlay/vcs_status.zig")); - } - pub const show_vcs_status_meta: Meta = .{ .description = "Show git status" }; - pub fn open_recent_project(_: *Self, _: Ctx) Result { try project_manager.request_recent_projects(); } @@ -1370,10 +1365,6 @@ pub fn mainview() ?*MainView { return if (current().mainview_) |*mv| mv.dynamic_cast(MainView) else null; } -pub fn sync_with_vcs() !void { - try project_manager.request_sync_with_vcs(); -} - pub fn mainview_widget() Widget { return current().mainview_ orelse @panic("tui main view not found"); } @@ -1688,15 +1679,6 @@ pub fn render_pointer(self: *renderer.Plane, selected: bool) void { _ = self.print("{s}", .{pointer}) catch {}; } -pub fn render_pointer_vcs(self: *renderer.Plane, vcs_status: u8, selected: bool) void { - const pointer = "⏵"; - if (selected) { - _ = self.print("{s}{c}", .{ pointer, vcs_status }) catch {}; - } else { - _ = self.print("{c} ", .{vcs_status}) catch {}; - } -} - pub fn render_file_item( self: *renderer.Plane, file_path_: []const u8, @@ -1760,72 +1742,6 @@ pub fn render_file_item_cbor(self: *renderer.Plane, file_item_cbor: []const u8, return render_file_item(self, file_path_, icon, color, indicator, matches_cbor, active, selected, hover, theme_); } -pub fn render_file_vcs_item( - self: *renderer.Plane, - file_path_: []const u8, - icon: []const u8, - color: u24, - indicator: []const u8, - vcs_status: u8, - matches_cbor: []const u8, - active: bool, - selected: bool, - hover: bool, - theme_: *const Widget.Theme, -) bool { - const style_base = theme_.editor_widget; - const style_label = if (active) theme_.editor_cursor else if (hover or selected) theme_.editor_selection else theme_.editor_widget; - const style_hint = if (find_scope_style(theme_, "entity.name")) |sty| sty.style else style_label; - self.set_base_style(style_base); - self.erase(); - self.home(); - self.set_style(style_label); - if (active or hover or selected) { - self.fill(" "); - self.home(); - } - - self.set_style(style_hint); - render_pointer_vcs(self, vcs_status, selected); - - const icon_width = render_file_icon(self, icon, color); - - self.set_style(style_label); - _ = self.print("{s} ", .{file_path_}) catch {}; - - self.set_style(style_hint); - _ = self.print_aligned_right(0, "{s} ", .{indicator}) catch {}; - - var iter = matches_cbor; - var index: usize = 0; - var len = cbor.decodeArrayHeader(&iter) catch return false; - while (len > 0) : (len -= 1) { - if (cbor.matchValue(&iter, cbor.extract(&index)) catch break) { - render_match_cell(self, 0, index + 2 + icon_width, theme_) catch break; - } else break; - } - return false; -} - -pub fn render_file_vcs_item_cbor(self: *renderer.Plane, file_item_cbor: []const u8, active: bool, selected: bool, hover: bool, theme_: *const Widget.Theme) bool { - var iter = file_item_cbor; - var file_path_: []const u8 = undefined; - var icon: []const u8 = undefined; - var color: u24 = undefined; - var indicator: []const u8 = undefined; - var vcs_status: u8 = undefined; - var matches_cbor: []const u8 = undefined; - - if (!(cbor.matchString(&iter, &file_path_) catch false)) @panic("invalid buffer file path"); - if (!(cbor.matchString(&iter, &icon) catch false)) @panic("invalid buffer file type icon"); - if (!(cbor.matchInt(u24, &iter, &color) catch false)) @panic("invalid buffer file type color"); - if (!(cbor.matchString(&iter, &indicator) catch false)) indicator = ""; - if (!(cbor.matchInt(u8, &iter, &vcs_status) catch false)) indicator = " "; - - if (!(cbor.matchValue(&iter, cbor.extract_cbor(&matches_cbor)) catch false)) @panic("invalid matches cbor"); - return render_file_vcs_item(self, file_path_, icon, color, indicator, vcs_status, matches_cbor, active, selected, hover, theme_); -} - fn get_or_create_theme_file(self: *Self, allocator: std.mem.Allocator) ![]const u8 { const theme_name = self.current_theme().name; if (root.read_theme(allocator, theme_name)) |content| {