feat: cleanup appstate, move sort to tab
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
running: bool = true,
|
running: bool = true,
|
||||||
usage_number: locked(u16) = .{ .data = 0 },
|
usage_number: locked(u16) = .{ .data = 0 },
|
||||||
current_items: locked(?[]Arc(*models.Item).Weak) = .{ .data = null },
|
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
appState: AppState,
|
appState: AppState,
|
||||||
|
|
||||||
@@ -12,66 +11,8 @@ pub fn init(model: *Self, allocator: std.mem.Allocator, appState: AppState) !voi
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn updateCurrentItems(self: *Self, tab_current_items: *std.ArrayList(Arc(*models.Item))) !void {
|
|
||||||
self.resetCurrentItems();
|
|
||||||
|
|
||||||
var items = try self.allocator.alloc(Arc(*models.Item).Weak, tab_current_items.items.len);
|
|
||||||
errdefer {
|
|
||||||
self.allocator.free(items);
|
|
||||||
self.current_items.data = null;
|
|
||||||
}
|
|
||||||
for (tab_current_items.items, 0..) |*item, i| {
|
|
||||||
items[i] = item.downgrade();
|
|
||||||
}
|
|
||||||
|
|
||||||
std.mem.sort(Arc(*models.Item).Weak, items, {}, struct {
|
|
||||||
fn sort(_: void, lhs_weak: Arc(*models.Item).Weak, rhs_weak: Arc(*models.Item).Weak) bool {
|
|
||||||
const lhs_arc = @constCast(&lhs_weak).upgrade();
|
|
||||||
defer if (lhs_arc) |l1| if (l1.releaseUnwrap()) |l2| l2.deinit();
|
|
||||||
|
|
||||||
const rhs_arc = @constCast(&rhs_weak).upgrade();
|
|
||||||
defer if (rhs_arc) |r1| if (r1.releaseUnwrap()) |r2| r2.deinit();
|
|
||||||
|
|
||||||
const lhs = if (lhs_arc) |l|
|
|
||||||
l.value.*
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const rhs = if (rhs_arc) |r|
|
|
||||||
r.value.*
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (lhs.item == .container and rhs.item == .element) return true;
|
|
||||||
if (lhs.item == .element and rhs.item == .container) return false;
|
|
||||||
return std.mem.order(u8, lhs.displayName, rhs.displayName) == .lt;
|
|
||||||
}
|
|
||||||
}.sort);
|
|
||||||
|
|
||||||
self.current_items.mutex.lock();
|
|
||||||
defer self.current_items.mutex.unlock();
|
|
||||||
self.current_items.data = items;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resetCurrentItems(self: *@This()) void {
|
|
||||||
self.current_items.mutex.lock();
|
|
||||||
defer self.current_items.mutex.unlock();
|
|
||||||
|
|
||||||
const data = self.current_items.data;
|
|
||||||
// self.current_items.data = null;
|
|
||||||
|
|
||||||
if (data) |currentItems| {
|
|
||||||
for (currentItems) |item| {
|
|
||||||
item.release();
|
|
||||||
}
|
|
||||||
self.allocator.free(currentItems);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: *@This()) void {
|
pub fn deinit(self: *@This()) void {
|
||||||
self.appState.deinit();
|
self.appState.deinit();
|
||||||
|
|
||||||
self.resetCurrentItems();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
const std = @import("std");
|
|
||||||
const models = @import("../core/models.zig");
|
|
||||||
const Model = @import("Model.zig");
|
|
||||||
|
|
||||||
pub fn data_loop(vm: *Model) void {
|
|
||||||
vm.usage_number.data += 1;
|
|
||||||
while (vm.running) {
|
|
||||||
inner_loop(vm) catch {};
|
|
||||||
std.Thread.sleep(100 * std.time.ns_per_ms);
|
|
||||||
}
|
|
||||||
vm.usage_number.data -= 1;
|
|
||||||
}
|
|
||||||
fn inner_loop(appCommonModel: *Model) !void {
|
|
||||||
const tab = appCommonModel.appState.currentTab;
|
|
||||||
tab.currentItems.mutex.lock();
|
|
||||||
defer tab.currentItems.mutex.unlock();
|
|
||||||
|
|
||||||
if (tab.currentItemsChanged) {
|
|
||||||
std.Thread.sleep(10 * std.time.ns_per_ms);
|
|
||||||
|
|
||||||
if (tab.currentItems.data) |*tab_current_items| {
|
|
||||||
try appCommonModel.updateCurrentItems(tab_current_items);
|
|
||||||
tab.currentItemsChanged = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,18 @@
|
|||||||
pub fn handle_key(key: vaxis.Key, appState: *AppState, arena: std.mem.Allocator) !void {
|
pub fn handle_key(key: vaxis.Key, appState: *AppState, arena: std.mem.Allocator) !ActionResult {
|
||||||
if (key.matches(vaxis.Key.left, .{})) {
|
if (key.matches(vaxis.Key.left, .{})) {
|
||||||
try handle_action(Action.GoUp, appState, arena);
|
return try handle_action(Action.GoUp, 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 std = @import("std");
|
||||||
const vaxis = @import("vaxis");
|
const vaxis = @import("vaxis");
|
||||||
|
const ActionResult = @import("../core/action/action.zig").ActionResult;
|
||||||
const handle_action = @import("../core/action/action_handler.zig").handle;
|
const handle_action = @import("../core/action/action_handler.zig").handle;
|
||||||
const Action = @import("../core/action/action.zig").Action;
|
const Action = @import("../core/action/action.zig").Action;
|
||||||
const AppState = @import("../core/app_state.zig").AppState;
|
const AppState = @import("../core/app_state.zig").AppState;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
/// Our main application state
|
|
||||||
const Model = struct {
|
const Model = struct {
|
||||||
crash: bool = false,
|
crash: bool = false,
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
current_items_view: *vxfw.ListView,
|
current_items_view: *vxfw.ListView,
|
||||||
|
current_items_view_widget: vxfw.Widget,
|
||||||
app_common_model: *AppCommonModel,
|
app_common_model: *AppCommonModel,
|
||||||
root_provider: *RootProvider,
|
root_provider: *RootProvider,
|
||||||
|
|
||||||
@@ -11,15 +11,15 @@ const Model = struct {
|
|||||||
return .{
|
return .{
|
||||||
.userdata = self,
|
.userdata = self,
|
||||||
.eventHandler = Model.typeErasedEventHandler,
|
.eventHandler = Model.typeErasedEventHandler,
|
||||||
|
.captureHandler = Model.typeErasedCaptureHandler,
|
||||||
.drawFn = Model.typeErasedDrawFn,
|
.drawFn = Model.typeErasedDrawFn,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function will be called from the vxfw runtime.
|
|
||||||
fn typeErasedEventHandler(ptr: *anyopaque, ctx: *vxfw.EventContext, event: vxfw.Event) anyerror!void {
|
fn typeErasedEventHandler(ptr: *anyopaque, ctx: *vxfw.EventContext, event: vxfw.Event) anyerror!void {
|
||||||
const vm: *Model = @ptrCast(@alignCast(ptr));
|
const vm: *Model = @ptrCast(@alignCast(ptr));
|
||||||
switch (event) {
|
switch (event) {
|
||||||
.init => return ctx.requestFocus(vm.current_items_view.widget()),
|
.init => return ctx.requestFocus(vm.current_items_view_widget),
|
||||||
.key_press => |key| {
|
.key_press => |key| {
|
||||||
if (key.matches('c', .{ .ctrl = true })) {
|
if (key.matches('c', .{ .ctrl = true })) {
|
||||||
ctx.quit = true;
|
ctx.quit = true;
|
||||||
@@ -28,18 +28,27 @@ const Model = struct {
|
|||||||
if (key.matches('r', .{})) {
|
if (key.matches('r', .{})) {
|
||||||
// vm.crash = true;
|
// vm.crash = true;
|
||||||
ctx.redraw = true;
|
ctx.redraw = true;
|
||||||
return ctx.requestFocus(vm.current_items_view.widget());
|
return ctx.requestFocus(vm.current_items_view_widget);
|
||||||
}
|
}
|
||||||
// if (key.matches(vaxis.Key.left, .{})) {
|
},
|
||||||
// ctx.redraw = true;
|
.focus_in => return ctx.requestFocus(vm.current_items_view_widget),
|
||||||
// return ctx.requestFocus(vm.current_items_view.widget());
|
else => {},
|
||||||
// }
|
}
|
||||||
|
}
|
||||||
|
fn typeErasedCaptureHandler(ptr: *anyopaque, ctx: *vxfw.EventContext, event: vxfw.Event) anyerror!void {
|
||||||
|
const vm: *Model = @ptrCast(@alignCast(ptr));
|
||||||
|
switch (event) {
|
||||||
|
.key_press => |key| {
|
||||||
var arena = std.heap.ArenaAllocator.init(vm.allocator);
|
var arena = std.heap.ArenaAllocator.init(vm.allocator);
|
||||||
defer arena.deinit();
|
defer arena.deinit();
|
||||||
handle_key(key, &vm.app_common_model.appState, arena.allocator()) catch {};
|
|
||||||
|
const result = handle_key(key, &vm.app_common_model.appState, arena.allocator()) catch null;
|
||||||
|
if (result) |r| {
|
||||||
|
if (r == ActionResult.Handled) {
|
||||||
|
ctx.consumeAndRedraw();
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
.focus_in => return ctx.requestFocus(vm.current_items_view.widget()),
|
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -80,8 +89,7 @@ const Model = struct {
|
|||||||
const currentItemsTop = 1;
|
const currentItemsTop = 1;
|
||||||
const list_surface: vxfw.SubSurface = .{
|
const list_surface: vxfw.SubSurface = .{
|
||||||
.origin = .{ .row = currentItemsTop, .col = parentItemsWidth },
|
.origin = .{ .row = currentItemsTop, .col = parentItemsWidth },
|
||||||
.surface = try vm.current_items_view
|
.surface = try vm.current_items_view_widget
|
||||||
.widget()
|
|
||||||
.draw(ctx.withConstraints(ctx.min, .{
|
.draw(ctx.withConstraints(ctx.min, .{
|
||||||
.width = currentItemsWidth,
|
.width = currentItemsWidth,
|
||||||
.height = ctx.max.height.? - currentItemsTop,
|
.height = ctx.max.height.? - currentItemsTop,
|
||||||
@@ -90,23 +98,77 @@ const Model = struct {
|
|||||||
};
|
};
|
||||||
try rootWidgets.append(list_surface);
|
try rootWidgets.append(list_surface);
|
||||||
|
|
||||||
const current_location_text = if (vm.app_common_model.appState.currentTab.currentLocation) |loc| loc.item.fullName.path else "";
|
const header = try ctx.arena.create(std.ArrayList(vxfw.Widget));
|
||||||
const current_location_text_element = try ctx.arena.create(vxfw.Text);
|
header.* = std.ArrayList(vxfw.Widget).init(ctx.arena);
|
||||||
current_location_text_element.* = vxfw.Text{
|
|
||||||
.text = current_location_text,
|
|
||||||
.overflow = .clip,
|
|
||||||
.softwrap = false,
|
|
||||||
.style = .{
|
|
||||||
.fg = .{ .index = 4 },
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const current_location_text_surface: vxfw.SubSurface = .{
|
|
||||||
.origin = .{ .row = 0, .col = 0 },
|
|
||||||
.surface = try current_location_text_element.widget().draw(ctx),
|
|
||||||
// .surface = try vm.current_items.widget().draw(ctx),
|
|
||||||
};
|
|
||||||
|
|
||||||
try rootWidgets.append(current_location_text_surface);
|
{
|
||||||
|
const current_location_text = if (vm.app_common_model.appState.currentTab.currentLocation) |loc|
|
||||||
|
try std.fmt.allocPrint(ctx.arena, "{s} ", .{loc.item.fullName.path})
|
||||||
|
else
|
||||||
|
"";
|
||||||
|
const current_location_text_element = try ctx.arena.create(vxfw.Text);
|
||||||
|
current_location_text_element.* = vxfw.Text{
|
||||||
|
.text = current_location_text,
|
||||||
|
.overflow = .clip,
|
||||||
|
.softwrap = false,
|
||||||
|
.style = .{
|
||||||
|
.fg = .{ .index = 4 },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
try header.append(current_location_text_element.widget());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const currentTab = vm.app_common_model.appState.currentTab;
|
||||||
|
if (currentTab.currentItem) |currentItem| {
|
||||||
|
currentTab.currentItems.mutex.lock();
|
||||||
|
defer currentTab.currentItems.mutex.unlock();
|
||||||
|
|
||||||
|
if (currentTab.currentItems.data) |currentItems| {
|
||||||
|
const current_item_text =
|
||||||
|
for (currentItems.items) |item| {
|
||||||
|
const arc_item = item.retain();
|
||||||
|
defer if (arc_item.releaseUnwrap()) |i| i.deinit();
|
||||||
|
|
||||||
|
if (models.FullName.eql(&arc_item.value.*.fullName, ¤tItem)) {
|
||||||
|
break try std.fmt.allocPrint(ctx.arena, "{s} ", .{arc_item.value.*.displayName});
|
||||||
|
}
|
||||||
|
} else "";
|
||||||
|
|
||||||
|
const current_item_text_element = try ctx.arena.create(vxfw.Text);
|
||||||
|
current_item_text_element.* = vxfw.Text{
|
||||||
|
.text = current_item_text,
|
||||||
|
.overflow = .clip,
|
||||||
|
.softwrap = false,
|
||||||
|
.style = .{
|
||||||
|
.fg = .{ .index = 4 },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
try header.append(current_item_text_element.widget());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const head_items = try ctx.arena.alloc(vxfw.FlexItem, header.items.len);
|
||||||
|
|
||||||
|
for (0.., header.items) |i, item| {
|
||||||
|
head_items[i] = vxfw.FlexItem{
|
||||||
|
.widget = item,
|
||||||
|
.flex = 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const header_element = try ctx.arena.create(vxfw.FlexRow);
|
||||||
|
header_element.* = .{ .children = head_items };
|
||||||
|
|
||||||
|
const flex_column_surface: vxfw.SubSurface = .{
|
||||||
|
.origin = .{ .row = 0, .col = 0 },
|
||||||
|
.surface = try header_element.widget().draw(ctx),
|
||||||
|
};
|
||||||
|
|
||||||
|
try rootWidgets.append(flex_column_surface);
|
||||||
|
}
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.size = max_size,
|
.size = max_size,
|
||||||
@@ -120,20 +182,32 @@ const Model = struct {
|
|||||||
if (vm.crash) @panic("asd123");
|
if (vm.crash) @panic("asd123");
|
||||||
|
|
||||||
const text_items = blk2: {
|
const text_items = blk2: {
|
||||||
vm.app_common_model.current_items.mutex.lock();
|
const currentTab = vm.app_common_model.appState.currentTab;
|
||||||
defer vm.app_common_model.current_items.mutex.unlock();
|
const current_full_name = if (currentTab.currentItem) |currentItem|
|
||||||
|
models.FullName{ .path = try ctx.arena.dupe(u8, currentItem.path) }
|
||||||
|
else
|
||||||
|
null;
|
||||||
|
|
||||||
break :blk2 if (vm.app_common_model.current_items.data) |items| blk: {
|
currentTab.currentItems.mutex.lock();
|
||||||
|
defer currentTab.currentItems.mutex.unlock();
|
||||||
|
|
||||||
|
break :blk2 if (currentTab.currentItems.data) |items| blk: {
|
||||||
const children = try ctx.arena.create(std.ArrayList(*vxfw.Text));
|
const children = try ctx.arena.create(std.ArrayList(*vxfw.Text));
|
||||||
children.* = std.ArrayList(*vxfw.Text).init(ctx.arena);
|
children.* = std.ArrayList(*vxfw.Text).init(ctx.arena);
|
||||||
|
|
||||||
|
// const current_index = vm.current_items_view.cursor;
|
||||||
|
|
||||||
// const children = try ctx.arena.alloc(*vxfw.Text, items.len);
|
// const children = try ctx.arena.alloc(*vxfw.Text, items.len);
|
||||||
for (0.., items) |i, *weak_child| {
|
for (items.items) |*original_arc_child| {
|
||||||
const arc_child = weak_child.upgrade() orelse continue;
|
const arc_child = original_arc_child.retain();
|
||||||
defer if (arc_child.releaseUnwrap()) |item| item.deinit();
|
defer if (arc_child.releaseUnwrap()) |item| item.deinit();
|
||||||
|
|
||||||
const child = arc_child.value.*;
|
const child = arc_child.value.*;
|
||||||
const is_active = i == vm.current_items_view.cursor;
|
// const is_active = i == current_index;
|
||||||
|
const is_active = if (current_full_name) |c_full_name|
|
||||||
|
models.FullName.eql(&c_full_name, &child.fullName)
|
||||||
|
else
|
||||||
|
false;
|
||||||
|
|
||||||
const fg, const bg = colors: {
|
const fg, const bg = colors: {
|
||||||
var fg: vaxis.Color = .default;
|
var fg: vaxis.Color = .default;
|
||||||
@@ -271,6 +345,10 @@ pub fn main() !void {
|
|||||||
.draw_cursor = false,
|
.draw_cursor = false,
|
||||||
.children = .{ .slice = items },
|
.children = .{ .slice = items },
|
||||||
};
|
};
|
||||||
|
var list_widget = list.widget();
|
||||||
|
list_widget.eventHandler = struct {
|
||||||
|
fn a(_: *anyopaque, _: *vxfw.EventContext, _: vxfw.Event) anyerror!void {}
|
||||||
|
}.a;
|
||||||
|
|
||||||
var appState: AppState = AppState.init(allocator);
|
var appState: AppState = AppState.init(allocator);
|
||||||
try appState.addTab(tab1);
|
try appState.addTab(tab1);
|
||||||
@@ -287,13 +365,12 @@ pub fn main() !void {
|
|||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.app_common_model = &app_common_model,
|
.app_common_model = &app_common_model,
|
||||||
.current_items_view = &list,
|
.current_items_view = &list,
|
||||||
|
.current_items_view_widget = list_widget,
|
||||||
.root_provider = &rootProvider,
|
.root_provider = &rootProvider,
|
||||||
};
|
};
|
||||||
|
|
||||||
model.app_common_model.usage_number.data += 1;
|
model.app_common_model.usage_number.data += 1;
|
||||||
|
|
||||||
try pool.spawn(core.data_loop, .{model.app_common_model});
|
|
||||||
|
|
||||||
var app = try vxfw.App.init(allocator);
|
var app = try vxfw.App.init(allocator);
|
||||||
defer app.deinit();
|
defer app.deinit();
|
||||||
|
|
||||||
@@ -313,12 +390,12 @@ const vaxis = @import("vaxis");
|
|||||||
const vxfw = vaxis.vxfw;
|
const vxfw = vaxis.vxfw;
|
||||||
|
|
||||||
const models = @import("../core/models.zig");
|
const models = @import("../core/models.zig");
|
||||||
|
const ActionResult = @import("../core/action/action.zig").ActionResult;
|
||||||
const provider = @import("../core/provider/provider.zig");
|
const provider = @import("../core/provider/provider.zig");
|
||||||
const RootProvider = @import("../core/provider/root.zig").RootProvider;
|
const RootProvider = @import("../core/provider/root.zig").RootProvider;
|
||||||
const local_provider = @import("../core/provider/local.zig");
|
const local_provider = @import("../core/provider/local.zig");
|
||||||
const Tab = @import("../core/tab/tab.zig").Tab;
|
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 core = @import("../app_common/root.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 handle_key = @import("./action_map.zig").handle_key;
|
||||||
|
|||||||
@@ -1,4 +1,11 @@
|
|||||||
|
pub const ActionResult = union(enum) {
|
||||||
|
None,
|
||||||
|
Handled,
|
||||||
|
};
|
||||||
|
|
||||||
pub const Action = union(enum) {
|
pub const Action = union(enum) {
|
||||||
GoUp,
|
GoUp,
|
||||||
Enter,
|
Enter,
|
||||||
|
SelectNext,
|
||||||
|
SelectPrevious,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
pub fn handle(action: Action, appState: *AppState, arena: std.mem.Allocator) !void {
|
pub fn handle(action: Action, appState: *AppState, arena: std.mem.Allocator) !ActionResult {
|
||||||
switch (action) {
|
switch (action) {
|
||||||
.GoUp => {
|
.GoUp => {
|
||||||
if (appState.currentTab.currentLocation) |currentLocation| {
|
if (appState.currentTab.currentLocation) |currentLocation| {
|
||||||
@@ -6,14 +6,76 @@ pub fn handle(action: Action, appState: *AppState, arena: std.mem.Allocator) !vo
|
|||||||
if (parent) |p| {
|
if (parent) |p| {
|
||||||
const path = try arena.dupe(u8, p.path.path);
|
const path = try arena.dupe(u8, p.path.path);
|
||||||
try appState.currentTab.setCurrentLocation(.{ .path = path });
|
try appState.currentTab.setCurrentLocation(.{ .path = path });
|
||||||
|
return ActionResult.Handled;
|
||||||
} else return error.NoParent;
|
} else return error.NoParent;
|
||||||
} else return error.NoCurrentLocation;
|
} else return error.NoCurrentLocation;
|
||||||
},
|
},
|
||||||
.Enter => unreachable,
|
.Enter => {},
|
||||||
|
.SelectNext => {
|
||||||
|
return selectNextIndex(appState.currentTab, .Next);
|
||||||
|
},
|
||||||
|
.SelectPrevious => {
|
||||||
|
return selectNextIndex(appState.currentTab, .Previous);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ActionResult.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SelectStep = enum {
|
||||||
|
Next,
|
||||||
|
Previous,
|
||||||
|
NextPage,
|
||||||
|
PreviousPage,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn selectNextIndex(currentTab: *Tab, step: SelectStep) ActionResult {
|
||||||
|
const index = blk: {
|
||||||
|
currentTab.currentItems.mutex.lock();
|
||||||
|
defer currentTab.currentItems.mutex.unlock();
|
||||||
|
|
||||||
|
const currentItems = currentTab.currentItems.data orelse return ActionResult.None;
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
currentTab.selectItem(index) 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 std = @import("std");
|
||||||
const Action = @import("action.zig").Action;
|
const Action = @import("action.zig").Action;
|
||||||
|
const ActionResult = @import("action.zig").ActionResult;
|
||||||
const AppState = @import("../app_state.zig").AppState;
|
const AppState = @import("../app_state.zig").AppState;
|
||||||
const RootProvider = @import("../provider/root.zig").RootProvider;
|
const RootProvider = @import("../provider/root.zig").RootProvider;
|
||||||
|
const models = @import("../models.zig");
|
||||||
|
const Arc = @import("zigrc").Arc;
|
||||||
|
const Tab = @import("../tab/tab.zig").Tab;
|
||||||
|
|||||||
@@ -80,6 +80,10 @@ pub const FullName = struct {
|
|||||||
|
|
||||||
return FullName{ .path = path };
|
return FullName{ .path = path };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn eql(self: *const FullName, value: *const FullName) bool {
|
||||||
|
return std.mem.eql(u8, self.path, value.path);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const NativePath = struct {
|
pub const NativePath = struct {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ pub const Tab = struct {
|
|||||||
currentLocation: ?*Container,
|
currentLocation: ?*Container,
|
||||||
currentItems: locked(?std.ArrayList(Arc(*Item))),
|
currentItems: locked(?std.ArrayList(Arc(*Item))),
|
||||||
currentLocationChanged: Observable(?*Container),
|
currentLocationChanged: Observable(?*Container),
|
||||||
currentItemsChanged: bool = false,
|
currentItem: ?models.FullName,
|
||||||
threadPool: *std.Thread.Pool,
|
threadPool: *std.Thread.Pool,
|
||||||
rootProvider: *RootProvider,
|
rootProvider: *RootProvider,
|
||||||
|
|
||||||
@@ -18,6 +18,7 @@ pub const Tab = struct {
|
|||||||
.currentItems = .{ .data = null },
|
.currentItems = .{ .data = null },
|
||||||
.currentLocationChanged = Observable(?*Container).init(allocator),
|
.currentLocationChanged = Observable(?*Container).init(allocator),
|
||||||
.currentLocation = null,
|
.currentLocation = null,
|
||||||
|
.currentItem = null,
|
||||||
.threadPool = threadPool,
|
.threadPool = threadPool,
|
||||||
.rootProvider = rootProvider,
|
.rootProvider = rootProvider,
|
||||||
};
|
};
|
||||||
@@ -28,26 +29,54 @@ pub const Tab = struct {
|
|||||||
c.item.deinit();
|
c.item.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
errdefer {
|
if (self.currentItem) |i| {
|
||||||
self.currentLocation = null;
|
self.allocator.free(i.path);
|
||||||
self.currentLocationChanged.notify(null);
|
self.currentItem = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newLocation = try self.rootProvider.getItemByFullName(newLocationFullName, &.{}, self.allocator);
|
const newLocationContainer = blk: {
|
||||||
errdefer {
|
const newLocation = try self.rootProvider.getItemByFullName(newLocationFullName, &.{}, self.allocator);
|
||||||
newLocation.deinit();
|
errdefer {
|
||||||
}
|
newLocation.deinit();
|
||||||
|
self.currentLocation = null;
|
||||||
|
self.currentLocationChanged.notify(null);
|
||||||
|
}
|
||||||
|
|
||||||
const newLocationContainer = switch (newLocation.item) {
|
const newLocationContainer = switch (newLocation.item) {
|
||||||
.container => |c| c,
|
.container => |c| c,
|
||||||
.element => return error.NotContainer,
|
.element => return error.NotContainer,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.currentLocation = newLocationContainer;
|
||||||
|
break :blk newLocationContainer;
|
||||||
};
|
};
|
||||||
|
|
||||||
self.currentLocation = newLocationContainer;
|
|
||||||
self.currentLocationChanged.notify(newLocationContainer);
|
self.currentLocationChanged.notify(newLocationContainer);
|
||||||
|
|
||||||
//TODO: Proper error handling
|
//TODO: Proper error handling
|
||||||
std.Thread.Pool.spawn(self.threadPool, loadItemsWrapper, .{ self, newLocationContainer }) catch unreachable;
|
std.Thread.Pool.spawn(self.threadPool, loadItemsWrapper, .{ self, newLocationContainer }) catch unreachable;
|
||||||
|
|
||||||
|
self.selectItem(0) catch {
|
||||||
|
self.currentItem = null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn selectItem(self: *Tab, index: usize) !void {
|
||||||
|
self.currentItems.mutex.lock();
|
||||||
|
defer self.currentItems.mutex.unlock();
|
||||||
|
|
||||||
|
const currentItems = self.currentItems.data orelse return error.Error;
|
||||||
|
|
||||||
|
if (index >= currentItems.items.len) {
|
||||||
|
return error.OutOfRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.currentItem) |currentItem| {
|
||||||
|
self.allocator.free(currentItem.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.currentItem = models.FullName{
|
||||||
|
.path = try self.allocator.dupe(u8, currentItems.items[index].value.*.fullName.path),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn loadItemsWrapper(self: *Tab, location: *Container) void {
|
fn loadItemsWrapper(self: *Tab, location: *Container) void {
|
||||||
@@ -84,25 +113,25 @@ pub const Tab = struct {
|
|||||||
std.Thread.sleep(1 * std.time.ns_per_ms);
|
std.Thread.sleep(1 * std.time.ns_per_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (location.children.items) |item| {
|
for (location.children.items) |item_fullname| {
|
||||||
const resolvedItem = location.item.provider.getItemByFullName(item, &.{ .skipChildInit = true }, self.allocator) catch |e| {
|
const resolvedItem = location.item.provider.getItemByFullName(item_fullname, &.{ .skipChildInit = true }, self.allocator) catch |e| {
|
||||||
//TODO: save error to container errors
|
//TODO: save error to container errors
|
||||||
std.debug.print("error {} {s}\r\n", .{ e, item.path });
|
std.debug.print("error {} {s}\r\n", .{ e, item_fullname.path });
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
self.currentItems.mutex.lock();
|
self.currentItems.mutex.lock();
|
||||||
defer self.currentItems.mutex.unlock();
|
defer self.currentItems.mutex.unlock();
|
||||||
|
|
||||||
// const arc = try Arc(*Item).init(self.allocator, resolvedItem);
|
const index = for (self.currentItems.data.?.items, 0..) |item, i| {
|
||||||
// try self.currentItems.data.?.append(arc);
|
if (compareByDisplayName(resolvedItem, item.value.*)) break i;
|
||||||
try self.currentItems.data.?.append(try Arc(*Item).init(self.allocator, resolvedItem));
|
} else null;
|
||||||
}
|
const arc = try Arc(*Item).init(self.allocator, resolvedItem);
|
||||||
|
if (index) |i| {
|
||||||
{
|
try self.currentItems.data.?.insert(i, arc);
|
||||||
self.currentItems.mutex.lock();
|
} else {
|
||||||
defer self.currentItems.mutex.unlock();
|
try self.currentItems.data.?.append(arc);
|
||||||
self.currentItemsChanged = true;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,8 +151,18 @@ pub const Tab = struct {
|
|||||||
currentItems.deinit();
|
currentItems.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (self.currentItem) |currentItem| {
|
||||||
|
self.allocator.free(currentItem.path);
|
||||||
|
}
|
||||||
|
|
||||||
self.allocator.destroy(self);
|
self.allocator.destroy(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn compareByDisplayName(lhs: *models.Item, rhs: *models.Item) bool {
|
||||||
|
if (lhs.item == .container and rhs.item == .element) return true;
|
||||||
|
if (lhs.item == .element and rhs.item == .container) return false;
|
||||||
|
return std.mem.order(u8, lhs.displayName, rhs.displayName) == .lt;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|||||||
@@ -73,7 +73,6 @@ pub fn main() !void {
|
|||||||
};
|
};
|
||||||
|
|
||||||
defer model.core_model.deinit();
|
defer model.core_model.deinit();
|
||||||
try pool.spawn(core.data_loop, .{&model.core_model});
|
|
||||||
|
|
||||||
// init Raylib backend (creates OS window)
|
// init Raylib backend (creates OS window)
|
||||||
// initWindow() means the backend calls CloseWindow for you in deinit()
|
// initWindow() means the backend calls CloseWindow for you in deinit()
|
||||||
@@ -138,12 +137,14 @@ pub fn main() !void {
|
|||||||
|
|
||||||
fn dvui_frame(model: *Model) !void {
|
fn dvui_frame(model: *Model) !void {
|
||||||
{
|
{
|
||||||
model.core_model.current_items.mutex.lock();
|
const currentTab = model.core_model.appState.currentTab;
|
||||||
defer model.core_model.current_items.mutex.unlock();
|
|
||||||
|
|
||||||
if (model.core_model.current_items.data) |current_items| {
|
currentTab.currentItems.mutex.lock();
|
||||||
for (0.., current_items) |i, *weak_item| {
|
defer currentTab.currentItems.mutex.unlock();
|
||||||
const arc_item = weak_item.upgrade() orelse continue;
|
|
||||||
|
if (currentTab.currentItems.data) |current_items| {
|
||||||
|
for (0.., current_items.items) |i, *source_arc_item| {
|
||||||
|
const arc_item = source_arc_item.retain();
|
||||||
defer if (arc_item.releaseUnwrap()) |item| item.deinit();
|
defer if (arc_item.releaseUnwrap()) |item| item.deinit();
|
||||||
|
|
||||||
const item = arc_item.value.*;
|
const item = arc_item.value.*;
|
||||||
@@ -205,7 +206,6 @@ const provider = @import("../core/provider/provider.zig");
|
|||||||
const RootProvider = @import("../core/provider/root.zig").RootProvider;
|
const RootProvider = @import("../core/provider/root.zig").RootProvider;
|
||||||
const local_provider = @import("../core/provider/local.zig");
|
const local_provider = @import("../core/provider/local.zig");
|
||||||
const Tab = @import("../core/tab/tab.zig").Tab;
|
const Tab = @import("../core/tab/tab.zig").Tab;
|
||||||
const core = @import("../app_common/root.zig");
|
|
||||||
const AppState = @import("../core/app_state.zig").AppState;
|
const AppState = @import("../core/app_state.zig").AppState;
|
||||||
|
|
||||||
const dvui = @import("dvui");
|
const dvui = @import("dvui");
|
||||||
|
|||||||
Reference in New Issue
Block a user