feat: re-add support for integer command arguments

closes #182
This commit is contained in:
CJ van den Berg 2025-04-08 18:02:39 +02:00
parent 5f05fd97e6
commit 6946cb4010
Signed by: neurocyte
GPG key ID: 8EB1E1BB660E3FB9
2 changed files with 61 additions and 7 deletions

View file

@ -25,6 +25,31 @@ const builtin_keybinds = std.static_string_map.StaticStringMap([]const u8).initC
.{ "emacs", @embedFile("builtin/emacs.json") }, .{ "emacs", @embedFile("builtin/emacs.json") },
}); });
var integer_argument: ?usize = null;
var commands: Commands = undefined;
const Commands = command.Collection(struct {
pub const Target = void;
const Ctx = command.Context;
const Meta = command.Metadata;
const Result = command.Result;
pub fn add_integer_argument_digit(_: *void, ctx: Ctx) Result {
var digit: usize = undefined;
if (!try ctx.args.match(.{tp.extract(&digit)}))
return error.InvalidIntegerParameterArgument;
if (digit > 9)
return error.InvalidIntegerParameterDigit;
integer_argument = if (integer_argument) |x| x * 10 + digit else digit;
}
pub const add_integer_argument_digit_meta: Meta = .{ .arguments = &.{.integer} };
});
pub fn init() !void {
var v: void = {};
try commands.init(&v);
}
pub fn mode(mode_name: []const u8, allocator: std.mem.Allocator, opts: anytype) !Mode { 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) { return Handler.create(mode_name, allocator, opts) catch |e| switch (e) {
error.NotFound => return error.Stop, error.NotFound => return error.Stop,
@ -86,10 +111,18 @@ pub const Mode = struct {
selection_style: SelectionStyle, selection_style: SelectionStyle,
init_command: ?Command = null, init_command: ?Command = null,
deinit_command: ?Command = null, deinit_command: ?Command = null,
initialized: bool = false,
pub fn run_init(self: *Mode) void {
if (self.initialized) return;
self.initialized = true;
clear_integer_argument();
if (self.init_command) |init_command| init_command.execute_const();
}
pub fn deinit(self: *Mode) void { pub fn deinit(self: *Mode) void {
if (self.deinit_command) |deinit_| if (self.deinit_command) |deinit_command|
deinit_.execute_const(); deinit_command.execute_const();
self.allocator.free(self.mode); self.allocator.free(self.mode);
self.input_handler.deinit(); self.input_handler.deinit();
if (self.event_handler) |eh| eh.deinit(); if (self.event_handler) |eh| eh.deinit();
@ -144,11 +177,11 @@ fn get_or_load_namespace(namespace_name: []const u8) LoadError!*const Namespace
pub fn set_namespace(namespace_name: []const u8) LoadError!void { pub fn set_namespace(namespace_name: []const u8) LoadError!void {
const new_namespace = try get_or_load_namespace(namespace_name); const new_namespace = try get_or_load_namespace(namespace_name);
if (globals.current_namespace) |old_namespace| if (globals.current_namespace) |old_namespace|
if (old_namespace.deinit_command) |deinit| if (old_namespace.deinit_command) |deinit_command|
deinit.execute_const(); deinit_command.execute_const();
globals.current_namespace = new_namespace; globals.current_namespace = new_namespace;
if (new_namespace.init_command) |init| if (new_namespace.init_command) |init_command|
init.execute_const(); init_command.execute_const();
} }
fn get_mode_binding_set(mode_name: []const u8, insert_command: []const u8) LoadError!*const BindingSet { fn get_mode_binding_set(mode_name: []const u8, insert_command: []const u8) LoadError!*const BindingSet {
@ -262,10 +295,17 @@ const Command = struct {
}; };
var buf: [2048]u8 = undefined; var buf: [2048]u8 = undefined;
@memcpy(buf[0..self.args.len], self.args); @memcpy(buf[0..self.args.len], self.args);
if (integer_argument) |int_arg| {
if (cbor.match(self.args, .{}) catch false and has_integer_argument(id)) {
integer_argument = null;
try command.execute(id, command.fmt(.{int_arg}));
return;
}
}
try command.execute(id, .{ .args = .{ .buf = buf[0..self.args.len] } }); try command.execute(id, .{ .args = .{ .buf = buf[0..self.args.len] } });
} }
pub fn execute_const(self: *const @This()) void { fn execute_const(self: *const @This()) void {
var buf: [2048]u8 = undefined; var buf: [2048]u8 = undefined;
@memcpy(buf[0..self.args.len], self.args); @memcpy(buf[0..self.args.len], self.args);
command.executeName(self.command, .{ .args = .{ .buf = buf[0..self.args.len] } }) catch |e| { command.executeName(self.command, .{ .args = .{ .buf = buf[0..self.args.len] } }) catch |e| {
@ -275,6 +315,11 @@ const Command = struct {
}; };
} }
fn has_integer_argument(id: command.ID) bool {
const args = command.get_arguments(id) orelse return false;
return args.len == 1 and args[0] == .integer;
}
fn load(allocator: std.mem.Allocator, tokens: []const std.json.Value) (parse_flow.ParseError || parse_vim.ParseError)!Command { fn load(allocator: std.mem.Allocator, tokens: []const std.json.Value) (parse_flow.ParseError || parse_vim.ParseError)!Command {
if (tokens.len == 0) return error.InvalidFormat; if (tokens.len == 0) return error.InvalidFormat;
var state: enum { command, args } = .command; var state: enum { command, args } = .command;
@ -724,6 +769,14 @@ pub fn current_key_event_sequence_fmt() KeyEventSequenceFmt {
return .{ .key_events = globals.current_sequence.items }; return .{ .key_events = globals.current_sequence.items };
} }
pub fn current_integer_argument() ?usize {
return integer_argument;
}
pub fn clear_integer_argument() void {
integer_argument = null;
}
const expectEqual = std.testing.expectEqual; const expectEqual = std.testing.expectEqual;
const parse_test_cases = .{ const parse_test_cases = .{

View file

@ -154,6 +154,7 @@ fn init(allocator: Allocator) InitError!*Self {
try frame_clock.start(); try frame_clock.start();
try self.commands.init(self); try self.commands.init(self);
try keybind.init();
errdefer self.deinit(); errdefer self.deinit();
switch (builtin.os.tag) { switch (builtin.os.tag) {
.windows => { .windows => {