feat: add auto_save_mode option with new on_input_idle and on_focus_change modes
The original auto_save mode is now called on_document_change. The new default is on_focus_change. closes #481
This commit is contained in:
parent
1317de3f72
commit
70b60a15fa
3 changed files with 75 additions and 21 deletions
|
|
@ -33,6 +33,7 @@ follow_cursor_on_buffer_switch: bool = false, //scroll cursor into view on buffe
|
|||
default_cursor: CursorShape = .default,
|
||||
modes_can_change_cursor: bool = true,
|
||||
enable_auto_save: bool = false,
|
||||
auto_save_mode: AutoSaveMode = .on_focus_change,
|
||||
limit_auto_save_file_types: ?[]const []const u8 = null, // null means *all*
|
||||
enable_prefix_keyhints: bool = true,
|
||||
enable_auto_find: bool = true,
|
||||
|
|
@ -149,6 +150,12 @@ pub const WhitespaceMode = enum {
|
|||
none,
|
||||
};
|
||||
|
||||
pub const AutoSaveMode = enum {
|
||||
on_input_idle,
|
||||
on_focus_change,
|
||||
on_document_change,
|
||||
};
|
||||
|
||||
pub const CursorShape = enum {
|
||||
default,
|
||||
block_blink,
|
||||
|
|
|
|||
|
|
@ -649,7 +649,7 @@ pub const Editor = struct {
|
|||
self.highlight_references_pending.deinit(self.allocator);
|
||||
self.handlers.deinit();
|
||||
self.logger.deinit();
|
||||
if (self.buffer) |p| self.buffer_manager.retire(p, meta.written());
|
||||
if (self.buffer) |p| self.retire_buffer(p, meta.written());
|
||||
}
|
||||
|
||||
pub fn need_render(_: *Self) void {
|
||||
|
|
@ -697,7 +697,6 @@ pub const Editor = struct {
|
|||
defer frame.deinit();
|
||||
break :blk try self.buffer_manager.open_file(file_path);
|
||||
};
|
||||
if (tui.config().enable_auto_save) buffer.enable_auto_save();
|
||||
return self.open_buffer(file_path, buffer, null);
|
||||
}
|
||||
|
||||
|
|
@ -713,7 +712,7 @@ pub const Editor = struct {
|
|||
fn open_buffer(self: *Self, file_path: []const u8, new_buf: *Buffer, file_type_: ?[]const u8) !void {
|
||||
const frame = tracy.initZone(@src(), .{ .name = "open_buffer" });
|
||||
defer frame.deinit();
|
||||
errdefer self.buffer_manager.retire(new_buf, null);
|
||||
errdefer self.retire_buffer(new_buf, null);
|
||||
self.cancel_all_selections();
|
||||
self.get_primary().reset();
|
||||
self.file_path = try self.allocator.dupe(u8, file_path);
|
||||
|
|
@ -755,8 +754,6 @@ pub const Editor = struct {
|
|||
self.checked_formatter = false;
|
||||
self.formatter = null;
|
||||
|
||||
self.maybe_enable_auto_save();
|
||||
|
||||
const syn = blk: {
|
||||
const frame_ = tracy.initZone(@src(), .{ .name = "create" });
|
||||
defer frame_.deinit();
|
||||
|
|
@ -793,7 +790,6 @@ pub const Editor = struct {
|
|||
buffer.file_type_icon = fti;
|
||||
buffer.file_type_color = ftc;
|
||||
}
|
||||
const auto_save = if (self.buffer) |b| b.is_auto_save() and !b.is_ephemeral() else false;
|
||||
|
||||
if (buffer_meta) |meta| {
|
||||
const frame_ = tracy.initZone(@src(), .{ .name = "extract_state" });
|
||||
|
|
@ -801,24 +797,29 @@ pub const Editor = struct {
|
|||
var iter = meta;
|
||||
try self.extract_state(&iter, .none);
|
||||
}
|
||||
|
||||
const auto_save = if (self.buffer) |b|
|
||||
self.maybe_enable_buffer_auto_save(b)
|
||||
else
|
||||
false;
|
||||
|
||||
try self.send_editor_open(file_path, new_buf.file_exists, ftn, fti, ftc, auto_save);
|
||||
}
|
||||
|
||||
fn maybe_enable_auto_save(self: *Self) void {
|
||||
const buffer = self.buffer orelse return;
|
||||
if (self.restored_state) return;
|
||||
buffer.disable_auto_save();
|
||||
if (!tui.config().enable_auto_save) return;
|
||||
const self_file_type = self.file_type orelse return;
|
||||
fn maybe_enable_buffer_auto_save(self: *Self, buffer: *Buffer) bool {
|
||||
if (self.restored_state) return false;
|
||||
if (!tui.config().enable_auto_save) return false;
|
||||
const self_file_type = self.file_type orelse return false;
|
||||
|
||||
enable: {
|
||||
const file_types = tui.config().limit_auto_save_file_types orelse break :enable;
|
||||
for (file_types) |file_type|
|
||||
if (std.mem.eql(u8, file_type, self_file_type.name))
|
||||
break :enable;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
buffer.enable_auto_save();
|
||||
return !buffer.is_ephemeral();
|
||||
}
|
||||
|
||||
fn detect_indent_mode(self: *Self, content: []const u8) void {
|
||||
|
|
@ -853,11 +854,16 @@ pub const Editor = struct {
|
|||
}
|
||||
pub const set_editor_tab_width_meta: Meta = .{ .arguments = &.{.integer} };
|
||||
|
||||
fn retire_buffer(self: *const Self, buffer: *Buffer, meta: ?[]const u8) void {
|
||||
self.buffer_manager.retire(buffer, meta);
|
||||
auto_save_buffer(buffer, .on_focus_change);
|
||||
}
|
||||
|
||||
fn close(self: *Self) !void {
|
||||
var meta: std.Io.Writer.Allocating = .init(self.allocator);
|
||||
defer meta.deinit();
|
||||
self.write_state(&meta.writer) catch {};
|
||||
if (self.buffer) |b_mut| self.buffer_manager.retire(b_mut, meta.written());
|
||||
if (self.buffer) |b_mut| self.retire_buffer(b_mut, meta.written());
|
||||
self.cancel_all_selections();
|
||||
self.buffer = null;
|
||||
self.plane.erase();
|
||||
|
|
@ -2020,10 +2026,11 @@ pub const Editor = struct {
|
|||
|
||||
fn send_editor_update(self: *const Self, old_root: ?Buffer.Root, new_root: ?Buffer.Root, eol_mode: Buffer.EolMode) !void {
|
||||
_ = try self.handlers.msg(.{ "E", "update" });
|
||||
if (self.buffer) |buffer| if (self.syntax) |_| if (self.file_path) |file_path| if (old_root != null and new_root != null)
|
||||
project_manager.did_change(file_path, buffer.lsp_version, try text_from_root(new_root, eol_mode), try text_from_root(old_root, eol_mode), eol_mode) catch {};
|
||||
if (self.buffer) |b| if (b.is_auto_save() and !b.is_ephemeral())
|
||||
tp.self_pid().send(.{ "cmd", "save_file", .{} }) catch {};
|
||||
if (self.buffer) |buffer| {
|
||||
if (self.syntax) |_| if (self.file_path) |file_path| if (old_root != null and new_root != null)
|
||||
project_manager.did_change(file_path, buffer.lsp_version, try text_from_root(new_root, eol_mode), try text_from_root(old_root, eol_mode), eol_mode) catch {};
|
||||
auto_save_buffer(buffer, .on_document_change);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn vcs_content_update(self: *const Self) !void {
|
||||
|
|
@ -5547,7 +5554,10 @@ pub const Editor = struct {
|
|||
buffer.disable_auto_save();
|
||||
self.send_editor_auto_save(buffer.is_auto_save()) catch {};
|
||||
if (buffer.is_auto_save())
|
||||
tp.self_pid().send(.{ "cmd", "save_file", .{} }) catch {};
|
||||
std.log.info("enabled auto save {t}", .{tui.config().auto_save_mode})
|
||||
else
|
||||
std.log.info("disabled auto save", .{});
|
||||
auto_save_buffer(buffer, .on_document_change);
|
||||
}
|
||||
pub const toggle_auto_save_meta: Meta = .{ .description = "Toggle auto save" };
|
||||
|
||||
|
|
@ -7135,6 +7145,7 @@ pub const EditorWidget = struct {
|
|||
if (self.focused) self.commands.unregister();
|
||||
self.focused = false;
|
||||
command.executeName("enter_mode_default", .{}) catch {};
|
||||
if (self.editor.buffer) |b| auto_save_buffer(b, .on_focus_change);
|
||||
}
|
||||
|
||||
pub fn update(self: *Self) void {
|
||||
|
|
@ -7213,6 +7224,7 @@ pub const EditorWidget = struct {
|
|||
}
|
||||
},
|
||||
};
|
||||
if (self.editor.buffer) |b| auto_save_buffer(b, .on_input_idle);
|
||||
return false;
|
||||
} else if (try m.match(.{ "whitespace_mode", tp.extract(&whitespace_mode) })) {
|
||||
self.editor.render_whitespace = whitespace_mode;
|
||||
|
|
@ -7428,3 +7440,24 @@ fn ViewMap(T: type, default: T) type {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn auto_save_buffer(b: *Buffer, comptime event: @import("config").AutoSaveMode) void {
|
||||
const auto_save = switch (tui.config().auto_save_mode) {
|
||||
.on_input_idle => comptime switch (event) {
|
||||
.on_input_idle, .on_focus_change => true,
|
||||
.on_document_change => false,
|
||||
},
|
||||
.on_document_change => comptime switch (event) {
|
||||
.on_document_change => true,
|
||||
.on_input_idle, .on_focus_change => false,
|
||||
},
|
||||
.on_focus_change => comptime switch (event) {
|
||||
.on_focus_change => true,
|
||||
.on_input_idle, .on_document_change => false,
|
||||
},
|
||||
};
|
||||
if (auto_save and b.is_auto_save() and !b.is_ephemeral() and b.is_dirty()) {
|
||||
tp.self_pid().send(.{ "cmd", "save_buffer", .{ b.get_file_path(), "auto_save" } }) catch {};
|
||||
std.log.debug("auto save {t} {s}", .{ event, b.get_file_path() });
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -188,10 +188,18 @@ pub fn receive(self: *Self, from_: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
|||
} else if (try m.match(.{ "navigate_complete", tp.extract(&path), tp.extract(&goto_args), tp.null_, tp.null_ })) {
|
||||
cmds.navigate_complete(self, null, path, goto_args, null, null, null) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
return true;
|
||||
} else if (try m.match(.{"focus_out"})) {
|
||||
self.process_focus_out() catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
}
|
||||
return if (try self.floating_views.send(from_, m)) true else self.widgets.send(from_, m);
|
||||
}
|
||||
|
||||
fn process_focus_out(self: *Self) error{OutOfMemory}!void {
|
||||
const buffers = try self.buffer_manager.list_unordered(self.allocator);
|
||||
defer self.allocator.free(buffers);
|
||||
for (buffers) |b| ed.auto_save_buffer(b, .on_focus_change);
|
||||
}
|
||||
|
||||
pub fn update(self: *Self) void {
|
||||
self.widgets.update();
|
||||
self.floating_views.update();
|
||||
|
|
@ -769,8 +777,11 @@ const cmds = struct {
|
|||
pub const create_new_file_meta: Meta = .{ .description = "New file" };
|
||||
|
||||
pub fn save_buffer(self: *Self, ctx: Ctx) Result {
|
||||
var auto_save: bool = false;
|
||||
var file_path: []const u8 = undefined;
|
||||
if (!(ctx.args.match(.{tp.extract(&file_path)}) catch false))
|
||||
if (ctx.args.match(.{ tp.extract(&file_path), "auto_save" }) catch false) {
|
||||
auto_save = true;
|
||||
} else 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;
|
||||
|
|
@ -786,7 +797,10 @@ const cmds = struct {
|
|||
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", .{});
|
||||
if (!buffer.is_dirty()) {
|
||||
if (!auto_save) logger.print("no changes to save", .{});
|
||||
return;
|
||||
}
|
||||
try buffer.store_to_file_and_clean(file_path);
|
||||
}
|
||||
pub const save_buffer_meta: Meta = .{ .arguments = &.{.string} };
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue