pub fn handle(action: Action, appState: *AppState, arena: std.mem.Allocator) !ActionResult { switch (action) { .GoUp => { if (appState.currentTab.currentLocation) |currentLocation| { const parent = currentLocation.item.parent; if (parent) |p| { const path = try arena.dupe(u8, p.path.path); try appState.currentTab.setCurrentLocation(.{ .path = path }); return ActionResult.Handled; } else return error.NoParent; } else return error.NoCurrentLocation; }, .Enter => { if (appState.currentTab.currentItem) |currentItem| { const path = try arena.dupe(u8, currentItem.path); try appState.currentTab.setCurrentLocation(.{ .path = path }); return ActionResult.Handled; } else return error.NoCurrentLocation; }, .SelectNext => { return selectNextIndex(appState.currentTab, .Next, arena); }, .SelectPrevious => { return selectNextIndex(appState.currentTab, .Previous, arena); }, } return ActionResult.None; } const SelectStep = enum { Next, Previous, NextPage, PreviousPage, }; fn selectNextIndex(currentTab: *Tab, step: SelectStep, arena: std.mem.Allocator) !ActionResult { const item = item: { currentTab.currentItems.mutex.lock(); defer currentTab.currentItems.mutex.unlock(); const currentItems = currentTab.currentItems.data orelse return ActionResult.None; const index = blk: { if (currentTab.currentItem) |*currentItem| { const index = indexOf(Arc(*models.Item), models.FullName, currentItems.items, currentItem, arcFullNameEql); if (index) |i| { break :blk switch (step) { .Next => i +| 1, .Previous => i -| 1, .NextPage => i +| 8, .PreviousPage => i +| 8, }; } } break :blk 0; }; const arc = currentItems.items[index]; const arc_copy = arc.retain(); defer if (arc_copy.releaseUnwrap()) |item| item.deinit(); break :item models.FullName{ .path = try arena.dupe(u8, arc_copy.value.*.fullName.path), }; }; currentTab.selectItem(item) catch { //TODO }; return ActionResult.Handled; } fn arcFullNameEql(arcLhs: *const Arc(*models.Item), rhs: *const models.FullName) bool { const arcLhs2 = arcLhs.retain(); defer if (arcLhs2.releaseUnwrap()) |i| i.deinit(); return models.FullName.eql(&arcLhs2.value.*.fullName, rhs); } fn indexOf(comptime TSlice: type, comptime TItem: type, slice: []const TSlice, value: *const TItem, compare: *const fn (a: *const TSlice, b: *const TItem) bool) ?usize { for (0.., slice) |i, *item| { if (compare(item, value)) return i; } return null; } const std = @import("std"); const Action = @import("action.zig").Action; const ActionResult = @import("action.zig").ActionResult; const AppState = @import("../app_state.zig").AppState; const RootProvider = @import("../provider/root.zig").RootProvider; const models = @import("../models.zig"); const Arc = @import("zigrc").Arc; const Tab = @import("../tab/tab.zig").Tab;