feat: action map refactor, bugfix
This commit is contained in:
96
src/console/ActionMap.zig
Normal file
96
src/console/ActionMap.zig
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
key_action_map: []KeyActionMap,
|
||||||
|
previous_keys: std.ArrayList(vaxis.Key),
|
||||||
|
_private: Private,
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
const Private = struct {
|
||||||
|
key_action_map: std.ArrayList(KeyActionMap),
|
||||||
|
max_action_key_length: u8,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn init(allocator: std.mem.Allocator) !Self {
|
||||||
|
var key_action_map = std.ArrayList(KeyActionMap).init(allocator);
|
||||||
|
try init_key_action_map(&key_action_map);
|
||||||
|
|
||||||
|
var max_action_key_length: u8 = 0;
|
||||||
|
for (key_action_map.items) |item| {
|
||||||
|
if (item.keys.len > max_action_key_length) {
|
||||||
|
max_action_key_length = @intCast(item.keys.len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.key_action_map = key_action_map.items,
|
||||||
|
.previous_keys = std.ArrayList(vaxis.Key).init(allocator),
|
||||||
|
._private = .{
|
||||||
|
.key_action_map = key_action_map,
|
||||||
|
.max_action_key_length = max_action_key_length,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Self) void {
|
||||||
|
self._private.key_action_map.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_key_action_map(map_list: *std.ArrayList(KeyActionMap)) !void {
|
||||||
|
try map_list.appendSlice(&.{
|
||||||
|
.{
|
||||||
|
.keys = &[1]KeyMatch{.{ .code_point = vaxis.Key.left, .modifiers = .{} }},
|
||||||
|
.action = Action.GoUp,
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.keys = &[1]KeyMatch{.{ .code_point = vaxis.Key.right, .modifiers = .{} }},
|
||||||
|
.action = Action.Enter,
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.keys = &[1]KeyMatch{.{ .code_point = vaxis.Key.up, .modifiers = .{} }},
|
||||||
|
.action = Action.SelectPrevious,
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.keys = &[1]KeyMatch{.{ .code_point = vaxis.Key.down, .modifiers = .{} }},
|
||||||
|
.action = Action.SelectNext,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_key(self: *Self, key: vaxis.Key, appState: *AppState, arena: std.mem.Allocator) !ActionResult {
|
||||||
|
try self.previous_keys.append(key);
|
||||||
|
|
||||||
|
const action_result = action_result: for (self.key_action_map) |action_map| {
|
||||||
|
if (action_map.keys.len != self.previous_keys.items.len) continue;
|
||||||
|
|
||||||
|
const matches = blk: for (action_map.keys, self.previous_keys.items) |action_key, previous_key| {
|
||||||
|
if (!previous_key.matches(action_key.code_point, action_key.modifiers)) break :blk false;
|
||||||
|
} else true;
|
||||||
|
|
||||||
|
if (!matches) continue;
|
||||||
|
|
||||||
|
self.previous_keys.clearRetainingCapacity();
|
||||||
|
break :action_result try handle_action(action_map.action, appState, arena);
|
||||||
|
} else ActionResult.None;
|
||||||
|
|
||||||
|
if (self.previous_keys.items.len >= self._private.max_action_key_length) {
|
||||||
|
self.previous_keys.clearRetainingCapacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
return action_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const KeyMatch = struct {
|
||||||
|
code_point: u21,
|
||||||
|
modifiers: vaxis.Key.Modifiers,
|
||||||
|
};
|
||||||
|
const KeyActionMap = struct {
|
||||||
|
keys: []const KeyMatch,
|
||||||
|
action: Action,
|
||||||
|
};
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const vaxis = @import("vaxis");
|
||||||
|
const ActionResult = @import("../core/action/action.zig").ActionResult;
|
||||||
|
const handle_action = @import("../core/action/action_handler.zig").handle;
|
||||||
|
const Action = @import("../core/action/action.zig").Action;
|
||||||
|
const AppState = @import("../core/app_state.zig").AppState;
|
||||||
|
const RootProvider = @import("../core/provider/root.zig").RootProvider;
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
pub fn handle_key(key: vaxis.Key, appState: *AppState, arena: std.mem.Allocator) !ActionResult {
|
|
||||||
if (key.matches(vaxis.Key.left, .{})) {
|
|
||||||
return try handle_action(Action.GoUp, appState, arena);
|
|
||||||
} else if (key.matches(vaxis.Key.right, .{})) {
|
|
||||||
return try handle_action(Action.Enter, appState, arena);
|
|
||||||
} else if (key.matches(vaxis.Key.up, .{})) {
|
|
||||||
return try handle_action(Action.SelectPrevious, appState, arena);
|
|
||||||
} else if (key.matches(vaxis.Key.down, .{})) {
|
|
||||||
return try handle_action(Action.SelectNext, appState, arena);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ActionResult.None;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std = @import("std");
|
|
||||||
const vaxis = @import("vaxis");
|
|
||||||
const ActionResult = @import("../core/action/action.zig").ActionResult;
|
|
||||||
const handle_action = @import("../core/action/action_handler.zig").handle;
|
|
||||||
const Action = @import("../core/action/action.zig").Action;
|
|
||||||
const AppState = @import("../core/app_state.zig").AppState;
|
|
||||||
const RootProvider = @import("../core/provider/root.zig").RootProvider;
|
|
||||||
@@ -7,6 +7,7 @@ const Model = struct {
|
|||||||
current_children_view: *vxfw.ListView,
|
current_children_view: *vxfw.ListView,
|
||||||
app_common_model: *AppCommonModel,
|
app_common_model: *AppCommonModel,
|
||||||
root_provider: *RootProvider,
|
root_provider: *RootProvider,
|
||||||
|
action_map: ActionMap,
|
||||||
|
|
||||||
/// Helper function to return a vxfw.Widget struct
|
/// Helper function to return a vxfw.Widget struct
|
||||||
pub fn widget(self: *Model) vxfw.Widget {
|
pub fn widget(self: *Model) vxfw.Widget {
|
||||||
@@ -54,7 +55,7 @@ const Model = struct {
|
|||||||
var arena = std.heap.ArenaAllocator.init(vm.allocator);
|
var arena = std.heap.ArenaAllocator.init(vm.allocator);
|
||||||
defer arena.deinit();
|
defer arena.deinit();
|
||||||
|
|
||||||
const result = handle_key(key, &vm.app_common_model.appState, arena.allocator()) catch null;
|
const result = vm.action_map.handle_key(key, &vm.app_common_model.appState, arena.allocator()) catch null;
|
||||||
if (result) |r| {
|
if (result) |r| {
|
||||||
if (r == ActionResult.Handled) {
|
if (r == ActionResult.Handled) {
|
||||||
ctx.consumeAndRedraw();
|
ctx.consumeAndRedraw();
|
||||||
@@ -542,6 +543,7 @@ pub fn main() !void {
|
|||||||
.parent_items_view = &parent_items_list,
|
.parent_items_view = &parent_items_list,
|
||||||
.current_children_view = ¤t_children_view,
|
.current_children_view = ¤t_children_view,
|
||||||
.root_provider = &rootProvider,
|
.root_provider = &rootProvider,
|
||||||
|
.action_map = try ActionMap.init(allocator),
|
||||||
};
|
};
|
||||||
|
|
||||||
model.app_common_model.usage_number.data += 1;
|
model.app_common_model.usage_number.data += 1;
|
||||||
@@ -572,7 +574,7 @@ const Tab = @import("../core/tab/tab.zig").Tab;
|
|||||||
const locked = @import("../core/sync.zig").locked;
|
const locked = @import("../core/sync.zig").locked;
|
||||||
const AppCommonModel = @import("../app_common/Model.zig");
|
const AppCommonModel = @import("../app_common/Model.zig");
|
||||||
const AppState = @import("../core/app_state.zig").AppState;
|
const AppState = @import("../core/app_state.zig").AppState;
|
||||||
const handle_key = @import("./action_map.zig").handle_key;
|
const ActionMap = @import("./ActionMap.zig");
|
||||||
const Arc = @import("zigrc").Arc;
|
const Arc = @import("zigrc").Arc;
|
||||||
const Observer = @import("../core/observable.zig").Observer;
|
const Observer = @import("../core/observable.zig").Observer;
|
||||||
const draw_context = @import("draw_context.zig");
|
const draw_context = @import("draw_context.zig");
|
||||||
|
|||||||
@@ -65,6 +65,22 @@ pub fn getFullNameByNativePath(allocator: std.mem.Allocator, nativePath: NativeP
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn getNativePathByFullName(allocator: std.mem.Allocator, fullName: FullName) ![]u8 {
|
pub fn getNativePathByFullName(allocator: std.mem.Allocator, fullName: FullName) ![]u8 {
|
||||||
|
std.debug.assert(!std.mem.endsWith(u8, fullName.path, "/"));
|
||||||
|
|
||||||
|
if (fullName.path.len < LocalProviderId.len or
|
||||||
|
!std.mem.eql(u8, fullName.path[0..LocalProviderId.len], LocalProviderId))
|
||||||
|
{
|
||||||
|
return ProviderError.WrongProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
//NOTE: their might be an other edge case where the fullname is local/ that is not handled by this
|
||||||
|
if (fullName.path.len == LocalProviderId.len) {
|
||||||
|
if (native_os == .linux)
|
||||||
|
return try std.fmt.allocPrint(allocator, "/", .{})
|
||||||
|
else
|
||||||
|
return ProviderError.WrongProvider;
|
||||||
|
}
|
||||||
|
|
||||||
const fullNameWithoutId = fullName.path[LocalProviderId.len + 1 ..];
|
const fullNameWithoutId = fullName.path[LocalProviderId.len + 1 ..];
|
||||||
var native_path = try std.mem.replaceOwned(u8, allocator, fullNameWithoutId, "/", std.fs.path.sep_str);
|
var native_path = try std.mem.replaceOwned(u8, allocator, fullNameWithoutId, "/", std.fs.path.sep_str);
|
||||||
|
|
||||||
@@ -217,6 +233,7 @@ const models = @import("../models.zig");
|
|||||||
const Provider = @import("provider.zig").Provider;
|
const Provider = @import("provider.zig").Provider;
|
||||||
const ProviderVTable = @import("provider.zig").VTable;
|
const ProviderVTable = @import("provider.zig").VTable;
|
||||||
const GetItemsError = @import("provider.zig").GetItemsError;
|
const GetItemsError = @import("provider.zig").GetItemsError;
|
||||||
|
const ProviderError = @import("provider.zig").ProviderError;
|
||||||
const InitContext = @import("provider.zig").InitContext;
|
const InitContext = @import("provider.zig").InitContext;
|
||||||
|
|
||||||
const FullName = models.FullName;
|
const FullName = models.FullName;
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ pub const GetItemsError = error{
|
|||||||
OutOfMemory,
|
OutOfMemory,
|
||||||
NotExists,
|
NotExists,
|
||||||
NotSupported,
|
NotSupported,
|
||||||
|
} || ProviderError;
|
||||||
|
|
||||||
|
pub const ProviderError = error{
|
||||||
|
WrongProvider,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Provider = struct {
|
pub const Provider = struct {
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ pub const Tab = struct {
|
|||||||
pub fn setCurrentLocation(self: *Tab, newLocationFullName: models.FullName) !void {
|
pub fn setCurrentLocation(self: *Tab, newLocationFullName: models.FullName) !void {
|
||||||
if (self.currentLocation) |c| {
|
if (self.currentLocation) |c| {
|
||||||
c.item.deinit();
|
c.item.deinit();
|
||||||
|
self.currentLocation = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.cleanCurrentItem();
|
self.cleanCurrentItem();
|
||||||
@@ -201,7 +202,7 @@ pub const Tab = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const resolvedParent = location.item.provider.getItemByFullName(parentFullName, &.{}, allocator) catch |e| {
|
const resolvedParent = location.item.provider.getItemByFullName(parentFullName, &.{}, allocator) catch |e| {
|
||||||
std.debug.print("error {} {s}\r\n", .{ e, parentFullName.path });
|
std.debug.print("error {s}:{} {} {s}\r\n", .{ @src().file, @src().line, e, parentFullName.path });
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
const parentContainer = switch (resolvedParent.item) {
|
const parentContainer = switch (resolvedParent.item) {
|
||||||
@@ -229,7 +230,7 @@ pub const Tab = struct {
|
|||||||
const allocator = arena.allocator();
|
const allocator = arena.allocator();
|
||||||
|
|
||||||
const resolvedChild = newSelectedItemArc.value.*.provider.getItemByFullName(newSelectedItemArc.value.*.fullName, &.{}, allocator) catch |e| {
|
const resolvedChild = newSelectedItemArc.value.*.provider.getItemByFullName(newSelectedItemArc.value.*.fullName, &.{}, allocator) catch |e| {
|
||||||
std.debug.print("error {} {s}\r\n", .{ e, newSelectedItemArc.value.*.fullName.path });
|
std.debug.print("error {s}:{} {} {s}\r\n", .{ @src().file, @src().line, e, newSelectedItemArc.value.*.fullName.path });
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
const childContainer = switch (resolvedChild.item) {
|
const childContainer = switch (resolvedChild.item) {
|
||||||
@@ -362,7 +363,7 @@ fn loadItems(
|
|||||||
for (location.children.data.items[processed_number..]) |item_fullname| {
|
for (location.children.data.items[processed_number..]) |item_fullname| {
|
||||||
const resolvedItem = location.item.provider.getItemByFullName(item_fullname, &.{}, allocator) catch |e| {
|
const resolvedItem = location.item.provider.getItemByFullName(item_fullname, &.{}, allocator) catch |e| {
|
||||||
//TODO: save error to container errors
|
//TODO: save error to container errors
|
||||||
std.debug.print("error {} {s}\r\n", .{ e, item_fullname.path });
|
std.debug.print("error {s}:{} {} {s}\r\n", .{ @src().file, @src().line, e, item_fullname.path });
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user