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,
|
||||
app_common_model: *AppCommonModel,
|
||||
root_provider: *RootProvider,
|
||||
action_map: ActionMap,
|
||||
|
||||
/// Helper function to return a vxfw.Widget struct
|
||||
pub fn widget(self: *Model) vxfw.Widget {
|
||||
@@ -54,7 +55,7 @@ const Model = struct {
|
||||
var arena = std.heap.ArenaAllocator.init(vm.allocator);
|
||||
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 (r == ActionResult.Handled) {
|
||||
ctx.consumeAndRedraw();
|
||||
@@ -542,6 +543,7 @@ pub fn main() !void {
|
||||
.parent_items_view = &parent_items_list,
|
||||
.current_children_view = ¤t_children_view,
|
||||
.root_provider = &rootProvider,
|
||||
.action_map = try ActionMap.init(allocator),
|
||||
};
|
||||
|
||||
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 AppCommonModel = @import("../app_common/Model.zig");
|
||||
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 Observer = @import("../core/observable.zig").Observer;
|
||||
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 {
|
||||
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 ..];
|
||||
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 ProviderVTable = @import("provider.zig").VTable;
|
||||
const GetItemsError = @import("provider.zig").GetItemsError;
|
||||
const ProviderError = @import("provider.zig").ProviderError;
|
||||
const InitContext = @import("provider.zig").InitContext;
|
||||
|
||||
const FullName = models.FullName;
|
||||
|
||||
@@ -18,6 +18,10 @@ pub const GetItemsError = error{
|
||||
OutOfMemory,
|
||||
NotExists,
|
||||
NotSupported,
|
||||
} || ProviderError;
|
||||
|
||||
pub const ProviderError = error{
|
||||
WrongProvider,
|
||||
};
|
||||
|
||||
pub const Provider = struct {
|
||||
|
||||
@@ -39,6 +39,7 @@ pub const Tab = struct {
|
||||
pub fn setCurrentLocation(self: *Tab, newLocationFullName: models.FullName) !void {
|
||||
if (self.currentLocation) |c| {
|
||||
c.item.deinit();
|
||||
self.currentLocation = null;
|
||||
}
|
||||
|
||||
self.cleanCurrentItem();
|
||||
@@ -201,7 +202,7 @@ pub const Tab = struct {
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
const parentContainer = switch (resolvedParent.item) {
|
||||
@@ -229,7 +230,7 @@ pub const Tab = struct {
|
||||
const allocator = arena.allocator();
|
||||
|
||||
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;
|
||||
};
|
||||
const childContainer = switch (resolvedChild.item) {
|
||||
@@ -362,7 +363,7 @@ fn loadItems(
|
||||
for (location.children.data.items[processed_number..]) |item_fullname| {
|
||||
const resolvedItem = location.item.provider.getItemByFullName(item_fullname, &.{}, allocator) catch |e| {
|
||||
//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;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user