diff --git a/src/tui/mainview.zig b/src/tui/mainview.zig index 6ea5bf6..2bb510e 100644 --- a/src/tui/mainview.zig +++ b/src/tui/mainview.zig @@ -579,10 +579,33 @@ const cmds = struct { } pub const create_new_file_meta: Meta = .{ .description = "New file" }; + pub fn save_buffer(self: *Self, ctx: Ctx) Result { + var file_path: []const u8 = undefined; + if (!(ctx.args.match(.{tp.extract(&file_path)}) catch false)) + return error.InvalidSaveBufferArgument; + + const buffer = self.buffer_manager.get_buffer_for_file(file_path) orelse return; + + if (self.get_active_editor()) |editor| blk: { + const editor_buffer = editor.buffer orelse break :blk; + if (buffer == editor_buffer) { + try editor.save_file(.{}); + return; + } + } + + const logger = log.logger("buffer"); + defer logger.deinit(); + if (buffer.is_ephemeral()) return logger.print_err("save", "ephemeral buffer, use save as", .{}); + if (!buffer.is_dirty()) return logger.print("no changes to save", .{}); + try buffer.store_to_file_and_clean(file_path); + } + pub const save_buffer_meta: Meta = .{ .arguments = &.{.string} }; + pub fn save_file_as(self: *Self, ctx: Ctx) Result { var file_path: []const u8 = undefined; if (!(ctx.args.match(.{tp.extract(&file_path)}) catch false)) - return error.InvalidSafeFileAsArgument; + return error.InvalidSaveFileAsArgument; if (self.get_active_editor()) |editor| { const buffer = editor.buffer orelse return; diff --git a/src/tui/status/tabs.zig b/src/tui/status/tabs.zig index c307f8e..84e7950 100644 --- a/src/tui/status/tabs.zig +++ b/src/tui/status/tabs.zig @@ -27,6 +27,8 @@ const @"style.config" = struct { dirty_indicator_fg: ?colors = null, close_icon: []const u8 = "󰅖", close_icon_fg: colors = .Error, + save_icon: []const u8 = "󰆓", + save_icon_fg: ?colors = null, spacer: []const u8 = "|", spacer_fg: colors = .active_bg, @@ -325,6 +327,7 @@ const Tab = struct { buffer_ref: usize, tab_style: *const Style, close_pos: ?c_uint = null, + save_pos: ?c_uint = null, const Mode = enum { active, inactive, selected }; @@ -356,6 +359,10 @@ const Tab = struct { tp.self_pid().send(.{ "cmd", "close_buffer", .{buffer.get_file_path()} }) catch {}; return; }; + if (self.save_pos) |save_pos| if (pos.col == save_pos) { + tp.self_pid().send(.{ "cmd", "save_buffer", .{buffer.get_file_path()} }) catch {}; + return; + }; tp.self_pid().send(.{ "cmd", "navigate", .{ .file = buffer.get_file_path() } }) catch {}; } } @@ -498,10 +505,18 @@ const Tab = struct { _ = btn.plane.putstr(btn.opts.label) catch {}; _ = btn.plane.putstr(" ") catch {}; self.close_pos = null; + self.save_pos = null; if (btn.hover) { - btn.plane.set_style(.{ .fg = self.tab_style.close_icon_fg.from_theme(theme) }); - self.close_pos = btn.plane.cursor_x(); - _ = btn.plane.putstr(self.tabbar.tab_style.close_icon) catch {}; + if (is_dirty) { + if (self.tab_style.save_icon_fg) |color| + btn.plane.set_style(.{ .fg = color.from_theme(theme) }); + self.save_pos = btn.plane.cursor_x(); + _ = btn.plane.putstr(self.tabbar.tab_style.save_icon) catch {}; + } else { + btn.plane.set_style(.{ .fg = self.tab_style.close_icon_fg.from_theme(theme) }); + self.close_pos = btn.plane.cursor_x(); + _ = btn.plane.putstr(self.tabbar.tab_style.close_icon) catch {}; + } } else if (is_dirty) { if (self.tab_style.dirty_indicator_fg) |color| btn.plane.set_style(.{ .fg = color.from_theme(theme) });