parent
5f05fd97e6
commit
6946cb4010
2 changed files with 61 additions and 7 deletions
|
@ -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 = .{
|
||||||
|
|
|
@ -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 => {
|
||||||
|
|
Loading…
Add table
Reference in a new issue