diff --git a/src/keybind/builtin/flow.json b/src/keybind/builtin/flow.json index 511e230..3fc1244 100644 --- a/src/keybind/builtin/flow.json +++ b/src/keybind/builtin/flow.json @@ -196,7 +196,7 @@ ["enter", "home_menu_activate"] ] }, - "palette": { + "overlay/palette": { "press": [ ["ctrl+j", "toggle_panel"], ["ctrl+q", "quit"], diff --git a/src/keybind/builtin/helix.json b/src/keybind/builtin/helix.json index ef7d9a6..9577dae 100644 --- a/src/keybind/builtin/helix.json +++ b/src/keybind/builtin/helix.json @@ -1,4 +1,7 @@ { + "settings": { + "fallback": "vim" + }, "normal": { "syntax": "vim", "on_match_failure": "ignore", diff --git a/src/keybind/builtin/vim.json b/src/keybind/builtin/vim.json index cf481e8..2260bba 100644 --- a/src/keybind/builtin/vim.json +++ b/src/keybind/builtin/vim.json @@ -14,8 +14,8 @@ ["l", "move_right_vim"], ["h", "move_left"], ["", "move_right_vim"], - ["i", "enter_mode", "vim/insert"], - ["v", "enter_mode", "vim/visual"], + ["i", "enter_mode", "insert"], + ["v", "enter_mode", "visual"], ["/", "find"], ["n", "goto_next_match"], ["0", "move_begin"], @@ -72,17 +72,6 @@ ["", "toggle_inspector_view"], ["", "toggle_whitespace_mode"], - ["", "toggle_input_mode"], - ["", "goto_next_match"], - ["", "goto_prev_match"], - ["", "toggle_inspector_view"], - ["", "dump_current_line_tree"], - ["", "dump_current_line"], - ["", "theme_prev"], - ["", "theme_next"], - ["", "toggle_panel"], - ["", "goto_definition"], - ["", "toggle_whitespace_mode"], ["", "smart_insert_line"], ["", "delete_forward"], ["", "delete_backward"] @@ -91,8 +80,8 @@ "insert": { "syntax": "vim", "press": [ - ["jk", "enter_mode", "vim/normal"], - ["", "enter_mode", "vim/normal"], + ["jk", "enter_mode", "normal"], + ["", "enter_mode", "normal"], ["", "delete_forward"], ["", "delete_backward"] ] diff --git a/src/keybind/keybind.zig b/src/keybind/keybind.zig index 4f53140..c934b89 100644 --- a/src/keybind/keybind.zig +++ b/src/keybind/keybind.zig @@ -17,33 +17,6 @@ const KeyEvent = input.KeyEvent; const parse_flow = @import("parse_flow.zig"); const parse_vim = @import("parse_vim.zig"); -pub const mode = struct { - pub const input = struct { - pub const flow = Handler("flow", "normal"); - pub const home = Handler("flow", "home"); - pub const vim = struct { - pub const normal = Handler("vim", "normal"); - pub const insert = Handler("vim", "insert"); - pub const visual = Handler("vim", "visual"); - }; - pub const helix = struct { - pub const normal = Handler("helix", "normal"); - pub const insert = Handler("helix", "insert"); - pub const visual = Handler("helix", "select"); - }; - }; - pub const overlay = struct { - pub const palette = Handler("flow", "palette"); - }; - pub const mini = struct { - pub const goto = Handler("flow", "mini/goto"); - pub const move_to_char = Handler("flow", "mini/move_to_char"); - pub const file_browser = Handler("flow", "mini/file_browser"); - pub const find_in_files = Handler("flow", "mini/find_in_files"); - pub const find = Handler("flow", "mini/find"); - }; -}; - const builtin_keybinds = std.static_string_map.StaticStringMap([]const u8).initComptime(.{ .{ "flow", @embedFile("builtin/flow.json") }, .{ "vim", @embedFile("builtin/vim.json") }, @@ -51,35 +24,40 @@ const builtin_keybinds = std.static_string_map.StaticStringMap([]const u8).initC .{ "emacs", @embedFile("builtin/emacs.json") }, }); -fn Handler(namespace_name: []const u8, mode_name: []const u8) type { - return struct { - allocator: std.mem.Allocator, - bindings: *const BindingSet, - - pub fn create(allocator: std.mem.Allocator, opts: anytype) !struct { EventHandler, *const KeybindHints } { - const self: *@This() = try allocator.create(@This()); - self.* = .{ - .allocator = allocator, - .bindings = try get_namespace_mode( - namespace_name, - mode_name, - if (@hasField(@TypeOf(opts), "insert_command")) - opts.insert_command - else - "insert_chars", - ), - }; - return .{ EventHandler.to_owned(self), self.bindings.hints() }; - } - pub fn deinit(self: *@This()) void { - self.allocator.destroy(self); - } - pub fn receive(self: *@This(), from: tp.pid_ref, m: tp.message) error{Exit}!bool { - return self.bindings.receive(from, m); - } - }; +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 const default_mode = "normal"; +pub const default_namespace = "flow"; + +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 } { + const self: *@This() = try allocator.create(@This()); + errdefer allocator.destroy(self); + self.* = .{ + .allocator = allocator, + .bindings = try get_mode_binding_set( + mode_name, + if (@hasField(@TypeOf(opts), "insert_command")) + opts.insert_command + else + "insert_chars", + ), + }; + return .{ EventHandler.to_owned(self), self.bindings.hints() }; + } + pub fn deinit(self: *@This()) void { + self.allocator.destroy(self); + } + pub fn receive(self: *@This(), from: tp.pid_ref, m: tp.message) error{Exit}!bool { + return self.bindings.receive(from, m); + } +}; + pub const Mode = struct { input_handler: EventHandler, event_handler: ?EventHandler = null, @@ -97,16 +75,32 @@ pub const Mode = struct { const NamespaceMap = std.StringHashMapUnmanaged(Namespace); -fn get_namespace_mode(namespace_name: []const u8, mode_name: []const u8, insert_command: []const u8) LoadError!*const BindingSet { +pub fn get_namespace() []const u8 { + return current_namespace().name; +} + +fn current_namespace() *const Namespace { + return globals.current_namespace orelse @panic("no keybind namespace set"); +} + +fn get_or_load_namespace(namespace_name: []const u8) LoadError!*const Namespace { const allocator = globals_allocator; - const namespace = globals.namespaces.getPtr(namespace_name) orelse blk: { + return globals.namespaces.getPtr(namespace_name) orelse blk: { 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); result.value_ptr.* = namespace; break :blk result.value_ptr; }; - var binding_set = namespace.modes.getPtr(mode_name) orelse { +} + +pub fn set_namespace(namespace_name: []const u8) LoadError!void { + globals.current_namespace = try get_or_load_namespace(namespace_name); +} + +fn get_mode_binding_set(mode_name: []const u8, insert_command: []const u8) LoadError!*const BindingSet { + const namespace = current_namespace(); + var binding_set = namespace.get_mode(mode_name) orelse { const logger = log.logger("keybind"); logger.print_err("get_namespace_mode", "ERROR: mode not found: {s}", .{mode_name}); var iter = namespace.modes.iterator(); @@ -124,7 +118,6 @@ const LoadError = (error{ NotFound, NotAnObject } || std.json.ParseError(std.jso const Namespace = struct { name: []const u8, fallback: ?*const Namespace = null, - default_mode: []const u8, modes: std.StringHashMapUnmanaged(BindingSet), init_command: Command = .{}, @@ -144,7 +137,6 @@ const Namespace = struct { var self: @This() = .{ .name = try allocator.dupe(u8, namespace_name), - .default_mode = "", .modes = .{}, }; errdefer allocator.free(self.name); @@ -154,40 +146,61 @@ const Namespace = struct { try self.load_settings(allocator, mode_entry.value_ptr.*); } + if (!std.mem.eql(u8, self.name, default_namespace) and self.fallback == null) + self.fallback = try get_or_load_namespace(default_namespace); + var modes = parsed.value.object.iterator(); while (modes.next()) |mode_entry| { if (std.mem.eql(u8, mode_entry.key_ptr.*, "settings")) continue; try self.load_mode(allocator, mode_entry.key_ptr.*, mode_entry.value_ptr.*); } + + if (self.fallback) |fallback| { + var iter = fallback.modes.iterator(); + while (iter.next()) |entry| + if (self.get_mode(entry.key_ptr.*) == null) + try self.copy_mode(allocator, entry.key_ptr.*, entry.value_ptr); + } + + const logger = log.logger("keybind"); + logger.print("loaded namespace {s} fallback: {any} default: {s}", .{ + self.name, + self.fallback, + default_namespace, + }); + var iter = self.modes.iterator(); + while (iter.next()) |entry| logger.print("available modes: {s}", .{entry.key_ptr.*}); + logger.deinit(); + return self; } - fn load_settings(self: *@This(), allocator: std.mem.Allocator, settings_value: std.json.Value) (parse_flow.ParseError || parse_vim.ParseError || std.json.ParseFromValueError)!void { + fn load_settings(self: *@This(), allocator: std.mem.Allocator, settings_value: std.json.Value) LoadError!void { const JsonSettings = struct { init_command: []const std.json.Value = &[_]std.json.Value{}, deinit_command: []const std.json.Value = &[_]std.json.Value{}, - fallback: []const u8 = "flow", + fallback: ?[]const u8 = null, }; const parsed = try std.json.parseFromValue(JsonSettings, allocator, settings_value, .{ .ignore_unknown_fields = true, }); defer parsed.deinit(); - // self.fallback = try allocator.dupe(u8, parsed.value.fallback); + self.fallback = if (parsed.value.fallback) |fallback| try get_or_load_namespace(fallback) else null; try self.init_command.load(allocator, parsed.value.init_command); try self.deinit_command.load(allocator, parsed.value.deinit_command); } fn load_mode(self: *@This(), allocator: std.mem.Allocator, mode_name: []const u8, mode_value: std.json.Value) !void { - try self.modes.put(allocator, try allocator.dupe(u8, mode_name), try BindingSet.load(allocator, mode_value)); + 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)); } - fn get_mode(self: *@This(), mode_name: []const u8) error{}!*BindingSet { - for (self.modes.items) |*mode_| - if (std.mem.eql(u8, mode_.name, mode_name)) - return mode_; - const mode_ = try self.modes.addOne(); - mode_.* = try BindingSet.init(self.modes.allocator, mode_name); - return mode_; + fn copy_mode(self: *@This(), allocator: std.mem.Allocator, mode_name: []const u8, fallback_mode: *const BindingSet) !void { + try self.modes.put(allocator, mode_name, try BindingSet.copy(allocator, fallback_mode)); + } + + fn get_mode(self: *const @This(), mode_name: []const u8) ?*BindingSet { + return self.modes.getPtr(mode_name); } }; @@ -278,6 +291,7 @@ const max_input_buffer_size = 4096; var globals: struct { namespaces: NamespaceMap = .{}, + current_namespace: ?*const Namespace = null, input_buffer: std.ArrayListUnmanaged(u8) = .{}, insert_command: []const u8 = "", insert_command_id: ?command.ID = null, @@ -299,17 +313,9 @@ const BindingSet = struct { const KeySyntax = enum { flow, vim }; const OnMatchFailure = enum { insert, ignore }; - fn load(allocator: std.mem.Allocator, mode_bindings: std.json.Value) (error{OutOfMemory} || parse_flow.ParseError || parse_vim.ParseError || std.json.ParseFromValueError)!@This() { + 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() = .{}; - defer self.press.append(allocator, .{ - .key_events = allocator.dupe(KeyEvent, &[_]KeyEvent{.{ .key = input.key.f2 }}) catch @panic("failed to add toggle_input_mode fallback"), - .command = .{ - .command = allocator.dupe(u8, "toggle_input_mode") catch @panic("failed to add toggle_input_mode fallback"), - .args = "", - }, - }) catch {}; - const JsonConfig = struct { press: []const []const std.json.Value = &[_][]std.json.Value{}, release: []const []const std.json.Value = &[_][]std.json.Value{}, @@ -324,6 +330,10 @@ const BindingSet = struct { self.on_match_failure = parsed.value.on_match_failure; 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_| { + for (fallback_.press.items) |binding| try self.press.append(allocator, binding); + for (fallback_.release.items) |binding| try self.release.append(allocator, binding); + } self.build_hints(allocator) catch {}; return self; } @@ -401,6 +411,15 @@ const BindingSet = struct { } } + fn copy(allocator: std.mem.Allocator, fallback: *const BindingSet) error{OutOfMemory}!@This() { + var self: @This() = .{}; + 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); + self.build_hints(allocator) catch {}; + return self; + } + fn hints(self: *const @This()) *const KeybindHints { return &self.hints_map; } diff --git a/src/tui/mode/mini/file_browser.zig b/src/tui/mode/mini/file_browser.zig index 5fa94d7..e9cc1ff 100644 --- a/src/tui/mode/mini/file_browser.zig +++ b/src/tui/mode/mini/file_browser.zig @@ -48,7 +48,7 @@ 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.create(allocator, .{ + const input_handler, const keybind_hints = try keybind.mode("mini/file_browser", allocator, .{ .insert_command = "mini_mode_insert_bytes", }); return .{ diff --git a/src/tui/mode/mini/find.zig b/src/tui/mode/mini/find.zig index 1a67291..4afe73f 100644 --- a/src/tui/mode/mini/find.zig +++ b/src/tui/mode/mini/find.zig @@ -44,7 +44,7 @@ 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.create(allocator, .{ + const input_handler, const keybind_hints = try keybind.mode("mini/find", allocator, .{ .insert_command = "mini_mode_insert_bytes", }); return .{ diff --git a/src/tui/mode/mini/find_in_files.zig b/src/tui/mode/mini/find_in_files.zig index 6f77426..7536151 100644 --- a/src/tui/mode/mini/find_in_files.zig +++ b/src/tui/mode/mini/find_in_files.zig @@ -38,7 +38,7 @@ 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.create(allocator, .{ + const input_handler, const keybind_hints = try keybind.mode("mini/find_in_files", allocator, .{ .insert_command = "mini_mode_insert_bytes", }); return .{ diff --git a/src/tui/mode/mini/goto.zig b/src/tui/mode/mini/goto.zig index b28e0cb..af0ae7c 100644 --- a/src/tui/mode/mini/goto.zig +++ b/src/tui/mode/mini/goto.zig @@ -32,7 +32,7 @@ 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.create(allocator, .{ + const input_handler, const keybind_hints = try keybind.mode("mini/goto", allocator, .{ .insert_command = "mini_mode_insert_bytes", }); return .{ diff --git a/src/tui/mode/mini/move_to_char.zig b/src/tui/mode/mini/move_to_char.zig index 1884fd0..92a427b 100644 --- a/src/tui/mode/mini/move_to_char.zig +++ b/src/tui/mode/mini/move_to_char.zig @@ -41,7 +41,7 @@ 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.create(allocator, .{ + const input_handler, const keybind_hints = try keybind.mode("mini/move_to_char", allocator, .{ .insert_command = "mini_mode_insert_bytes", }); return .{ diff --git a/src/tui/mode/overlay/open_recent.zig b/src/tui/mode/overlay/open_recent.zig index f562acd..0e6fdca 100644 --- a/src/tui/mode/overlay/open_recent.zig +++ b/src/tui/mode/overlay/open_recent.zig @@ -59,7 +59,7 @@ 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.create(allocator, .{ + const input_handler, const keybind_hints = try keybind.mode("overlay/palette", allocator, .{ .insert_command = "overlay_insert_bytes", }); return .{ diff --git a/src/tui/mode/overlay/palette.zig b/src/tui/mode/overlay/palette.zig index 47b4d42..4b20deb 100644 --- a/src/tui/mode/overlay/palette.zig +++ b/src/tui/mode/overlay/palette.zig @@ -82,7 +82,7 @@ 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.create(allocator, .{ + const input_handler, const keybind_hints = try keybind.mode("overlay/palette", allocator, .{ .insert_command = "overlay_insert_bytes", }); return .{ diff --git a/src/tui/tui.zig b/src/tui/tui.zig index a6aee5b..9b1b2ea 100644 --- a/src/tui/tui.zig +++ b/src/tui/tui.zig @@ -152,8 +152,16 @@ fn init(allocator: Allocator) !*Self { fn init_delayed(self: *Self) !void { self.delayed_init_done = true; if (self.input_mode) |_| {} else { + var mode_parts = std.mem.splitScalar(u8, self.config.input_mode, '/'); + const namespace_name = mode_parts.first(); + keybind.set_namespace(namespace_name) catch { + self.logger.print_err("keybind", "unknown mode {s}", .{namespace_name}); + try keybind.set_namespace("flow"); + self.config.input_mode = "flow"; + try self.save_config(); + }; return cmds.enter_mode(self, command.Context.fmt(.{ - self.delayed_init_input_mode orelse self.config.input_mode, + self.delayed_init_input_mode orelse keybind.default_mode, })); } } @@ -575,8 +583,8 @@ fn enter_overlay_mode(self: *Self, mode: type) command.Result { self.refresh_hover(); } -fn get_input_mode(self: *Self, mode: anytype, name: []const u8, opts: anytype) !Mode { - const input_handler, const keybind_hints = try mode.create(self.allocator, opts); +fn get_input_mode(self: *Self, mode_name: []const u8, name: []const u8, opts: anytype) !Mode { + const input_handler, const keybind_hints = try keybind.mode(mode_name, self.allocator, opts); return .{ .input_handler = input_handler, .keybind_hints = keybind_hints, @@ -658,16 +666,18 @@ const cmds = struct { pub const toggle_whitespace_mode_meta = .{ .description = "Switch to next whitespace rendering mode" }; pub fn toggle_input_mode(self: *Self, _: Ctx) Result { + var it = std.mem.splitScalar(u8, self.config.input_mode, '/'); + self.config.input_mode = it.first(); self.config.input_mode = if (std.mem.eql(u8, self.config.input_mode, "flow")) - "vim/normal" - else if (std.mem.eql(u8, self.config.input_mode, "vim/normal")) - "helix/normal" + "vim" + else if (std.mem.eql(u8, self.config.input_mode, "vim")) + "helix" else "flow"; try self.save_config(); - var it = std.mem.splitScalar(u8, self.config.input_mode, '/'); - self.logger.print("input mode {s}", .{it.first()}); - return enter_mode(self, Ctx.fmt(.{self.config.input_mode})); + self.logger.print("input mode {s}", .{self.config.input_mode}); + try keybind.set_namespace(self.config.input_mode); + return enter_mode(self, Ctx.fmt(.{keybind.default_mode})); } pub const toggle_input_mode_meta = .{ .description = "Switch to next input mode" }; @@ -685,51 +695,52 @@ const cmds = struct { m.deinit(); self.input_mode = null; } - self.input_mode = if (std.mem.eql(u8, mode, "vim/normal")) - try self.get_input_mode(keybind.mode.input.vim.normal, "NORMAL", .{ + 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"); + self.input_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 (std.mem.eql(u8, mode, "vim/insert")) - try self.get_input_mode(keybind.mode.input.vim.insert, "INSERT", .{ + else if (is_vim_mode and std.mem.eql(u8, mode, "insert")) + try self.get_input_mode("insert", "INSERT", .{ .enable_chording = self.config.vim_insert_chording_keybindings, .line_numbers_relative = self.config.vim_insert_gutter_line_numbers_relative, .cursor_shape = .beam, }) - else if (std.mem.eql(u8, mode, "vim/visual")) - try self.get_input_mode(keybind.mode.input.vim.visual, "VISUAL", .{ + 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 (std.mem.eql(u8, mode, "helix/normal")) - try self.get_input_mode(keybind.mode.input.helix.normal, "NOR", .{ + 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 (std.mem.eql(u8, mode, "helix/insert")) - try self.get_input_mode(keybind.mode.input.helix.insert, "INS", .{ + 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 (std.mem.eql(u8, mode, "helix/select")) - try self.get_input_mode(keybind.mode.input.helix.visual, "SEL", .{ + 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 if (std.mem.eql(u8, mode, "flow")) - try self.get_input_mode(keybind.mode.input.flow, "flow", .{}) - else if (std.mem.eql(u8, mode, "home")) - try self.get_input_mode(keybind.mode.input.home, "flow", .{}) else ret: { - self.logger.print("unknown mode {s}", .{mode}); - break :ret try self.get_input_mode(keybind.mode.input.flow, "flow", .{}); + 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, .{}); + }; }; // self.logger.print("input mode: {s}", .{(self.input_mode orelse return).description}); } pub const enter_mode_meta = .{ .arguments = &.{.string} }; pub fn enter_mode_default(self: *Self, _: Ctx) Result { - return enter_mode(self, Ctx.fmt(.{self.config.input_mode})); + return enter_mode(self, Ctx.fmt(.{keybind.default_mode})); } pub const enter_mode_default_meta = .{};