From a74a36b4bc9817eb77b0f7f6b6a6945be2597dec Mon Sep 17 00:00:00 2001 From: Robert Burnett Date: Mon, 18 Nov 2024 09:35:26 -0600 Subject: [PATCH] feat: added some missing features to vim keybinding parser closes: #65 --- src/keybind/keybind.zig | 13 +++++- src/keybind/parse_vim.zig | 84 ++++++++++++++++++++++++++++++++++----- 2 files changed, 87 insertions(+), 10 deletions(-) diff --git a/src/keybind/keybind.zig b/src/keybind/keybind.zig index 7c8c4b2..c2ad1a6 100644 --- a/src/keybind/keybind.zig +++ b/src/keybind/keybind.zig @@ -495,11 +495,22 @@ const expectEqual = std.testing.expectEqual; const parse_test_cases = .{ //input, expected .{ "j", &.{KeyEvent{ .key = 'j' }} }, + .{ "J", &.{KeyEvent{ .key = 'j', .modifiers = input.mod.shift }} }, .{ "jk", &.{ KeyEvent{ .key = 'j' }, KeyEvent{ .key = 'k' } } }, .{ "", &.{KeyEvent{ .key = input.key.space }} }, .{ "", &.{ KeyEvent{ .key = 'x', .modifiers = input.mod.ctrl }, KeyEvent{ .key = 'c', .modifiers = input.mod.ctrl } } }, .{ "", &.{ KeyEvent{ .key = 'x', .modifiers = input.mod.alt }, KeyEvent{ .key = input.key.tab } } }, - .{ "", &.{ KeyEvent{ .key = 'x', .modifiers = input.mod.alt | input.mod.shift }, KeyEvent{ .key = input.key.delete, .modifiers = input.mod.super } } }, + .{ "", &.{ + KeyEvent{ .key = 'x', .modifiers = input.mod.alt | input.mod.shift }, + KeyEvent{ .key = input.key.delete, .modifiers = input.mod.super }, + } }, + .{ ".", &.{KeyEvent{ .key = '.' }} }, + .{ ",", &.{KeyEvent{ .key = ',' }} }, + .{ "`", &.{KeyEvent{ .key = '`' }} }, + .{ "", &.{ + KeyEvent{ .key = '-', .modifiers = input.mod.shift }, + KeyEvent{ .key = input.key.home }, + } }, }; test "parse" { diff --git a/src/keybind/parse_vim.zig b/src/keybind/parse_vim.zig index c35a6b8..99f85d4 100644 --- a/src/keybind/parse_vim.zig +++ b/src/keybind/parse_vim.zig @@ -14,10 +14,11 @@ pub const ParseError = error{ InvalidInitialCharacter, InvalidStartOfControlBinding, InvalidStartOfShiftBinding, - InvalidStartOfDeleteBinding, + InvalidStartOfDelBinding, + InvalidStartOfHomeBinding, InvalidCRBinding, InvalidSpaceBinding, - InvalidDeleteBinding, + InvalidDelBinding, InvalidTabBinding, InvalidUpBinding, InvalidEscapeBinding, @@ -29,6 +30,10 @@ pub const ParseError = error{ InvalidEscapeSequenceDelimiter, InvalidModifier, InvalidEscapeSequenceEnd, + InvalidHomeBinding, + InvalidEndBinding, + InvalidBSBinding, + InvalidInsertBinding, }; var parse_error_buf: [256]u8 = undefined; @@ -62,6 +67,10 @@ pub fn parse_key_events(allocator: std.mem.Allocator, event: input.Event, str: [ down, left, right, + home, + end, + insert, + bs, }; var state: State = .base; var function_key_number: u8 = 0; @@ -72,19 +81,29 @@ pub fn parse_key_events(allocator: std.mem.Allocator, event: input.Event, str: [ var i: usize = 0; while (i < str.len) { switch (state) { + // zig fmt: off .base => { switch (str[i]) { '<' => { state = .escape_sequence_start; i += 1; }, - 'a'...'z', '\\', '[', ']', '/', '`', '-', '=', ';', '0'...'9' => { - try result.append(.{ .event = event, .key = str[i] }); + //lowercase characters + 'a'...'z', + '0'...'9', + '`', '-', '=', '[', ']', '\\', ';', '\'', ',', '.', '/', => { + try result.append(.{ .key = str[i] }); + i += 1; + }, + //uppercase letters also allowed here + 'A'...'Z', => { + try result.append(.{ .key = std.ascii.toLower(str[i]), .modifiers = input.mod.shift}); i += 1; }, else => return parse_error(error.InvalidInitialCharacter, "str: {s}, i: {} c: {c}", .{ str, i, str[i] }), } }, + // zig fmt: on .escape_sequence_start => { switch (str[i]) { 'A' => { @@ -128,6 +147,12 @@ pub fn parse_key_events(allocator: std.mem.Allocator, event: input.Event, str: [ 'R' => { state = .right; }, + 'I' => { + state = .insert; + }, + 'B' => { + state = .bs; + }, 'E' => { state = .esc; }, @@ -142,12 +167,47 @@ pub fn parse_key_events(allocator: std.mem.Allocator, event: input.Event, str: [ 'e' => { state = .del; }, - else => return parse_error(error.InvalidStartOfDeleteBinding, "str: {s}, i: {} c: {c}", .{ str, i, str[i] }), + else => return parse_error(error.InvalidStartOfDelBinding, "str: {s}, i: {} c: {c}", .{ str, i, str[i] }), } }, - else => return parse_error(error.InvalidEscapeSequenceStart, "str: {s}, i: {} c: {c}", .{ str, i, str[i] }), + 'H' => { + state = .home; + }, + else => return parse_error(error.InvalidStartOfHomeBinding, "str: {s}, i: {} c: {c}", .{ str, i, str[i] }), } }, + .insert => { + if (std.mem.indexOf(u8, str[i..], "Insert") == 0) { + try result.append(.{ .key = input.key.insert, .modifiers = modifiers }); + modifiers = 0; + state = .escape_sequence_end; + i += 4; + } else return parse_error(error.InvalidInsertBinding, "str: {s}, i: {} c: {c}", .{ str, i, str[i] }); + }, + .end => { + if (std.mem.indexOf(u8, str[i..], "End") == 0) { + try result.append(.{ .key = input.key.end, .modifiers = modifiers }); + modifiers = 0; + state = .escape_sequence_end; + i += 3; + } else return parse_error(error.InvalidEndBinding, "str: {s}, i: {} c: {c}", .{ str, i, str[i] }); + }, + .home => { + if (std.mem.indexOf(u8, str[i..], "Home") == 0) { + try result.append(.{ .key = input.key.home, .modifiers = modifiers }); + modifiers = 0; + state = .escape_sequence_end; + i += 4; + } else return parse_error(error.InvalidHomeBinding, "str: {s}, i: {} c: {c}", .{ str, i, str[i] }); + }, + .bs => { + if (std.mem.indexOf(u8, str[i..], "BS") == 0) { + try result.append(.{ .key = input.key.backspace, .modifiers = modifiers }); + modifiers = 0; + state = .escape_sequence_end; + i += 2; + } else return parse_error(error.InvalidBSBinding, "str: {s}, i: {} c: {c}", .{ str, i, str[i] }); + }, .cr => { if (std.mem.indexOf(u8, str[i..], "CR") == 0) { try result.append(.{ .event = event, .key = input.key.enter, .modifiers = modifiers }); @@ -170,7 +230,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, event: input.Event, str: [ modifiers = 0; state = .escape_sequence_end; i += 3; - } else return parse_error(error.InvalidDeleteBinding, "str: {s}, i: {} c: {c}", .{ str, i, str[i] }); + } else return parse_error(error.InvalidDelBinding, "str: {s}, i: {} c: {c}", .{ str, i, str[i] }); }, .tab => { if (std.mem.indexOf(u8, str[i..], "Tab") == 0) { @@ -249,10 +309,15 @@ pub fn parse_key_events(allocator: std.mem.Allocator, event: input.Event, str: [ else => return parse_error(error.InvalidEscapeSequenceDelimiter, "str: {s}, i: {} c: {c}", .{ str, i, str[i] }), } }, + // zig fmt: off .char_or_key_or_modifier => { switch (str[i]) { - 'a'...'z', ';', '0'...'9' => { - try result.append(.{ .event = event, .key = str[i], .modifiers = modifiers }); + //lowercase characters only inside the escape sequence + 'a'...'z', + '0'...'9', + '`', '-', '=', '[', ']', '\\', ';', '\'', ',', '.', '/', + => { + try result.append(.{ .key = str[i], .modifiers = modifiers }); modifiers = 0; state = .escape_sequence_end; i += 1; @@ -262,6 +327,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, event: input.Event, str: [ }, } }, + // zig fmt: on .modifier => { modifiers |= switch (str[i]) { 'A' => input.mod.alt,