diff --git a/src/keybind/builtin/helix.json b/src/keybind/builtin/helix.json index 728d827..331559b 100644 --- a/src/keybind/builtin/helix.json +++ b/src/keybind/builtin/helix.json @@ -67,9 +67,9 @@ ["shift+b", "move_prev_long_word_start"], ["shift+e", "move_next_long_word_end"], - ["shift+i", ["smart_move_begin"], ["enter_mode", "insert"]], - ["shift+a", ["move_end"], ["enter_mode", "insert"]], - ["shift+o", ["smart_insert_line_before"], ["enter_mode", "insert"]], + ["shift+i", ["enter_mode", "insert"], ["smart_move_begin"]], + ["shift+a", ["enter_mode", "insert"], ["move_end"]], + ["shift+o", ["enter_mode", "insert"], ["smart_insert_line_before"]], ["shift+c", "copy_selection_on_next_line"], ["shift+s", "split_selection"], @@ -143,11 +143,11 @@ ["g shift+d", "goto_declaration"], ["i", "enter_mode", "insert"], - ["a", ["move_right"], ["enter_mode", "insert"]], - ["o", ["smart_insert_line_after"], ["enter_mode", "insert"]], + ["a", ["enter_mode", "insert"], ["move_right"]], + ["o", ["enter_mode", "insert"], ["smart_insert_line_after"]], ["d", "cut_forward_internal_inclusive"], - ["c", ["cut_forward_internal_inclusive"], ["enter_mode", "insert"]], + ["c", ["enter_mode", "insert"], ["cut_forward_internal_inclusive"]], ["s", "select_regex"], [";", "collapse_selections"], @@ -240,6 +240,8 @@ "name": "INS", "line_numbers": "absolute", "cursor": "beam", + "init_command": ["pause_undo_history"], + "deinit_command": ["resume_undo_history"], "press": [ ["ctrl+u", "move_scroll_page_up"], ["ctrl+d", "move_scroll_page_down"], @@ -276,7 +278,7 @@ ["alt+`", "switch_to_uppercase"], ["alt+d", "delete_backward"], - ["alt+c", ["delete_backward"], ["enter_mode", "insert"]], + ["alt+c", ["enter_mode", "insert"], ["delete_backward"]], ["alt+s", "split_selection_on_newline"], ["alt+-", "merge_selections"], @@ -328,10 +330,10 @@ ["shift+g", "move_buffer_end_or_count_line"], - ["shift+i", ["smart_move_begin"], ["enter_mode", "insert"]], - ["shift+a", ["move_end"], ["enter_mode", "insert"]], + ["shift+i", ["enter_mode", "insert"], ["smart_move_begin"]], + ["shift+a", ["enter_mode", "insert"], ["move_end"]], - ["shift+o", ["smart_insert_line_before"], ["enter_mode", "insert"]], + ["shift+o", ["enter_mode", "insert"], ["smart_insert_line_before"]], ["shift+c", "copy_selection_on_next_line"], @@ -415,11 +417,11 @@ ["g shift+d", "goto_declaration"], ["i", "enter_mode", "insert"], - ["a", ["move_right"], ["enter_mode", "insert"]], - ["o", ["smart_insert_line_after"], ["enter_mode", "insert"]], + ["a", ["enter_mode", "insert"], ["move_right"]], + ["o", ["enter_mode", "insert"], ["smart_insert_line_after"]], ["d", "cut"], - ["c", ["cut"], ["enter_mode", "insert"]], + ["c", ["enter_mode", "insert"], ["cut"]], ["s", "select_regex"], [";", "collapse_selections"], diff --git a/src/keybind/builtin/vim.json b/src/keybind/builtin/vim.json index b112d9f..9482da5 100644 --- a/src/keybind/builtin/vim.json +++ b/src/keybind/builtin/vim.json @@ -17,7 +17,7 @@ ["B", "move_word_left"], ["e", "move_word_right_end_vim"], ["x", "cut_forward_internal"], - ["s", ["cut_forward_internal"], ["enter_mode", "insert"]], + ["s", ["enter_mode", "insert"], ["cut_forward_internal"]], ["u", "undo"], ["j", "move_down_vim"], @@ -27,11 +27,11 @@ ["", "move_right_vim"], ["i", "enter_mode", "insert"], - ["a", ["move_right"], ["enter_mode", "insert"]], - ["I", ["smart_move_begin"], ["enter_mode", "insert"]], - ["A", ["move_end"], ["enter_mode", "insert"]], - ["o", ["smart_insert_line_after"], ["enter_mode", "insert"]], - ["O", ["smart_insert_line_before"], ["enter_mode", "insert"]], + ["a", ["enter_mode", "insert"], ["move_right"]], + ["I", ["enter_mode", "insert"], ["smart_move_begin"]], + ["A", ["enter_mode", "insert"], ["move_end"]], + ["o", ["enter_mode", "insert"], ["smart_insert_line_after"]], + ["O", ["enter_mode", "insert"], ["smart_insert_line_before"]], ["", "indent"], ["", "unindent"], @@ -63,11 +63,11 @@ ["dd", "cut_internal_vim"], ["\"_dd", "delete_line"], - ["cc", ["cut_internal_vim"], ["enter_mode", "insert"]], - ["C", ["cut_to_end_vim"], ["enter_mode", "insert"]], + ["cc", ["enter_mode", "insert"], ["cut_internal_vim"]], + ["C", ["enter_mode", "insert"], ["cut_to_end_vim"]], ["D", "cut_to_end_vim"], - ["cw", ["cut_word_right_vim"], ["enter_mode", "insert"]], - ["cb", ["cut_word_left_vim"], ["enter_mode", "insert"]], + ["cw", ["enter_mode", "insert"], ["cut_word_right_vim"]], + ["cb", ["enter_mode", "insert"], ["cut_word_left_vim"]], ["yy", ["copy_line_internal_vim"], ["cancel"]], @@ -132,10 +132,10 @@ ["x", ["cut_forward_internal"], ["enter_mode", "normal"]], ["d", ["cut_forward_internal"], ["enter_mode", "normal"]], - ["s", ["cut_forward_internal"], ["enter_mode", "insert"]], + ["s", ["enter_mode", "insert"], ["cut_forward_internal"]], - ["c", ["cut_forward_internal"], ["enter_mode", "insert"]], - ["C", ["cut_to_end_vim"], ["enter_mode", "insert"]], + ["c", ["enter_mode", "insert"], ["cut_forward_internal"]], + ["C", ["enter_mode", "insert"], ["cut_to_end_vim"]], ["D", "cut_to_end_vim"] ] }, @@ -169,10 +169,10 @@ ["x", ["cut_internal_vim"], ["enter_mode", "normal"]], ["d", ["cut_internal_vim"], ["enter_mode", "normal"]], - ["s", ["cut_internal_vim"], ["enter_mode", "insert"]], + ["s", ["enter_mode", "insert"], ["cut_internal_vim"]], - ["c", ["cut_internal_vim"], ["enter_mode", "insert"]], - ["C", ["cut_to_end_vim"], ["enter_mode", "insert"]], + ["c", ["enter_mode", "insert"], ["cut_internal_vim"]], + ["C", ["enter_mode", "insert"], ["cut_to_end_vim"]], ["D", "cut_to_end_vim"] ] }, @@ -181,6 +181,8 @@ "name": "INSERT", "line_numbers": "absolute", "cursor": "beam", + "init_command": ["pause_undo_history"], + "deinit_command": ["resume_undo_history"], "press": [ ["", ["move_left_vim"], ["enter_mode", "normal"]], ["", "delete_forward"], diff --git a/src/keybind/keybind.zig b/src/keybind/keybind.zig index 2a8953a..5394792 100644 --- a/src/keybind/keybind.zig +++ b/src/keybind/keybind.zig @@ -61,6 +61,8 @@ const Handler = struct { .line_numbers = self.bindings.line_numbers, .cursor_shape = self.bindings.cursor_shape, .selection_style = self.bindings.selection_style, + .init_command = self.bindings.init_command, + .deinit_command = self.bindings.deinit_command, }; } pub fn deinit(self: *@This()) void { @@ -82,8 +84,12 @@ pub const Mode = struct { keybind_hints: *const KeybindHints, cursor_shape: ?CursorShape = null, selection_style: SelectionStyle, + init_command: ?Command = null, + deinit_command: ?Command = null, pub fn deinit(self: *Mode) void { + if (self.deinit_command) |deinit_| + deinit_.execute_const(); self.allocator.free(self.mode); self.input_handler.deinit(); if (self.event_handler) |eh| eh.deinit(); @@ -139,18 +145,10 @@ pub fn set_namespace(namespace_name: []const u8) LoadError!void { const new_namespace = try get_or_load_namespace(namespace_name); if (globals.current_namespace) |old_namespace| if (old_namespace.deinit_command) |deinit| - deinit.execute_const() catch |e| { - const logger = log.logger("keybind"); - logger.print_err("deinit_command", "ERROR: {s} {s}", .{ deinit.command, @errorName(e) }); - logger.deinit(); - }; + deinit.execute_const(); globals.current_namespace = new_namespace; if (new_namespace.init_command) |init| - init.execute_const() catch |e| { - const logger = log.logger("keybind"); - logger.print_err("init_command", "ERROR: {s} {s}", .{ init.command, @errorName(e) }); - logger.deinit(); - }; + init.execute_const(); } fn get_mode_binding_set(mode_name: []const u8, insert_command: []const u8) LoadError!*const BindingSet { @@ -267,10 +265,14 @@ const Command = struct { try command.execute(id, .{ .args = .{ .buf = buf[0..self.args.len] } }); } - fn execute_const(self: *const @This()) !void { + pub fn execute_const(self: *const @This()) void { var buf: [2048]u8 = undefined; @memcpy(buf[0..self.args.len], self.args); - try command.executeName(self.command, .{ .args = .{ .buf = buf[0..self.args.len] } }); + command.executeName(self.command, .{ .args = .{ .buf = buf[0..self.args.len] } }) catch |e| { + const logger = log.logger("keybind"); + logger.print_err("init/deinit_command", "ERROR: {s} {s}", .{ self.command, @errorName(e) }); + logger.deinit(); + }; } fn load(allocator: std.mem.Allocator, tokens: []const std.json.Value) (parse_flow.ParseError || parse_vim.ParseError)!Command { @@ -373,6 +375,8 @@ const BindingSet = struct { selection_style: SelectionStyle, insert_command: []const u8 = "", hints_map: KeybindHints = .{}, + init_command: ?Command = null, + deinit_command: ?Command = null, const KeySyntax = enum { flow, vim }; const OnMatchFailure = enum { insert, ignore }; @@ -391,6 +395,8 @@ const BindingSet = struct { inherit: ?[]const u8 = null, inherits: ?[][]const u8 = null, selection: ?SelectionStyle = null, + init_command: ?[]const std.json.Value = null, + deinit_command: ?[]const std.json.Value = null, }; const parsed = try std.json.parseFromValue(JsonConfig, allocator, mode_bindings, .{ .ignore_unknown_fields = true, @@ -402,6 +408,8 @@ const BindingSet = struct { self.line_numbers = parsed.value.line_numbers; self.cursor_shape = parsed.value.cursor; self.selection_style = parsed.value.selection orelse .normal; + if (parsed.value.init_command) |cmd| self.init_command = try Command.load(allocator, cmd); + if (parsed.value.deinit_command) |cmd| self.deinit_command = try Command.load(allocator, cmd); try self.load_event(allocator, &self.press, input.event.press, parsed.value.press); try self.load_event(allocator, &self.release, input.event.release, parsed.value.release); if (parsed.value.inherits) |sibling_fallbacks| { diff --git a/src/tui/editor.zig b/src/tui/editor.zig index ada0f81..93ee94e 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -269,6 +269,7 @@ pub const Editor = struct { buffer_manager: *Buffer.Manager, lsp_version: usize = 1, pause_undo: bool = false, + pause_undo_root: ?Buffer.Root = null, cursels: CurSel.List, cursels_saved: CurSel.List, @@ -780,11 +781,23 @@ pub const Editor = struct { pub fn pause_undo_history(self: *Self, _: Context) Result { self.pause_undo = true; + self.pause_undo_root = self.buf_root() catch return; + self.cursels_saved.clearAndFree(); + self.cursels_saved = try self.cursels.clone(); } pub const pause_undo_history_meta: Meta = .{ .description = "Pause undo history" }; pub fn resume_undo_history(self: *Self, _: Context) Result { self.pause_undo = false; + const b = self.buffer orelse return; + var sfa = std.heap.stackFallback(512, self.allocator); + const allocator = sfa.get(); + const meta = try self.store_undo_meta(allocator); + defer allocator.free(meta); + const root = self.buf_root() catch return; + if (self.pause_undo_root) |paused_root| b.update(paused_root); + try b.store_undo(meta); + b.update(root); } pub const resume_undo_history_meta: Meta = .{ .description = "Resume undo history" }; diff --git a/src/tui/tui.zig b/src/tui/tui.zig index 9339dd1..206b970 100644 --- a/src/tui/tui.zig +++ b/src/tui/tui.zig @@ -673,6 +673,8 @@ fn enter_input_mode(self: *Self, new_mode: Mode) command.Result { self.input_mode_ = null; } self.input_mode_ = new_mode; + if (new_mode.init_command) |cmd| + cmd.execute_const(); } fn refresh_input_mode(self: *Self) command.Result {