From 49319d62074c770f05db0b5861aa85031e1b8003 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Fri, 25 Oct 2024 22:40:58 +0200 Subject: [PATCH] refactor: move goto mini mode keybindings to keybind module --- build.zig | 12 +++ src/keybind/static/goto.zig | 72 ++++++++++++++++++ src/keybind/static/root.zig | 24 ++++++ src/tui/mode/mini/goto.zig | 143 +++++++++++++++++------------------- src/tui/tui.zig | 15 +--- 5 files changed, 176 insertions(+), 90 deletions(-) create mode 100644 src/keybind/static/goto.zig create mode 100644 src/keybind/static/root.zig diff --git a/build.zig b/build.zig index 6a793bb..164c71a 100644 --- a/build.zig +++ b/build.zig @@ -156,6 +156,17 @@ pub fn build(b: *std.Build) void { }, }); + const keybind_static_mod = b.createModule(.{ + .root_source_file = b.path("src/keybind/static/root.zig"), + .imports = &.{ + .{ .name = "cbor", .module = cbor_mod }, + .{ .name = "command", .module = command_mod }, + .{ .name = "EventHandler", .module = EventHandler_mod }, + .{ .name = "renderer", .module = renderer_mod }, + .{ .name = "thespian", .module = thespian_mod }, + }, + }); + const ripgrep_mod = b.createModule(.{ .root_source_file = b.path("src/ripgrep.zig"), .imports = &.{ @@ -218,6 +229,7 @@ pub fn build(b: *std.Build) void { .{ .name = "syntax", .module = syntax_mod }, .{ .name = "text_manip", .module = text_manip_mod }, .{ .name = "Buffer", .module = Buffer_mod }, + .{ .name = "keybind", .module = keybind_static_mod }, .{ .name = "ripgrep", .module = ripgrep_mod }, .{ .name = "theme", .module = themes_dep.module("theme") }, .{ .name = "themes", .module = themes_dep.module("themes") }, diff --git a/src/keybind/static/goto.zig b/src/keybind/static/goto.zig new file mode 100644 index 0000000..044b896 --- /dev/null +++ b/src/keybind/static/goto.zig @@ -0,0 +1,72 @@ +const tp = @import("thespian"); +const key = @import("renderer").input.key; +const mod = @import("renderer").input.modifier; +const event_type = @import("renderer").input.event_type; +const command = @import("command"); +const EventHandler = @import("EventHandler"); + +const Allocator = @import("std").mem.Allocator; +const fmt = @import("std").fmt; + +const Mode = @import("root.zig").Mode; + +const name = "#goto"; + +pub fn create(_: Allocator) error{OutOfMemory}!Mode { + return .{ + .handler = EventHandler.static(@This()), + .name = name, + .description = name, + }; +} + +pub fn receive(_: tp.pid_ref, m: tp.message) error{Exit}!bool { + var evtype: u32 = undefined; + var keypress: u32 = undefined; + var modifiers: u32 = undefined; + if (try m.match(.{ "I", tp.extract(&evtype), tp.extract(&keypress), tp.any, tp.string, tp.extract(&modifiers) })) + try mapEvent(evtype, keypress, modifiers); + return false; +} + +fn mapEvent(evtype: u32, keypress: u32, modifiers: u32) tp.result { + switch (evtype) { + event_type.PRESS => try mapPress(keypress, modifiers), + event_type.REPEAT => try mapPress(keypress, modifiers), + event_type.RELEASE => try mapRelease(keypress, modifiers), + else => {}, + } +} + +fn mapPress(keypress: u32, modifiers: u32) tp.result { + const keynormal = if ('a' <= keypress and keypress <= 'z') keypress - ('a' - 'A') else keypress; + return switch (modifiers) { + mod.CTRL => switch (keynormal) { + 'Q' => command.executeName("quit", .{}), + 'U' => command.executeName("mini_mode_reset", .{}), + 'G' => command.executeName("mini_mode_cancel", .{}), + 'C' => command.executeName("mini_mode_cancel", .{}), + 'L' => command.executeName("scroll_view_center", .{}), + key.SPACE => command.executeName("mini_mode_cancel", .{}), + else => {}, + }, + 0 => switch (keypress) { + key.LCTRL, key.RCTRL => command.executeName("enable_fast_scroll", .{}), + key.LALT, key.RALT => command.executeName("enable_fast_scroll", .{}), + key.ESC => command.executeName("mini_mode_cancel", .{}), + key.ENTER => command.executeName("exit_mini_mode", .{}), + key.BACKSPACE => command.executeName("mini_mode_delete_backwards", .{}), + '0'...'9' => command.executeName("mini_mode_insert_code_point", command.fmt(.{keypress})), + else => {}, + }, + else => {}, + }; +} + +fn mapRelease(keypress: u32, _: u32) tp.result { + return switch (keypress) { + key.LCTRL, key.RCTRL => command.executeName("disable_fast_scroll", .{}), + key.LALT, key.RALT => command.executeName("disable_fast_scroll", .{}), + else => {}, + }; +} diff --git a/src/keybind/static/root.zig b/src/keybind/static/root.zig new file mode 100644 index 0000000..4cc22b2 --- /dev/null +++ b/src/keybind/static/root.zig @@ -0,0 +1,24 @@ +pub const mode = struct { + pub const mini = struct { + pub const goto = @import("goto.zig"); + }; +}; + +pub const Mode = struct { + handler: EventHandler, + name: []const u8, + description: []const u8, + line_numbers: enum { absolute, relative } = .absolute, + keybind_hints: ?*const KeybindHints = null, + cursor_shape: renderer.CursorShape = .block, + + pub fn deinit(self: *Mode) void { + self.handler.deinit(); + } +}; + +pub const KeybindHints = std.static_string_map.StaticStringMap([]const u8); + +const renderer = @import("renderer"); +const EventHandler = @import("EventHandler"); +const std = @import("std"); diff --git a/src/tui/mode/mini/goto.zig b/src/tui/mode/mini/goto.zig index f7ddf44..acba191 100644 --- a/src/tui/mode/mini/goto.zig +++ b/src/tui/mode/mini/goto.zig @@ -3,11 +3,12 @@ const tp = @import("thespian"); const key = @import("renderer").input.key; const mod = @import("renderer").input.modifier; const event_type = @import("renderer").input.event_type; +const keybind = @import("keybind"); +const command = @import("command"); +const EventHandler = @import("EventHandler"); const tui = @import("../../tui.zig"); const mainview = @import("../../mainview.zig"); -const command = @import("../../command.zig"); -const EventHandler = @import("../../EventHandler.zig"); const Allocator = @import("std").mem.Allocator; const fmt = @import("std").fmt; @@ -15,10 +16,13 @@ const fmt = @import("std").fmt; const Self = @This(); const name = "#goto"; +const Commands = command.Collection(cmds); + allocator: Allocator, buf: [30]u8 = undefined, input: ?usize = null, start: usize, +commands: Commands = undefined, pub fn create(allocator: Allocator, _: command.Context) !struct { tui.Mode, tui.MiniMode } { const self: *Self = try allocator.create(Self); @@ -27,100 +31,85 @@ pub fn create(allocator: Allocator, _: command.Context) !struct { tui.Mode, tui. .allocator = allocator, .start = editor.get_primary().cursor.row + 1, }; + try self.commands.init(self); return .{ + try keybind.mode.mini.goto.create(allocator), .{ - .handler = EventHandler.to_owned(self), - .name = name, - .description = name, + .event_handler = EventHandler.to_owned(self), }, - .{}, }; }; return error.NotFound; } pub fn deinit(self: *Self) void { + self.commands.deinit(); self.allocator.destroy(self); } -pub fn receive(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool { - var evtype: u32 = undefined; - var keypress: u32 = undefined; - var modifiers: u32 = undefined; - defer { - if (tui.current().mini_mode) |*mini_mode| { - mini_mode.text = if (self.input) |linenum| - (fmt.bufPrint(&self.buf, "{d}", .{linenum}) catch "") - else - ""; - mini_mode.cursor = mini_mode.text.len; - } - } - if (try m.match(.{ "I", tp.extract(&evtype), tp.extract(&keypress), tp.any, tp.string, tp.extract(&modifiers) })) - try self.mapEvent(evtype, keypress, modifiers); +pub fn receive(_: *Self, _: tp.pid_ref, _: tp.message) error{Exit}!bool { return false; } -fn mapEvent(self: *Self, evtype: u32, keypress: u32, modifiers: u32) tp.result { - switch (evtype) { - event_type.PRESS => try self.mapPress(keypress, modifiers), - event_type.REPEAT => try self.mapPress(keypress, modifiers), - event_type.RELEASE => try self.mapRelease(keypress, modifiers), - else => {}, +fn update_mini_mode_text(self: *Self) void { + if (tui.current().mini_mode) |*mini_mode| { + mini_mode.text = if (self.input) |linenum| + (fmt.bufPrint(&self.buf, "{d}", .{linenum}) catch "") + else + ""; + mini_mode.cursor = mini_mode.text.len; } } -fn mapPress(self: *Self, keypress: u32, modifiers: u32) tp.result { - const keynormal = if ('a' <= keypress and keypress <= 'z') keypress - ('a' - 'A') else keypress; - return switch (modifiers) { - mod.CTRL => switch (keynormal) { - 'Q' => command.executeName("quit", .{}), - 'U' => self.input = null, - 'G' => self.cancel(), - 'C' => self.cancel(), - 'L' => command.executeName("scroll_view_center", .{}), - key.SPACE => self.cancel(), - else => {}, - }, - 0 => switch (keypress) { - key.LCTRL, key.RCTRL => command.executeName("enable_fast_scroll", .{}), - key.LALT, key.RALT => command.executeName("enable_fast_scroll", .{}), - key.ESC => self.cancel(), - key.ENTER => command.executeName("exit_mini_mode", .{}), - key.BACKSPACE => if (self.input) |linenum| { - const newval = if (linenum < 10) 0 else linenum / 10; - self.input = if (newval == 0) null else newval; - self.goto(); - }, - '0' => { - if (self.input) |linenum| self.input = linenum * 10; - self.goto(); - }, - '1'...'9' => { - const digit: usize = @intCast(keypress - '0'); - self.input = if (self.input) |x| x * 10 + digit else digit; - self.goto(); - }, - else => {}, - }, - else => {}, - }; -} - -fn mapRelease(_: *Self, keypress: u32, _: u32) tp.result { - return switch (keypress) { - key.LCTRL, key.RCTRL => command.executeName("disable_fast_scroll", .{}), - key.LALT, key.RALT => command.executeName("disable_fast_scroll", .{}), - else => {}, - }; -} - fn goto(self: *Self) void { command.executeName("goto_line", command.fmt(.{self.input orelse self.start})) catch {}; } -fn cancel(self: *Self) void { - self.input = null; - self.goto(); - command.executeName("exit_mini_mode", .{}) catch {}; -} +const cmds = struct { + pub const Target = Self; + const Ctx = command.Context; + const Result = command.Result; + + pub fn mini_mode_reset(self: *Self, _: Ctx) Result { + self.input = null; + self.update_mini_mode_text(); + } + pub const mini_mode_reset_meta = .{ .description = "Clear input" }; + + pub fn mini_mode_cancel(self: *Self, _: Ctx) Result { + self.input = null; + self.update_mini_mode_text(); + self.goto(); + command.executeName("exit_mini_mode", .{}) catch {}; + } + pub const mini_mode_cancel_meta = .{ .description = "Cancel input" }; + + pub fn mini_mode_delete_backwards(self: *Self, _: Ctx) Result { + if (self.input) |linenum| { + const newval = if (linenum < 10) 0 else linenum / 10; + self.input = if (newval == 0) null else newval; + self.update_mini_mode_text(); + self.goto(); + } + } + pub const mini_mode_delete_backwards_meta = .{ .description = "Delete backwards" }; + + pub fn mini_mode_insert_code_point(self: *Self, ctx: Ctx) Result { + var keypress: usize = 0; + if (!try ctx.args.match(.{tp.extract(&keypress)})) + return error.InvalidArgument; + switch (keypress) { + '0' => { + if (self.input) |linenum| self.input = linenum * 10; + }, + '1'...'9' => { + const digit: usize = @intCast(keypress - '0'); + self.input = if (self.input) |x| x * 10 + digit else digit; + }, + else => {}, + } + self.update_mini_mode_text(); + self.goto(); + } + pub const mini_mode_insert_code_point_meta = .{ .interactive = false }; +}; diff --git a/src/tui/tui.zig b/src/tui/tui.zig index 5bec5b2..91285e2 100644 --- a/src/tui/tui.zig +++ b/src/tui/tui.zig @@ -10,6 +10,7 @@ const builtin = @import("builtin"); pub const renderer = @import("renderer"); const command = @import("command"); const EventHandler = @import("EventHandler"); +const keybind = @import("keybind"); const Widget = @import("Widget.zig"); const MessageFilter = @import("MessageFilter.zig"); @@ -755,25 +756,13 @@ const cmds = struct { pub const exit_mini_mode_meta = .{ .interactive = false }; }; -pub const Mode = struct { - handler: EventHandler, - name: []const u8, - description: []const u8, - line_numbers: enum { absolute, relative } = .absolute, - keybind_hints: ?*const KeybindHints = null, - cursor_shape: renderer.CursorShape = .block, - - fn deinit(self: *Mode) void { - self.handler.deinit(); - } -}; - pub const MiniMode = struct { event_handler: ?EventHandler = null, text: []const u8 = "", cursor: ?usize = null, }; +pub const Mode = keybind.Mode; pub const KeybindHints = std.static_string_map.StaticStringMap([]const u8); threadlocal var instance_: ?*Self = null;