feat: add support for key release dynamic bindings
This commit is contained in:
parent
a8826b5067
commit
932409d6b7
5 changed files with 96 additions and 46 deletions
|
@ -139,7 +139,8 @@ const Hint = struct {
|
||||||
//A Collection of keybindings
|
//A Collection of keybindings
|
||||||
const BindingSet = struct {
|
const BindingSet = struct {
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
bindings: std.ArrayList(Binding),
|
press: std.ArrayList(Binding),
|
||||||
|
release: std.ArrayList(Binding),
|
||||||
syntax: KeySyntax = .flow,
|
syntax: KeySyntax = .flow,
|
||||||
on_match_failure: OnMatchFailure = .ignore,
|
on_match_failure: OnMatchFailure = .ignore,
|
||||||
current_sequence: std.ArrayList(KeyEvent),
|
current_sequence: std.ArrayList(KeyEvent),
|
||||||
|
@ -183,7 +184,8 @@ const BindingSet = struct {
|
||||||
.current_sequence_egc = try std.ArrayList(u8).initCapacity(allocator, 16),
|
.current_sequence_egc = try std.ArrayList(u8).initCapacity(allocator, 16),
|
||||||
.last_key_event_timestamp_ms = std.time.milliTimestamp(),
|
.last_key_event_timestamp_ms = std.time.milliTimestamp(),
|
||||||
.input_buffer = try std.ArrayList(u8).initCapacity(allocator, 16),
|
.input_buffer = try std.ArrayList(u8).initCapacity(allocator, 16),
|
||||||
.bindings = std.ArrayList(Binding).init(allocator),
|
.press = std.ArrayList(Binding).init(allocator),
|
||||||
|
.release = std.ArrayList(Binding).init(allocator),
|
||||||
.logger = if (!builtin.is_test) log.logger("keybind") else undefined,
|
.logger = if (!builtin.is_test) log.logger("keybind") else undefined,
|
||||||
.namespace_name = try allocator.dupe(u8, namespace_name),
|
.namespace_name = try allocator.dupe(u8, namespace_name),
|
||||||
.mode_name = try allocator.dupe(u8, mode_name),
|
.mode_name = try allocator.dupe(u8, mode_name),
|
||||||
|
@ -194,8 +196,10 @@ const BindingSet = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deinit(self: *const BindingSet) void {
|
fn deinit(self: *const BindingSet) void {
|
||||||
for (self.bindings.items) |binding| binding.deinit(self.allocator);
|
for (self.press.items) |binding| binding.deinit(self.allocator);
|
||||||
self.bindings.deinit();
|
self.press.deinit();
|
||||||
|
for (self.release.items) |binding| binding.deinit(self.allocator);
|
||||||
|
self.release.deinit();
|
||||||
self.current_sequence.deinit();
|
self.current_sequence.deinit();
|
||||||
self.current_sequence_egc.deinit();
|
self.current_sequence_egc.deinit();
|
||||||
self.input_buffer.deinit();
|
self.input_buffer.deinit();
|
||||||
|
@ -206,7 +210,7 @@ const BindingSet = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_json(self: *@This(), json_string: []const u8, namespace_name: []const u8, mode_name: []const u8) !void {
|
fn load_json(self: *@This(), json_string: []const u8, namespace_name: []const u8, mode_name: []const u8) !void {
|
||||||
defer self.bindings.append(.{
|
defer self.press.append(.{
|
||||||
.keys = self.allocator.dupe(KeyEvent, &[_]KeyEvent{.{ .key = input.key.f2 }}) catch @panic("failed to add toggle_input_mode fallback"),
|
.keys = self.allocator.dupe(KeyEvent, &[_]KeyEvent{.{ .key = input.key.f2 }}) catch @panic("failed to add toggle_input_mode fallback"),
|
||||||
.command = self.allocator.dupe(u8, "toggle_input_mode") catch @panic("failed to add toggle_input_mode fallback"),
|
.command = self.allocator.dupe(u8, "toggle_input_mode") catch @panic("failed to add toggle_input_mode fallback"),
|
||||||
.args = "",
|
.args = "",
|
||||||
|
@ -228,7 +232,8 @@ const BindingSet = struct {
|
||||||
|
|
||||||
fn load_set_from_json(self: *BindingSet, mode_bindings: std.json.Value) (parse_flow.ParseError || parse_vim.ParseError || std.json.ParseFromValueError)!void {
|
fn load_set_from_json(self: *BindingSet, mode_bindings: std.json.Value) (parse_flow.ParseError || parse_vim.ParseError || std.json.ParseFromValueError)!void {
|
||||||
const JsonConfig = struct {
|
const JsonConfig = struct {
|
||||||
bindings: []const []const std.json.Value,
|
press: []const []const std.json.Value = &[_][]std.json.Value{},
|
||||||
|
release: []const []const std.json.Value = &[_][]std.json.Value{},
|
||||||
syntax: KeySyntax = .flow,
|
syntax: KeySyntax = .flow,
|
||||||
on_match_failure: OnMatchFailure = .insert,
|
on_match_failure: OnMatchFailure = .insert,
|
||||||
};
|
};
|
||||||
|
@ -238,7 +243,12 @@ const BindingSet = struct {
|
||||||
defer parsed.deinit();
|
defer parsed.deinit();
|
||||||
self.syntax = parsed.value.syntax;
|
self.syntax = parsed.value.syntax;
|
||||||
self.on_match_failure = parsed.value.on_match_failure;
|
self.on_match_failure = parsed.value.on_match_failure;
|
||||||
bindings: for (parsed.value.bindings) |entry| {
|
try self.load_bindings_from_json(&self.press, input.event.press, parsed.value.press);
|
||||||
|
try self.load_bindings_from_json(&self.release, input.event.release, parsed.value.release);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_bindings_from_json(self: *BindingSet, dest: *std.ArrayList(Binding), event: input.Event, bindings: []const []const std.json.Value) (parse_flow.ParseError || parse_vim.ParseError)!void {
|
||||||
|
bindings: for (bindings) |entry| {
|
||||||
var state: enum { key_event, command, args } = .key_event;
|
var state: enum { key_event, command, args } = .key_event;
|
||||||
var keys: ?[]KeyEvent = null;
|
var keys: ?[]KeyEvent = null;
|
||||||
var command_: ?[]const u8 = null;
|
var command_: ?[]const u8 = null;
|
||||||
|
@ -260,11 +270,11 @@ const BindingSet = struct {
|
||||||
continue :bindings;
|
continue :bindings;
|
||||||
}
|
}
|
||||||
keys = switch (self.syntax) {
|
keys = switch (self.syntax) {
|
||||||
.flow => parse_flow.parse_key_events(self.allocator, token.string) catch |e| {
|
.flow => parse_flow.parse_key_events(self.allocator, event, token.string) catch |e| {
|
||||||
self.logger.print_err("keybind.load", "ERROR: {s} {s}", .{ @errorName(e), parse_flow.parse_error_message });
|
self.logger.print_err("keybind.load", "ERROR: {s} {s}", .{ @errorName(e), parse_flow.parse_error_message });
|
||||||
break;
|
break;
|
||||||
},
|
},
|
||||||
.vim => parse_vim.parse_key_events(self.allocator, token.string) catch |e| {
|
.vim => parse_vim.parse_key_events(self.allocator, event, token.string) catch |e| {
|
||||||
self.logger.print_err("keybind.load.vim", "ERROR: {s} {s}", .{ @errorName(e), parse_vim.parse_error_message });
|
self.logger.print_err("keybind.load.vim", "ERROR: {s} {s}", .{ @errorName(e), parse_vim.parse_error_message });
|
||||||
break;
|
break;
|
||||||
},
|
},
|
||||||
|
@ -298,7 +308,7 @@ const BindingSet = struct {
|
||||||
try cbor.writeArrayHeader(writer, args.items.len);
|
try cbor.writeArrayHeader(writer, args.items.len);
|
||||||
for (args.items) |arg| try cbor.writeJsonValue(writer, arg);
|
for (args.items) |arg| try cbor.writeJsonValue(writer, arg);
|
||||||
|
|
||||||
try self.bindings.append(.{
|
try dest.append(.{
|
||||||
.keys = keys.?,
|
.keys = keys.?,
|
||||||
.command = command_.?,
|
.command = command_.?,
|
||||||
.args = try args_cbor.toOwnedSlice(self.allocator),
|
.args = try args_cbor.toOwnedSlice(self.allocator),
|
||||||
|
@ -363,10 +373,18 @@ const BindingSet = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
//register a key press and try to match it with a binding
|
//register a key press and try to match it with a binding
|
||||||
fn process_key_event(self: *BindingSet, egc: input.Key, event: KeyEvent) !?*Binding {
|
fn process_key_event(self: *BindingSet, egc: input.Key, event_: KeyEvent) !?*Binding {
|
||||||
|
var event = event_;
|
||||||
|
|
||||||
//hacky fix since we are ignoring repeats and keyups right now
|
//ignore modifiers for modifier key events
|
||||||
if (event.event != input.event.press) return null;
|
event.modifiers = switch (event.key) {
|
||||||
|
input.key.left_control, input.key.right_control => 0,
|
||||||
|
input.key.left_alt, input.key.right_alt => 0,
|
||||||
|
else => event.modifiers,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (event.event == input.event.release)
|
||||||
|
return self.process_key_release_event(event);
|
||||||
|
|
||||||
//clear key history if enough time has passed since last key press
|
//clear key history if enough time has passed since last key press
|
||||||
const timestamp = std.time.milliTimestamp();
|
const timestamp = std.time.milliTimestamp();
|
||||||
|
@ -382,7 +400,8 @@ const BindingSet = struct {
|
||||||
try self.current_sequence_egc.appendSlice(buf[0..bytes]);
|
try self.current_sequence_egc.appendSlice(buf[0..bytes]);
|
||||||
|
|
||||||
var all_matches_impossible = true;
|
var all_matches_impossible = true;
|
||||||
for (self.bindings.items) |*binding| {
|
|
||||||
|
for (self.press.items) |*binding| {
|
||||||
switch (binding.match(self.current_sequence.items)) {
|
switch (binding.match(self.current_sequence.items)) {
|
||||||
.matched => {
|
.matched => {
|
||||||
self.current_sequence.clearRetainingCapacity();
|
self.current_sequence.clearRetainingCapacity();
|
||||||
|
@ -401,6 +420,17 @@ const BindingSet = struct {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn process_key_release_event(self: *BindingSet, event: KeyEvent) !?*Binding {
|
||||||
|
for (self.release.items) |*binding| {
|
||||||
|
switch (binding.match(&[_]KeyEvent{event})) {
|
||||||
|
.matched => return binding,
|
||||||
|
.match_possible => {},
|
||||||
|
.match_impossible => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const AbortType = enum { timeout, match_impossible };
|
const AbortType = enum { timeout, match_impossible };
|
||||||
fn terminate_sequence(self: *@This(), abort_type: AbortType, egc: input.Key, key_event: KeyEvent) anyerror!void {
|
fn terminate_sequence(self: *@This(), abort_type: AbortType, egc: input.Key, key_event: KeyEvent) anyerror!void {
|
||||||
_ = egc;
|
_ = egc;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"flow": {
|
"flow": {
|
||||||
"normal": {
|
"normal": {
|
||||||
"bindings": [
|
"press": [
|
||||||
["ctrl+e", "open_recent"],
|
["ctrl+e", "open_recent"],
|
||||||
["ctrl+r", "open_recent_project"],
|
["ctrl+r", "open_recent_project"],
|
||||||
["ctrl+j", "toggle_panel"],
|
["ctrl+j", "toggle_panel"],
|
||||||
|
@ -139,12 +139,23 @@
|
||||||
["end", "move_end"],
|
["end", "move_end"],
|
||||||
["page_up", "move_page_up"],
|
["page_up", "move_page_up"],
|
||||||
["page_down", "move_page_down"],
|
["page_down", "move_page_down"],
|
||||||
["tab", "indent"]
|
["tab", "indent"],
|
||||||
|
|
||||||
|
["left_control", "enable_fast_scroll"],
|
||||||
|
["right_control", "enable_fast_scroll"],
|
||||||
|
["left_alt", "enable_jump_mode"],
|
||||||
|
["right_alt", "enable_jump_mode"]
|
||||||
|
],
|
||||||
|
"release": [
|
||||||
|
["left_control", "disable_fast_scroll"],
|
||||||
|
["right_control", "disable_fast_scroll"],
|
||||||
|
["left_alt", "disable_jump_mode"],
|
||||||
|
["right_alt", "disable_jump_mode"]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"home": {
|
"home": {
|
||||||
"on_match_failure": "ignore",
|
"on_match_failure": "ignore",
|
||||||
"bindings": [
|
"press": [
|
||||||
["ctrl+f>ctrl+f>ctrl+f>ctrl+f>ctrl+f", "home_sheeran"],
|
["ctrl+f>ctrl+f>ctrl+f>ctrl+f>ctrl+f", "home_sheeran"],
|
||||||
["ctrl+j", "toggle_panel"],
|
["ctrl+j", "toggle_panel"],
|
||||||
["ctrl+q", "quit"],
|
["ctrl+q", "quit"],
|
||||||
|
@ -185,7 +196,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"palette": {
|
"palette": {
|
||||||
"bindings": [
|
"press": [
|
||||||
["ctrl+j", "toggle_panel"],
|
["ctrl+j", "toggle_panel"],
|
||||||
["ctrl+q", "quit"],
|
["ctrl+q", "quit"],
|
||||||
["ctrl+w", "close_file"],
|
["ctrl+w", "close_file"],
|
||||||
|
@ -230,10 +241,14 @@
|
||||||
["page_down", "palette_menu_pagedown"],
|
["page_down", "palette_menu_pagedown"],
|
||||||
["enter", "palette_menu_activate"],
|
["enter", "palette_menu_activate"],
|
||||||
["backspace", "overlay_delete_backwards"]
|
["backspace", "overlay_delete_backwards"]
|
||||||
|
],
|
||||||
|
"release": [
|
||||||
|
["left_control", "palette_menu_activate_quick"],
|
||||||
|
["right_control", "palette_menu_activate_quick"]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"mini/goto": {
|
"mini/goto": {
|
||||||
"bindings": [
|
"press": [
|
||||||
["ctrl+q", "quit"],
|
["ctrl+q", "quit"],
|
||||||
["ctrl+v", "system_paste"],
|
["ctrl+v", "system_paste"],
|
||||||
["ctrl+u", "mini_mode_reset"],
|
["ctrl+u", "mini_mode_reset"],
|
||||||
|
@ -248,7 +263,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"mini/move_to_char": {
|
"mini/move_to_char": {
|
||||||
"bindings": [
|
"press": [
|
||||||
["ctrl+g", "mini_mode_cancel"],
|
["ctrl+g", "mini_mode_cancel"],
|
||||||
["ctrl+c", "mini_mode_cancel"],
|
["ctrl+c", "mini_mode_cancel"],
|
||||||
["ctrl+l", "scroll_view_center_cycle"],
|
["ctrl+l", "scroll_view_center_cycle"],
|
||||||
|
@ -257,7 +272,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"mini/file_browser": {
|
"mini/file_browser": {
|
||||||
"bindings": [
|
"press": [
|
||||||
["ctrl+q", "quit"],
|
["ctrl+q", "quit"],
|
||||||
["ctrl+v", "system_paste"],
|
["ctrl+v", "system_paste"],
|
||||||
["ctrl+u", "mini_mode_reset"],
|
["ctrl+u", "mini_mode_reset"],
|
||||||
|
@ -284,7 +299,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"mini/find_in_files": {
|
"mini/find_in_files": {
|
||||||
"bindings": [
|
"press": [
|
||||||
["ctrl+q", "quit"],
|
["ctrl+q", "quit"],
|
||||||
["ctrl+v", "system_paste"],
|
["ctrl+v", "system_paste"],
|
||||||
["ctrl+u", "mini_mode_reset"],
|
["ctrl+u", "mini_mode_reset"],
|
||||||
|
@ -319,7 +334,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"mini/find": {
|
"mini/find": {
|
||||||
"bindings": [
|
"press": [
|
||||||
["ctrl+q", "quit"],
|
["ctrl+q", "quit"],
|
||||||
["ctrl+v", "system_paste"],
|
["ctrl+v", "system_paste"],
|
||||||
["ctrl+u", "mini_mode_reset"],
|
["ctrl+u", "mini_mode_reset"],
|
||||||
|
@ -358,7 +373,7 @@
|
||||||
"normal": {
|
"normal": {
|
||||||
"syntax": "vim",
|
"syntax": "vim",
|
||||||
"on_match_failure": "ignore",
|
"on_match_failure": "ignore",
|
||||||
"bindings": [
|
"press": [
|
||||||
["j", "move_down"],
|
["j", "move_down"],
|
||||||
["k", "move_up"],
|
["k", "move_up"],
|
||||||
["l", "move_right_vim"],
|
["l", "move_right_vim"],
|
||||||
|
@ -395,7 +410,7 @@
|
||||||
},
|
},
|
||||||
"insert": {
|
"insert": {
|
||||||
"syntax": "vim",
|
"syntax": "vim",
|
||||||
"bindings": [
|
"press": [
|
||||||
["jk", "enter_mode", "normal"],
|
["jk", "enter_mode", "normal"],
|
||||||
["<Esc>", "enter_mode", "normal"]
|
["<Esc>", "enter_mode", "normal"]
|
||||||
]
|
]
|
||||||
|
@ -404,7 +419,7 @@
|
||||||
"emacs" : {
|
"emacs" : {
|
||||||
"base": {
|
"base": {
|
||||||
"syntax": "vim",
|
"syntax": "vim",
|
||||||
"bindings": [
|
"press": [
|
||||||
["<C-a>", "cursor_line_start"],
|
["<C-a>", "cursor_line_start"],
|
||||||
["<C-e>", "cursor_line_end"],
|
["<C-e>", "cursor_line_end"],
|
||||||
["<C-b>", "cursor_left"],
|
["<C-b>", "cursor_left"],
|
||||||
|
|
|
@ -18,15 +18,15 @@ fn parse_error(comptime format: anytype, args: anytype) ParseError {
|
||||||
return error.InvalidFormat;
|
return error.InvalidFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseError![]KeyEvent {
|
pub fn parse_key_events(allocator: std.mem.Allocator, event: input.Event, str: []const u8) ParseError![]input.KeyEvent {
|
||||||
parse_error_reset();
|
parse_error_reset();
|
||||||
if (str.len == 0) return parse_error("empty", .{});
|
if (str.len == 0) return parse_error("empty", .{});
|
||||||
var result_events = std.ArrayList(KeyEvent).init(allocator);
|
var result_events = std.ArrayList(input.KeyEvent).init(allocator);
|
||||||
var iter_events = std.mem.tokenizeScalar(u8, str, '>');
|
var iter_sequence = std.mem.tokenizeScalar(u8, str, '>');
|
||||||
while (iter_events.next()) |event| {
|
while (iter_sequence.next()) |item| {
|
||||||
var key: ?input.Key = null;
|
var key: ?input.Key = null;
|
||||||
var mods = input.ModSet{};
|
var mods = input.ModSet{};
|
||||||
var iter = std.mem.tokenizeScalar(u8, event, '+');
|
var iter = std.mem.tokenizeScalar(u8, item, '+');
|
||||||
loop: while (iter.next()) |part| {
|
loop: while (iter.next()) |part| {
|
||||||
if (part.len == 0) return parse_error("empty part in '{s}'", .{str});
|
if (part.len == 0) return parse_error("empty part in '{s}'", .{str});
|
||||||
const modsInfo = @typeInfo(input.ModSet).Struct;
|
const modsInfo = @typeInfo(input.ModSet).Struct;
|
||||||
|
@ -65,7 +65,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
if (key == null) return parse_error("unknown key '{s}' in '{s}'", .{ part, str });
|
if (key == null) return parse_error("unknown key '{s}' in '{s}'", .{ part, str });
|
||||||
}
|
}
|
||||||
if (key) |k|
|
if (key) |k|
|
||||||
try result_events.append(.{ .key = k, .modifiers = @bitCast(mods) })
|
try result_events.append(.{ .event = event, .key = k, .modifiers = @bitCast(mods) })
|
||||||
else
|
else
|
||||||
return parse_error("no key defined in '{s}'", .{str});
|
return parse_error("no key defined in '{s}'", .{str});
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ fn parse_error(e: ParseError, comptime format: anytype, args: anytype) ParseErro
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseError![]KeyEvent {
|
pub fn parse_key_events(allocator: std.mem.Allocator, event: input.Event, str: []const u8) ParseError![]input.KeyEvent {
|
||||||
parse_error_reset();
|
parse_error_reset();
|
||||||
const State = enum {
|
const State = enum {
|
||||||
base,
|
base,
|
||||||
|
@ -66,7 +66,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
var state: State = .base;
|
var state: State = .base;
|
||||||
var function_key_number: u8 = 0;
|
var function_key_number: u8 = 0;
|
||||||
var modifiers: input.Mods = 0;
|
var modifiers: input.Mods = 0;
|
||||||
var result = std.ArrayList(KeyEvent).init(allocator);
|
var result = std.ArrayList(input.KeyEvent).init(allocator);
|
||||||
defer result.deinit();
|
defer result.deinit();
|
||||||
|
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
|
@ -79,7 +79,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
i += 1;
|
i += 1;
|
||||||
},
|
},
|
||||||
'a'...'z', '\\', '[', ']', '/', '`', '-', '=', ';', '0'...'9' => {
|
'a'...'z', '\\', '[', ']', '/', '`', '-', '=', ';', '0'...'9' => {
|
||||||
try result.append(.{ .key = str[i] });
|
try result.append(.{ .event = event, .key = str[i] });
|
||||||
i += 1;
|
i += 1;
|
||||||
},
|
},
|
||||||
else => return parse_error(error.InvalidInitialCharacter, "str: {s}, i: {} c: {c}", .{ str, i, str[i] }),
|
else => return parse_error(error.InvalidInitialCharacter, "str: {s}, i: {} c: {c}", .{ str, i, str[i] }),
|
||||||
|
@ -150,7 +150,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
},
|
},
|
||||||
.cr => {
|
.cr => {
|
||||||
if (std.mem.indexOf(u8, str[i..], "CR") == 0) {
|
if (std.mem.indexOf(u8, str[i..], "CR") == 0) {
|
||||||
try result.append(.{ .key = input.key.enter, .modifiers = modifiers });
|
try result.append(.{ .event = event, .key = input.key.enter, .modifiers = modifiers });
|
||||||
modifiers = 0;
|
modifiers = 0;
|
||||||
state = .escape_sequence_end;
|
state = .escape_sequence_end;
|
||||||
i += 2;
|
i += 2;
|
||||||
|
@ -158,7 +158,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
},
|
},
|
||||||
.space => {
|
.space => {
|
||||||
if (std.mem.indexOf(u8, str[i..], "Space") == 0) {
|
if (std.mem.indexOf(u8, str[i..], "Space") == 0) {
|
||||||
try result.append(.{ .key = input.key.space, .modifiers = modifiers });
|
try result.append(.{ .event = event, .key = input.key.space, .modifiers = modifiers });
|
||||||
modifiers = 0;
|
modifiers = 0;
|
||||||
state = .escape_sequence_end;
|
state = .escape_sequence_end;
|
||||||
i += 5;
|
i += 5;
|
||||||
|
@ -166,7 +166,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
},
|
},
|
||||||
.del => {
|
.del => {
|
||||||
if (std.mem.indexOf(u8, str[i..], "Del") == 0) {
|
if (std.mem.indexOf(u8, str[i..], "Del") == 0) {
|
||||||
try result.append(.{ .key = input.key.delete, .modifiers = modifiers });
|
try result.append(.{ .event = event, .key = input.key.delete, .modifiers = modifiers });
|
||||||
modifiers = 0;
|
modifiers = 0;
|
||||||
state = .escape_sequence_end;
|
state = .escape_sequence_end;
|
||||||
i += 3;
|
i += 3;
|
||||||
|
@ -174,7 +174,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
},
|
},
|
||||||
.tab => {
|
.tab => {
|
||||||
if (std.mem.indexOf(u8, str[i..], "Tab") == 0) {
|
if (std.mem.indexOf(u8, str[i..], "Tab") == 0) {
|
||||||
try result.append(.{ .key = input.key.tab, .modifiers = modifiers });
|
try result.append(.{ .event = event, .key = input.key.tab, .modifiers = modifiers });
|
||||||
modifiers = 0;
|
modifiers = 0;
|
||||||
state = .escape_sequence_end;
|
state = .escape_sequence_end;
|
||||||
i += 3;
|
i += 3;
|
||||||
|
@ -182,7 +182,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
},
|
},
|
||||||
.up => {
|
.up => {
|
||||||
if (std.mem.indexOf(u8, str[i..], "Up") == 0) {
|
if (std.mem.indexOf(u8, str[i..], "Up") == 0) {
|
||||||
try result.append(.{ .key = input.key.up, .modifiers = modifiers });
|
try result.append(.{ .event = event, .key = input.key.up, .modifiers = modifiers });
|
||||||
modifiers = 0;
|
modifiers = 0;
|
||||||
state = .escape_sequence_end;
|
state = .escape_sequence_end;
|
||||||
i += 2;
|
i += 2;
|
||||||
|
@ -190,7 +190,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
},
|
},
|
||||||
.esc => {
|
.esc => {
|
||||||
if (std.mem.indexOf(u8, str[i..], "Esc") == 0) {
|
if (std.mem.indexOf(u8, str[i..], "Esc") == 0) {
|
||||||
try result.append(.{ .key = input.key.escape, .modifiers = modifiers });
|
try result.append(.{ .event = event, .key = input.key.escape, .modifiers = modifiers });
|
||||||
modifiers = 0;
|
modifiers = 0;
|
||||||
state = .escape_sequence_end;
|
state = .escape_sequence_end;
|
||||||
i += 3;
|
i += 3;
|
||||||
|
@ -198,7 +198,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
},
|
},
|
||||||
.down => {
|
.down => {
|
||||||
if (std.mem.indexOf(u8, str[i..], "Down") == 0) {
|
if (std.mem.indexOf(u8, str[i..], "Down") == 0) {
|
||||||
try result.append(.{ .key = input.key.down, .modifiers = modifiers });
|
try result.append(.{ .event = event, .key = input.key.down, .modifiers = modifiers });
|
||||||
modifiers = 0;
|
modifiers = 0;
|
||||||
state = .escape_sequence_end;
|
state = .escape_sequence_end;
|
||||||
i += 4;
|
i += 4;
|
||||||
|
@ -206,7 +206,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
},
|
},
|
||||||
.left => {
|
.left => {
|
||||||
if (std.mem.indexOf(u8, str[i..], "Left") == 0) {
|
if (std.mem.indexOf(u8, str[i..], "Left") == 0) {
|
||||||
try result.append(.{ .key = input.key.left, .modifiers = modifiers });
|
try result.append(.{ .event = event, .key = input.key.left, .modifiers = modifiers });
|
||||||
modifiers = 0;
|
modifiers = 0;
|
||||||
state = .escape_sequence_end;
|
state = .escape_sequence_end;
|
||||||
i += 4;
|
i += 4;
|
||||||
|
@ -214,7 +214,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
},
|
},
|
||||||
.right => {
|
.right => {
|
||||||
if (std.mem.indexOf(u8, str[i..], "Right") == 0) {
|
if (std.mem.indexOf(u8, str[i..], "Right") == 0) {
|
||||||
try result.append(.{ .key = input.key.right, .modifiers = modifiers });
|
try result.append(.{ .event = event, .key = input.key.right, .modifiers = modifiers });
|
||||||
modifiers = 0;
|
modifiers = 0;
|
||||||
state = .escape_sequence_end;
|
state = .escape_sequence_end;
|
||||||
i += 5;
|
i += 5;
|
||||||
|
@ -231,7 +231,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
},
|
},
|
||||||
'>' => {
|
'>' => {
|
||||||
const function_key = input.key.f1 - 1 + function_key_number;
|
const function_key = input.key.f1 - 1 + function_key_number;
|
||||||
try result.append(.{ .key = function_key, .modifiers = modifiers });
|
try result.append(.{ .event = event, .key = function_key, .modifiers = modifiers });
|
||||||
modifiers = 0;
|
modifiers = 0;
|
||||||
function_key_number = 0;
|
function_key_number = 0;
|
||||||
state = .base;
|
state = .base;
|
||||||
|
@ -252,7 +252,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
.char_or_key_or_modifier => {
|
.char_or_key_or_modifier => {
|
||||||
switch (str[i]) {
|
switch (str[i]) {
|
||||||
'a'...'z', ';', '0'...'9' => {
|
'a'...'z', ';', '0'...'9' => {
|
||||||
try result.append(.{ .key = str[i], .modifiers = modifiers });
|
try result.append(.{ .event = event, .key = str[i], .modifiers = modifiers });
|
||||||
modifiers = 0;
|
modifiers = 0;
|
||||||
state = .escape_sequence_end;
|
state = .escape_sequence_end;
|
||||||
i += 1;
|
i += 1;
|
||||||
|
|
|
@ -410,6 +410,11 @@ pub fn Create(options: type) type {
|
||||||
}
|
}
|
||||||
pub const palette_menu_activate_meta = .{ .interactive = false };
|
pub const palette_menu_activate_meta = .{ .interactive = false };
|
||||||
|
|
||||||
|
pub fn palette_menu_activate_quick(self: *Self, _: Ctx) Result {
|
||||||
|
if (self.menu.selected orelse 0 > 0) self.menu.activate_selected();
|
||||||
|
}
|
||||||
|
pub const palette_menu_activate_quick_meta = .{ .interactive = false };
|
||||||
|
|
||||||
pub fn palette_menu_cancel(self: *Self, _: Ctx) Result {
|
pub fn palette_menu_cancel(self: *Self, _: Ctx) Result {
|
||||||
if (@hasDecl(options, "cancel")) try options.cancel(self);
|
if (@hasDecl(options, "cancel")) try options.cancel(self);
|
||||||
try self.cmd("exit_overlay_mode", .{});
|
try self.cmd("exit_overlay_mode", .{});
|
||||||
|
|
Loading…
Add table
Reference in a new issue