From 3b8982ac2638791e74e94ab679b695b46c491b09 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Tue, 3 Dec 2024 23:04:10 +0100 Subject: [PATCH] feat: move all keybind mode related options to keybind config --- src/config.zig | 3 -- src/keybind/builtin/helix.json | 9 ++++ src/keybind/builtin/vim.json | 16 ++++++++ src/keybind/keybind.zig | 44 ++++++++++++++------ src/tui/mode/mini/file_browser.zig | 14 ++----- src/tui/mode/mini/find.zig | 14 ++----- src/tui/mode/mini/find_in_files.zig | 14 ++----- src/tui/mode/mini/goto.zig | 14 ++----- src/tui/mode/mini/move_to_char.zig | 14 ++----- src/tui/mode/overlay/open_recent.zig | 11 ++--- src/tui/mode/overlay/palette.zig | 11 ++--- src/tui/tui.zig | 61 +++------------------------- 12 files changed, 85 insertions(+), 140 deletions(-) diff --git a/src/config.zig b/src/config.zig index 779eb13..b58e87e 100644 --- a/src/config.zig +++ b/src/config.zig @@ -5,9 +5,6 @@ theme: []const u8 = "default", input_mode: []const u8 = "flow", gutter_line_numbers: bool = true, gutter_line_numbers_relative: bool = false, -vim_normal_gutter_line_numbers_relative: bool = true, -vim_visual_gutter_line_numbers_relative: bool = true, -vim_insert_gutter_line_numbers_relative: bool = false, enable_terminal_cursor: bool = true, enable_terminal_color_scheme: bool = builtin.os.tag != .windows, highlight_current_line: bool = true, diff --git a/src/keybind/builtin/helix.json b/src/keybind/builtin/helix.json index 32ca62a..585534f 100644 --- a/src/keybind/builtin/helix.json +++ b/src/keybind/builtin/helix.json @@ -5,6 +5,9 @@ }, "normal": { "on_match_failure": "ignore", + "name": "NOR", + "line_numbers": "relative", + "cursor": "block", "press": [ ["ctrl+b", "move_scroll_page_up"], ["ctrl+f", "move_scroll_page_down"], @@ -232,6 +235,9 @@ ] }, "insert": { + "name": "INS", + "line_numbers": "absolute", + "cursor": "beam", "press": [ ["ctrl+u", "move_scroll_page_up"], ["ctrl+d", "move_scroll_page_down"], @@ -242,6 +248,9 @@ ] }, "select": { + "name": "SEL", + "line_numbers": "relative", + "cursor": "block", "press": [ ["ctrl+b", "move_scroll_page_up"], ["ctrl+f", "move_scroll_page_down"], diff --git a/src/keybind/builtin/vim.json b/src/keybind/builtin/vim.json index 66d6de0..b5f4890 100644 --- a/src/keybind/builtin/vim.json +++ b/src/keybind/builtin/vim.json @@ -6,6 +6,9 @@ "normal": { "syntax": "vim", "on_match_failure": "ignore", + "name": "NORMAL", + "line_numbers": "relative", + "cursor": "block", "press": [ ["b", "move_word_left"], ["w", "move_word_right_vim"], @@ -63,8 +66,21 @@ ["", "smart_insert_line"] ] }, + "visual": { + "syntax": "vim", + "on_match_failure": "ignore", + "name": "VISUAL", + "line_numbers": "relative", + "cursor": "underline", + "press": [ + ["", "enter_mode", "normal"], + ] + }, "insert": { "syntax": "vim", + "name": "INSERT", + "line_numbers": "absolute", + "cursor": "beam", "press": [ ["jk", "enter_mode", "normal"], ["", "enter_mode", "normal"], diff --git a/src/keybind/keybind.zig b/src/keybind/keybind.zig index 9e7a8fb..cb2712e 100644 --- a/src/keybind/keybind.zig +++ b/src/keybind/keybind.zig @@ -24,8 +24,11 @@ const builtin_keybinds = std.static_string_map.StaticStringMap([]const u8).initC .{ "emacs", @embedFile("builtin/emacs.json") }, }); -pub fn mode(mode_name: []const u8, allocator: std.mem.Allocator, opts: anytype) !struct { EventHandler, *const KeybindHints } { - return Handler.create(mode_name, allocator, opts); +pub fn mode(mode_name: []const u8, allocator: std.mem.Allocator, opts: anytype) !Mode { + return Handler.create(mode_name, allocator, opts) catch |e| switch (e) { + error.NotFound => return error.Stop, + else => return e, + }; } pub const default_mode = "normal"; @@ -35,7 +38,7 @@ const Handler = struct { allocator: std.mem.Allocator, bindings: *const BindingSet, - fn create(mode_name: []const u8, allocator: std.mem.Allocator, opts: anytype) !struct { EventHandler, *const KeybindHints } { + fn create(mode_name: []const u8, allocator: std.mem.Allocator, opts: anytype) !Mode { const self: *@This() = try allocator.create(@This()); errdefer allocator.destroy(self); self.* = .{ @@ -48,7 +51,13 @@ const Handler = struct { "insert_chars", ), }; - return .{ EventHandler.to_owned(self), self.bindings.hints() }; + return .{ + .input_handler = EventHandler.to_owned(self), + .keybind_hints = self.bindings.hints(), + .name = self.bindings.name, + .line_numbers = self.bindings.line_numbers, + .cursor_shape = self.bindings.cursor_shape, + }; } pub fn deinit(self: *@This()) void { self.allocator.destroy(self); @@ -63,7 +72,7 @@ pub const Mode = struct { event_handler: ?EventHandler = null, name: []const u8 = "", - line_numbers: enum { absolute, relative } = .absolute, + line_numbers: LineNumbers = .absolute, keybind_hints: *const KeybindHints, cursor_shape: CursorShape = .block, @@ -110,9 +119,6 @@ fn current_namespace() *const Namespace { fn get_or_load_namespace(namespace_name: []const u8) LoadError!*const Namespace { const allocator = globals_allocator; return globals.namespaces.getPtr(namespace_name) orelse blk: { - const logger = log.logger("keybind"); - logger.print("loading namespace '{s}'", .{namespace_name}); - defer logger.deinit(); const namespace = try Namespace.load(allocator, namespace_name); const result = try globals.namespaces.getOrPut(allocator, try allocator.dupe(u8, namespace_name)); std.debug.assert(result.found_existing == false); @@ -222,7 +228,7 @@ const Namespace = struct { fn load_mode(self: *@This(), allocator: std.mem.Allocator, mode_name: []const u8, mode_value: std.json.Value) !void { const fallback_mode = if (self.fallback) |fallback| fallback.get_mode(mode_name) orelse fallback.get_mode(default_mode) else null; - try self.modes.put(allocator, try allocator.dupe(u8, mode_name), try BindingSet.load(allocator, mode_value, fallback_mode)); + try self.modes.put(allocator, try allocator.dupe(u8, mode_name), try BindingSet.load(allocator, self.name, mode_value, fallback_mode)); } fn copy_mode(self: *@This(), allocator: std.mem.Allocator, mode_name: []const u8, fallback_mode: *const BindingSet) !void { @@ -349,20 +355,26 @@ const BindingSet = struct { release: std.ArrayListUnmanaged(Binding) = .{}, syntax: KeySyntax = .flow, on_match_failure: OnMatchFailure = .ignore, + name: []const u8, + line_numbers: LineNumbers = .absolute, + cursor_shape: CursorShape = .block, insert_command: []const u8 = "", hints_map: KeybindHints = .{}, const KeySyntax = enum { flow, vim }; const OnMatchFailure = enum { insert, ignore }; - fn load(allocator: std.mem.Allocator, mode_bindings: std.json.Value, fallback: ?*const BindingSet) (error{OutOfMemory} || parse_flow.ParseError || parse_vim.ParseError || std.json.ParseFromValueError)!@This() { - var self: @This() = .{}; + fn load(allocator: std.mem.Allocator, namespace_name: []const u8, mode_bindings: std.json.Value, fallback: ?*const BindingSet) (error{OutOfMemory} || parse_flow.ParseError || parse_vim.ParseError || std.json.ParseFromValueError)!@This() { + var self: @This() = .{ .name = undefined }; const JsonConfig = struct { press: []const []const std.json.Value = &[_][]std.json.Value{}, release: []const []const std.json.Value = &[_][]std.json.Value{}, syntax: KeySyntax = .flow, on_match_failure: OnMatchFailure = .insert, + name: ?[]const u8 = null, + line_numbers: LineNumbers = .absolute, + cursor: CursorShape = .block, }; const parsed = try std.json.parseFromValue(JsonConfig, allocator, mode_bindings, .{ .ignore_unknown_fields = true, @@ -370,6 +382,9 @@ const BindingSet = struct { defer parsed.deinit(); self.syntax = parsed.value.syntax; self.on_match_failure = parsed.value.on_match_failure; + self.name = try allocator.dupe(u8, parsed.value.name orelse namespace_name); + self.line_numbers = parsed.value.line_numbers; + self.cursor_shape = parsed.value.cursor; 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 (fallback) |fallback_| { @@ -439,7 +454,7 @@ const BindingSet = struct { } fn copy(allocator: std.mem.Allocator, fallback: *const BindingSet) error{OutOfMemory}!@This() { - var self: @This() = .{}; + var self: @This() = .{ .name = fallback.name }; self.on_match_failure = fallback.on_match_failure; for (fallback.press.items) |binding| try self.press.append(allocator, binding); for (fallback.release.items) |binding| try self.release.append(allocator, binding); @@ -624,6 +639,11 @@ const BindingSet = struct { } }; +pub const LineNumbers = enum { + absolute, + relative, +}; + pub const CursorShape = enum { default, block_blink, diff --git a/src/tui/mode/mini/file_browser.zig b/src/tui/mode/mini/file_browser.zig index e9cc1ff..b91739e 100644 --- a/src/tui/mode/mini/file_browser.zig +++ b/src/tui/mode/mini/file_browser.zig @@ -48,19 +48,11 @@ pub fn Create(options: type) type { try options.load_entries(self); if (@hasDecl(options, "restore_state")) options.restore_state(self) catch {}; - const input_handler, const keybind_hints = try keybind.mode("mini/file_browser", allocator, .{ + var mode = try keybind.mode("mini/file_browser", allocator, .{ .insert_command = "mini_mode_insert_bytes", }); - return .{ - .{ - .input_handler = input_handler, - .event_handler = EventHandler.to_owned(self), - .keybind_hints = keybind_hints, - }, - .{ - .name = options.name(self), - }, - }; + mode.event_handler = EventHandler.to_owned(self); + return .{ mode, .{ .name = options.name(self) } }; } pub fn deinit(self: *Self) void { diff --git a/src/tui/mode/mini/find.zig b/src/tui/mode/mini/find.zig index 4afe73f..88913d0 100644 --- a/src/tui/mode/mini/find.zig +++ b/src/tui/mode/mini/find.zig @@ -44,19 +44,11 @@ pub fn create(allocator: Allocator, _: command.Context) !struct { tui.Mode, tui. defer self.allocator.free(text); try self.input.appendSlice(text); } - const input_handler, const keybind_hints = try keybind.mode("mini/find", allocator, .{ + var mode = try keybind.mode("mini/find", allocator, .{ .insert_command = "mini_mode_insert_bytes", }); - return .{ - .{ - .input_handler = input_handler, - .event_handler = EventHandler.to_owned(self), - .keybind_hints = keybind_hints, - }, - .{ - .name = name, - }, - }; + mode.event_handler = EventHandler.to_owned(self); + return .{ mode, .{ .name = name } }; }; return error.NotFound; } diff --git a/src/tui/mode/mini/find_in_files.zig b/src/tui/mode/mini/find_in_files.zig index 7536151..f945dfb 100644 --- a/src/tui/mode/mini/find_in_files.zig +++ b/src/tui/mode/mini/find_in_files.zig @@ -38,19 +38,11 @@ pub fn create(allocator: Allocator, _: command.Context) !struct { tui.Mode, tui. @memcpy(self.buf[0..text.len], text); self.input = self.buf[0..text.len]; }; - const input_handler, const keybind_hints = try keybind.mode("mini/find_in_files", allocator, .{ + var mode = try keybind.mode("mini/find_in_files", allocator, .{ .insert_command = "mini_mode_insert_bytes", }); - return .{ - .{ - .input_handler = input_handler, - .event_handler = EventHandler.to_owned(self), - .keybind_hints = keybind_hints, - }, - .{ - .name = name, - }, - }; + mode.event_handler = EventHandler.to_owned(self); + return .{ mode, .{ .name = name } }; } return error.NotFound; } diff --git a/src/tui/mode/mini/goto.zig b/src/tui/mode/mini/goto.zig index af0ae7c..71a7606 100644 --- a/src/tui/mode/mini/goto.zig +++ b/src/tui/mode/mini/goto.zig @@ -32,19 +32,11 @@ pub fn create(allocator: Allocator, _: command.Context) !struct { tui.Mode, tui. .start = editor.get_primary().cursor.row + 1, }; try self.commands.init(self); - const input_handler, const keybind_hints = try keybind.mode("mini/goto", allocator, .{ + var mode = try keybind.mode("mini/goto", allocator, .{ .insert_command = "mini_mode_insert_bytes", }); - return .{ - .{ - .input_handler = input_handler, - .event_handler = EventHandler.to_owned(self), - .keybind_hints = keybind_hints, - }, - .{ - .name = name, - }, - }; + mode.event_handler = EventHandler.to_owned(self); + return .{ mode, .{ .name = name } }; }; return error.NotFound; } diff --git a/src/tui/mode/mini/move_to_char.zig b/src/tui/mode/mini/move_to_char.zig index 92a427b..2c21cb3 100644 --- a/src/tui/mode/mini/move_to_char.zig +++ b/src/tui/mode/mini/move_to_char.zig @@ -41,19 +41,11 @@ pub fn create(allocator: Allocator, ctx: command.Context) !struct { tui.Mode, tu .operation = if (select) .select else .move, }; try self.commands.init(self); - const input_handler, const keybind_hints = try keybind.mode("mini/move_to_char", allocator, .{ + var mode = try keybind.mode("mini/move_to_char", allocator, .{ .insert_command = "mini_mode_insert_bytes", }); - return .{ - .{ - .input_handler = input_handler, - .event_handler = EventHandler.to_owned(self), - .keybind_hints = keybind_hints, - }, - .{ - .name = self.name(), - }, - }; + mode.event_handler = EventHandler.to_owned(self); + return .{ mode, .{ .name = self.name() } }; } pub fn deinit(self: *Self) void { diff --git a/src/tui/mode/overlay/open_recent.zig b/src/tui/mode/overlay/open_recent.zig index 0e6fdca..4a01e02 100644 --- a/src/tui/mode/overlay/open_recent.zig +++ b/src/tui/mode/overlay/open_recent.zig @@ -59,15 +59,12 @@ pub fn create(allocator: std.mem.Allocator) !tui.Mode { self.menu.resize(.{ .y = 0, .x = self.menu_pos_x(), .w = max_menu_width() + 2 }); try mv.floating_views.add(self.modal.widget()); try mv.floating_views.add(self.menu.container_widget); - const input_handler, const keybind_hints = try keybind.mode("overlay/palette", allocator, .{ + var mode = try keybind.mode("overlay/palette", allocator, .{ .insert_command = "overlay_insert_bytes", }); - return .{ - .input_handler = input_handler, - .event_handler = EventHandler.to_owned(self), - .keybind_hints = keybind_hints, - .name = "󰈞 open recent", - }; + mode.event_handler = EventHandler.to_owned(self); + mode.name = "󰈞 open recent"; + return mode; } pub fn deinit(self: *Self) void { diff --git a/src/tui/mode/overlay/palette.zig b/src/tui/mode/overlay/palette.zig index 4b20deb..80c2819 100644 --- a/src/tui/mode/overlay/palette.zig +++ b/src/tui/mode/overlay/palette.zig @@ -82,15 +82,12 @@ pub fn Create(options: type) type { try self.start_query(); try mv.floating_views.add(self.modal.widget()); try mv.floating_views.add(self.menu.container_widget); - const input_handler, const keybind_hints = try keybind.mode("overlay/palette", allocator, .{ + var mode = try keybind.mode("overlay/palette", allocator, .{ .insert_command = "overlay_insert_bytes", }); - return .{ - .input_handler = input_handler, - .event_handler = EventHandler.to_owned(self), - .keybind_hints = keybind_hints, - .name = options.name, - }; + mode.event_handler = EventHandler.to_owned(self); + mode.name = options.name; + return mode; } pub fn deinit(self: *Self) void { diff --git a/src/tui/tui.zig b/src/tui/tui.zig index 41d80d7..9bf45e4 100644 --- a/src/tui/tui.zig +++ b/src/tui/tui.zig @@ -583,24 +583,8 @@ fn enter_overlay_mode(self: *Self, mode: type) command.Result { self.refresh_hover(); } -fn get_input_mode(self: *Self, mode_name: []const u8, name: []const u8, opts: anytype) !Mode { - const input_handler, const keybind_hints = keybind.mode(mode_name, self.allocator, opts) catch |e| switch (e) { - error.NotFound => return error.Stop, - else => return e, - }; - return .{ - .input_handler = input_handler, - .keybind_hints = keybind_hints, - .name = name, - .line_numbers = if (@hasField(@TypeOf(opts), "line_numbers_relative")) - if (opts.line_numbers_relative) - .relative - else - .absolute - else - .absolute, - .cursor_shape = if (@hasField(@TypeOf(opts), "cursor_shape")) opts.cursor_shape else .block, - }; +fn get_input_mode(self: *Self, mode_name: []const u8) !Mode { + return keybind.mode(mode_name, self.allocator, .{}); } const cmds = struct { @@ -700,44 +684,9 @@ const cmds = struct { return; } - const current_namespace = keybind.get_namespace(); - const is_vim_mode = std.mem.eql(u8, current_namespace, "vim"); - const is_helix_mode = std.mem.eql(u8, current_namespace, "helix"); - var new_mode = if (is_vim_mode and std.mem.eql(u8, mode, "normal")) - try self.get_input_mode("normal", "NORMAL", .{ - .line_numbers_relative = self.config.vim_normal_gutter_line_numbers_relative, - .cursor_shape = .block, - }) - else if (is_vim_mode and std.mem.eql(u8, mode, "insert")) - try self.get_input_mode("insert", "INSERT", .{ - .line_numbers_relative = self.config.vim_insert_gutter_line_numbers_relative, - .cursor_shape = .beam, - }) - else if (is_vim_mode and std.mem.eql(u8, mode, "visual")) - try self.get_input_mode("visual", "VISUAL", .{ - .line_numbers_relative = self.config.vim_visual_gutter_line_numbers_relative, - .cursor_shape = .underline, - }) - else if (is_helix_mode and std.mem.eql(u8, mode, "normal")) - try self.get_input_mode("normal", "NOR", .{ - .line_numbers_relative = self.config.vim_normal_gutter_line_numbers_relative, - .cursor_shape = .block, - }) - else if (is_helix_mode and std.mem.eql(u8, mode, "insert")) - try self.get_input_mode("insert", "INS", .{ - .line_numbers_relative = self.config.vim_insert_gutter_line_numbers_relative, - .cursor_shape = .beam, - }) - else if (is_helix_mode and std.mem.eql(u8, mode, "select")) - try self.get_input_mode("visual", "SEL", .{ - .line_numbers_relative = self.config.vim_visual_gutter_line_numbers_relative, - .cursor_shape = .block, - }) - else ret: { - break :ret self.get_input_mode(mode, current_namespace, .{}) catch { - self.logger.print("unknown mode {s}", .{mode}); - break :ret try self.get_input_mode(keybind.default_mode, current_namespace, .{}); - }; + var new_mode = self.get_input_mode(mode) catch ret: { + self.logger.print("unknown mode {s}", .{mode}); + break :ret try self.get_input_mode(keybind.default_mode); }; errdefer new_mode.deinit();