feat(core): appstate
This commit is contained in:
@@ -1,14 +1,48 @@
|
|||||||
const std = @import("std");
|
|
||||||
const models = @import("../core/models.zig");
|
|
||||||
const Tab = @import("../core/tab/tab.zig").Tab;
|
|
||||||
const locked = @import("../core/sync.zig").locked;
|
|
||||||
|
|
||||||
running: bool = true,
|
running: bool = true,
|
||||||
usage_number: locked(u16) = .{ .data = 0 },
|
usage_number: locked(u16) = .{ .data = 0 },
|
||||||
current_items: locked(?[]*models.Item) = .{ .data = null },
|
current_items: locked(?[]*models.Item) = .{ .data = null },
|
||||||
current_items_allocator: std.heap.ArenaAllocator,
|
current_items_allocator: std.heap.ArenaAllocator,
|
||||||
tab: *Tab,
|
appState: AppState,
|
||||||
|
_private: Private,
|
||||||
|
|
||||||
|
const Private = struct {
|
||||||
|
preCurrentItemsUnload: Observer(*Tab),
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn init(model: *Self, currentItemsAllocator: std.heap.ArenaAllocator, appState: AppState) !void {
|
||||||
|
model.* = Self{
|
||||||
|
.current_items_allocator = currentItemsAllocator,
|
||||||
|
.appState = appState,
|
||||||
|
._private = .{
|
||||||
|
.preCurrentItemsUnload = Observer(*Tab){
|
||||||
|
.ctx = @ptrCast(@alignCast(model)),
|
||||||
|
.update = preCurrentItemsUnload,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
try model.appState.tabPreCurrentItemsUnload.attach(&model._private.preCurrentItemsUnload);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn preCurrentItemsUnload(ctx: *anyopaque, tab: *Tab) void {
|
||||||
|
const self: *Self = @ptrCast(@alignCast(ctx));
|
||||||
|
if (tab == self.appState.currentTab) {
|
||||||
|
// @panic("asdasdasd");
|
||||||
|
self.current_items.mutex.lock();
|
||||||
|
defer self.current_items.mutex.unlock();
|
||||||
|
|
||||||
|
self.current_items.data = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *@This()) void {
|
pub fn deinit(self: *@This()) void {
|
||||||
self.current_items_allocator.deinit();
|
self.current_items_allocator.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const models = @import("../core/models.zig");
|
||||||
|
const Tab = @import("../core/tab/tab.zig").Tab;
|
||||||
|
const locked = @import("../core/sync.zig").locked;
|
||||||
|
const AppState = @import("../core/app_state.zig").AppState;
|
||||||
|
const Observer = @import("../core/observable.zig").Observer;
|
||||||
|
const Self = @This();
|
||||||
|
|||||||
@@ -11,18 +11,24 @@ pub fn data_loop(vm: *Model) void {
|
|||||||
vm.usage_number.data -= 1;
|
vm.usage_number.data -= 1;
|
||||||
}
|
}
|
||||||
fn inner_loop(vm: *Model) !void {
|
fn inner_loop(vm: *Model) !void {
|
||||||
if (vm.tab.currentItemsChanged) {
|
const tab = vm.appState.currentTab;
|
||||||
|
if (tab.currentItemsChanged) {
|
||||||
std.Thread.sleep(10 * std.time.ns_per_ms);
|
std.Thread.sleep(10 * std.time.ns_per_ms);
|
||||||
|
|
||||||
vm.tab.currentItems.mutex.lock();
|
tab.currentItems.mutex.lock();
|
||||||
defer vm.tab.currentItems.mutex.unlock();
|
defer tab.currentItems.mutex.unlock();
|
||||||
|
|
||||||
if (vm.tab.currentItems.data) |current_items| {
|
if (tab.currentItems.data) |tab_current_items| {
|
||||||
|
{
|
||||||
|
vm.current_items.mutex.lock();
|
||||||
|
defer vm.current_items.mutex.unlock();
|
||||||
|
vm.current_items.data = null;
|
||||||
|
}
|
||||||
_ = vm.current_items_allocator.reset(.retain_capacity);
|
_ = vm.current_items_allocator.reset(.retain_capacity);
|
||||||
const allocator = vm.current_items_allocator.allocator();
|
const allocator = vm.current_items_allocator.allocator();
|
||||||
|
|
||||||
const items = try allocator.alloc(*models.Item, current_items.items.len);
|
const items = try allocator.alloc(*models.Item, tab_current_items.items.len);
|
||||||
for (current_items.items, 0..) |item, i| {
|
for (tab_current_items.items, 0..) |item, i| {
|
||||||
items[i] = item;
|
items[i] = item;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,8 +43,7 @@ fn inner_loop(vm: *Model) !void {
|
|||||||
vm.current_items.mutex.lock();
|
vm.current_items.mutex.lock();
|
||||||
defer vm.current_items.mutex.unlock();
|
defer vm.current_items.mutex.unlock();
|
||||||
vm.current_items.data = items;
|
vm.current_items.data = items;
|
||||||
|
tab.currentItemsChanged = false;
|
||||||
vm.tab.currentItemsChanged = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
11
src/console/action_map.zig
Normal file
11
src/console/action_map.zig
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
pub fn handle_key(key: vaxis.Key, appState: *AppState) !void {
|
||||||
|
if (key.matches(vaxis.Key.left, .{})) {
|
||||||
|
try handle_action(Action.GoUp, appState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const vaxis = @import("vaxis");
|
||||||
|
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 +1,10 @@
|
|||||||
const std = @import("std");
|
|
||||||
const vaxis = @import("vaxis");
|
|
||||||
const vxfw = vaxis.vxfw;
|
|
||||||
|
|
||||||
const models = @import("../core/models.zig");
|
|
||||||
const provider = @import("../core/provider/provider.zig");
|
|
||||||
const local_provider = @import("../core/provider/local.zig");
|
|
||||||
const Tab = @import("../core/tab/tab.zig").Tab;
|
|
||||||
const locked = @import("../core/sync.zig").locked;
|
|
||||||
const CoreModel = @import("../app_common/Model.zig");
|
|
||||||
const core = @import("../app_common/root.zig");
|
|
||||||
|
|
||||||
/// Our main application state
|
/// 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,
|
||||||
core_model: CoreModel,
|
core_model: CoreModel,
|
||||||
|
root_provider: *RootProvider,
|
||||||
|
|
||||||
/// 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 {
|
||||||
@@ -36,11 +25,17 @@ const Model = struct {
|
|||||||
ctx.quit = true;
|
ctx.quit = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (key.matches('r', .{ .ctrl = true })) {
|
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;
|
||||||
|
// return ctx.requestFocus(vm.current_items_view.widget());
|
||||||
|
// }
|
||||||
|
|
||||||
|
handle_key(key, &vm.core_model.appState) catch {};
|
||||||
},
|
},
|
||||||
.focus_in => return ctx.requestFocus(vm.current_items_view.widget()),
|
.focus_in => return ctx.requestFocus(vm.current_items_view.widget()),
|
||||||
else => {},
|
else => {},
|
||||||
@@ -93,7 +88,7 @@ const Model = struct {
|
|||||||
};
|
};
|
||||||
try rootWidgets.append(list_surface);
|
try rootWidgets.append(list_surface);
|
||||||
|
|
||||||
const current_location_text = if (vm.core_model.tab.currentLocation) |loc| loc.item.fullName.path else "";
|
const current_location_text = if (vm.core_model.appState.currentTab.currentLocation) |loc| loc.item.fullName.path else "";
|
||||||
const current_location_text_element = try ctx.arena.create(vxfw.Text);
|
const current_location_text_element = try ctx.arena.create(vxfw.Text);
|
||||||
current_location_text_element.* = vxfw.Text{
|
current_location_text_element.* = vxfw.Text{
|
||||||
.text = current_location_text,
|
.text = current_location_text,
|
||||||
@@ -218,24 +213,26 @@ pub fn main() !void {
|
|||||||
defer pool.deinit();
|
defer pool.deinit();
|
||||||
|
|
||||||
var localContentProvider = local_provider.LocalContentProvider{ .threadPool = &pool };
|
var localContentProvider = local_provider.LocalContentProvider{ .threadPool = &pool };
|
||||||
|
var localContentProv = localContentProvider.provider();
|
||||||
|
|
||||||
const homeFullName: models.FullName = .{ .path = "/home/adam" };
|
var rootProvider = RootProvider.init(allocator);
|
||||||
const homeItem = try localContentProvider.getItemByFullName(homeFullName, &.{}, allocator);
|
defer rootProvider.deinit();
|
||||||
const c = switch (homeItem.item) {
|
|
||||||
.container => |c| c,
|
try rootProvider.providers.append(&localContentProv);
|
||||||
.element => unreachable,
|
|
||||||
};
|
const current_path = try std.fs.cwd().realpathAlloc(allocator, ".");
|
||||||
|
defer allocator.free(current_path);
|
||||||
|
|
||||||
|
const start_full_name = try local_provider.getFullNameByNativePath(allocator, models.NativePath{ .path = current_path });
|
||||||
|
defer allocator.free(start_full_name.path);
|
||||||
|
|
||||||
var tab1 = try allocator.create(Tab);
|
var tab1 = try allocator.create(Tab);
|
||||||
defer allocator.destroy(tab1);
|
defer allocator.destroy(tab1);
|
||||||
|
|
||||||
tab1.init(&pool, allocator);
|
tab1.init(&pool, &rootProvider, allocator);
|
||||||
defer tab1.deinit();
|
defer tab1.deinit();
|
||||||
|
|
||||||
tab1.setCurrentLocation(c);
|
try tab1.setCurrentLocation(start_full_name);
|
||||||
|
|
||||||
const model = try allocator.create(Model);
|
|
||||||
defer allocator.destroy(model);
|
|
||||||
|
|
||||||
// TODO: remove
|
// TODO: remove
|
||||||
std.Thread.sleep(1 * std.time.ns_per_s);
|
std.Thread.sleep(1 * std.time.ns_per_s);
|
||||||
@@ -260,13 +257,21 @@ pub fn main() !void {
|
|||||||
.draw_cursor = false,
|
.draw_cursor = false,
|
||||||
.children = .{ .slice = items },
|
.children = .{ .slice = items },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var appState: AppState = AppState.init(allocator);
|
||||||
|
appState.currentTab = tab1;
|
||||||
|
|
||||||
|
const model = try allocator.create(Model);
|
||||||
|
defer allocator.destroy(model);
|
||||||
|
|
||||||
|
var core_model: CoreModel = undefined;
|
||||||
|
try CoreModel.init(&core_model, std.heap.ArenaAllocator.init(allocator), appState);
|
||||||
|
|
||||||
model.* = .{
|
model.* = .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.core_model = .{
|
.core_model = core_model,
|
||||||
.current_items_allocator = std.heap.ArenaAllocator.init(allocator),
|
|
||||||
.tab = tab1,
|
|
||||||
},
|
|
||||||
.current_items_view = &list,
|
.current_items_view = &list,
|
||||||
|
.root_provider = &rootProvider,
|
||||||
};
|
};
|
||||||
defer model.core_model.deinit();
|
defer model.core_model.deinit();
|
||||||
|
|
||||||
@@ -288,4 +293,17 @@ pub fn main() !void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const asd1 = @import("../core/allocator.zig");
|
const std = @import("std");
|
||||||
|
const vaxis = @import("vaxis");
|
||||||
|
const vxfw = vaxis.vxfw;
|
||||||
|
|
||||||
|
const models = @import("../core/models.zig");
|
||||||
|
const provider = @import("../core/provider/provider.zig");
|
||||||
|
const RootProvider = @import("../core/provider/root.zig").RootProvider;
|
||||||
|
const local_provider = @import("../core/provider/local.zig");
|
||||||
|
const Tab = @import("../core/tab/tab.zig").Tab;
|
||||||
|
const locked = @import("../core/sync.zig").locked;
|
||||||
|
const CoreModel = @import("../app_common/Model.zig");
|
||||||
|
const core = @import("../app_common/root.zig");
|
||||||
|
const AppState = @import("../core/app_state.zig").AppState;
|
||||||
|
const handle_key = @import("./action_map.zig").handle_key;
|
||||||
|
|||||||
4
src/core/action/action.zig
Normal file
4
src/core/action/action.zig
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
pub const Action = union(enum) {
|
||||||
|
GoUp,
|
||||||
|
Enter,
|
||||||
|
};
|
||||||
17
src/core/action/action_handler.zig
Normal file
17
src/core/action/action_handler.zig
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
pub fn handle(action: Action, appState: *AppState) !void {
|
||||||
|
switch (action) {
|
||||||
|
.GoUp => {
|
||||||
|
if (appState.currentTab.currentLocation) |currentLocation| {
|
||||||
|
const parent = currentLocation.item.parent;
|
||||||
|
if (parent) |p| {
|
||||||
|
try appState.currentTab.setCurrentLocation(.{ .path = p.path.path });
|
||||||
|
} else return error.NoParent;
|
||||||
|
} else return error.NoCurrentLocation;
|
||||||
|
},
|
||||||
|
.Enter => unreachable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Action = @import("action.zig").Action;
|
||||||
|
const AppState = @import("../app_state.zig").AppState;
|
||||||
|
const RootProvider = @import("../provider/root.zig").RootProvider;
|
||||||
50
src/core/app_state.zig
Normal file
50
src/core/app_state.zig
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
pub const UnknownTabError = error.UnknownTab;
|
||||||
|
|
||||||
|
pub const AppState = struct {
|
||||||
|
currentTab: *Tab = undefined,
|
||||||
|
tabs: std.ArrayList(Tab),
|
||||||
|
currentTabChanged: Observable(*Tab),
|
||||||
|
tabPreCurrentItemsUnload: Observable(*Tab),
|
||||||
|
|
||||||
|
pub fn init(allocator: std.mem.Allocator) AppState {
|
||||||
|
return .{
|
||||||
|
.tabs = std.ArrayList(Tab).init(allocator),
|
||||||
|
.currentTabChanged = Observable(*Tab).init(allocator),
|
||||||
|
.tabPreCurrentItemsUnload = Observable(*Tab).init(allocator),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addTab(self: *AppState, tab: Tab) void {
|
||||||
|
self.tabs.append(tab);
|
||||||
|
// tab.preCurrentItemsUnload.attach(.{
|
||||||
|
// .ctx = @ptrCast(@alignCast(self)),
|
||||||
|
// .update = preCurrentItemsUnload,
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setCurrentTab(self: *AppState, newTab: *Tab) !void {
|
||||||
|
blk: {
|
||||||
|
for (self.tabs.items) |item| {
|
||||||
|
if (item == newTab) break :blk;
|
||||||
|
}
|
||||||
|
return UnknownTabError;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.currentTab = newTab;
|
||||||
|
self.currentTabChanged.notify(newTab);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *AppState) void {
|
||||||
|
self.currentTabChanged.deinit();
|
||||||
|
self.tabs.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preCurrentItemsUnload(ctx: *anyopaque, tab: *Tab) void {
|
||||||
|
const self: AppState = @ptrCast(@alignCast(ctx));
|
||||||
|
self.tabPreCurrentItemsUnload.notify(tab);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const Tab = @import("tab/tab.zig").Tab;
|
||||||
|
const Observable = @import("observable.zig").Observable;
|
||||||
@@ -54,18 +54,26 @@ pub const Container = struct {
|
|||||||
self.item.allocator.free(itemFullName.path);
|
self.item.allocator.free(itemFullName.path);
|
||||||
}
|
}
|
||||||
self.children.deinit();
|
self.children.deinit();
|
||||||
self.item.allocator.destroy(self);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const FullName = struct {
|
pub const FullName = struct {
|
||||||
path: []const u8,
|
path: []const u8,
|
||||||
|
|
||||||
pub fn getChild(self: *FullName, childName: []const u8, allocator: std.mem.Allocator) !FullName {
|
pub fn getChild(self: *const FullName, childName: []const u8, allocator: std.mem.Allocator) !FullName {
|
||||||
const path = try std.fmt.allocPrint(allocator, "{s}{s}{s}", .{ self.path, consts.PathSeparator, childName });
|
const path = try std.fmt.allocPrint(allocator, "{s}{s}{s}", .{ self.path, consts.PathSeparator, childName });
|
||||||
|
|
||||||
return FullName{ .path = path };
|
return FullName{ .path = path };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn getParent(self: *const FullName, allocator: std.mem.Allocator) !?FullName {
|
||||||
|
const lastIndex = std.mem.lastIndexOf(u8, self.path, consts.PathSeparator) orelse return null;
|
||||||
|
if (lastIndex == 0) return null;
|
||||||
|
|
||||||
|
const path = try std.fmt.allocPrint(allocator, "{s}", .{self.path[0..lastIndex]});
|
||||||
|
|
||||||
|
return FullName{ .path = path };
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const NativePath = struct {
|
pub const NativePath = struct {
|
||||||
@@ -73,7 +81,7 @@ pub const NativePath = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const AbsolutePath = struct {
|
pub const AbsolutePath = struct {
|
||||||
path: []const u8,
|
path: FullName,
|
||||||
type: AbsolutePathType,
|
type: AbsolutePathType,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -81,7 +89,7 @@ pub const Error = struct {
|
|||||||
content: []const u8,
|
content: []const u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const AbsolutePathType = enum {
|
pub const AbsolutePathType = union(enum) {
|
||||||
Container,
|
container,
|
||||||
Item,
|
item,
|
||||||
};
|
};
|
||||||
|
|||||||
41
src/core/observable.zig
Normal file
41
src/core/observable.zig
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
pub fn Observable(T: type) type {
|
||||||
|
return struct {
|
||||||
|
observers: std.ArrayList(*const Observer(T)),
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
pub fn init(allocator: std.mem.Allocator) Self {
|
||||||
|
return .{
|
||||||
|
.observers = std.ArrayList(*const Observer(T)).init(allocator),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Self) void {
|
||||||
|
self.observers.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn attach(self: *Self, obs: *const Observer(T)) !void {
|
||||||
|
try self.observers.append(obs);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn detach(self: *Self, obs: *const Observer(T)) void {
|
||||||
|
if (std.mem.indexOfScalar(*const Observer, self.observers.items, obs)) |index| {
|
||||||
|
_ = self.observers.swapRemove(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn notify(self: Self, args: T) void {
|
||||||
|
for (self.observers.items) |obs| {
|
||||||
|
obs.update(obs.ctx, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn Observer(T: type) type {
|
||||||
|
return struct {
|
||||||
|
ctx: *anyopaque,
|
||||||
|
update: *const fn (ctx: *anyopaque, args: T) void,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
@@ -1,15 +1,4 @@
|
|||||||
const std = @import("std");
|
pub const LocalProviderId = "local";
|
||||||
const models = @import("../models.zig");
|
|
||||||
const Provider = @import("provider.zig").Provider;
|
|
||||||
const ProviderVTable = @import("provider.zig").VTable;
|
|
||||||
const GetItemsError = @import("provider.zig").GetItemsError;
|
|
||||||
const InitContext = @import("provider.zig").InitContext;
|
|
||||||
|
|
||||||
const FullName = models.FullName;
|
|
||||||
const Item = models.Item;
|
|
||||||
const ItemEnum = models.ItemEnum;
|
|
||||||
const Element = models.Element;
|
|
||||||
const Container = models.Container;
|
|
||||||
|
|
||||||
// TODO: the container might be freed while this runs
|
// TODO: the container might be freed while this runs
|
||||||
// Tab should hold something at pass it here
|
// Tab should hold something at pass it here
|
||||||
@@ -18,6 +7,7 @@ fn loadChildren(container: *Container) void {
|
|||||||
container.childrenLoading = false;
|
container.childrenLoading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std.debug.print("load children {s}", .{container.item.nativePath.path});
|
||||||
var dir = std.fs.cwd().openDir(container.item.nativePath.path, .{ .iterate = true }) catch {
|
var dir = std.fs.cwd().openDir(container.item.nativePath.path, .{ .iterate = true }) catch {
|
||||||
// const errorContent = std.fmt.allocPrint(container.item.allocator, "Could not open directory '{s}'.", .{container.item.nativePath.path}) catch return;
|
// const errorContent = std.fmt.allocPrint(container.item.allocator, "Could not open directory '{s}'.", .{container.item.nativePath.path}) catch return;
|
||||||
// container.item.errors.append(.{ .content = errorContent }) catch return;
|
// container.item.errors.append(.{ .content = errorContent }) catch return;
|
||||||
@@ -35,6 +25,8 @@ fn loadChildren(container: *Container) void {
|
|||||||
|
|
||||||
const VTable: ProviderVTable = .{
|
const VTable: ProviderVTable = .{
|
||||||
.getItemByFullName = getItemByFullNameGeneric,
|
.getItemByFullName = getItemByFullNameGeneric,
|
||||||
|
.canHandle = canHandleGeneric,
|
||||||
|
.deinit = deinitGeneric,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn getItemByFullNameGeneric(
|
pub fn getItemByFullNameGeneric(
|
||||||
@@ -47,6 +39,43 @@ pub fn getItemByFullNameGeneric(
|
|||||||
return self.getItemByFullName(fullName, initContext, allocator);
|
return self.getItemByFullName(fullName, initContext, allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn canHandleGeneric(
|
||||||
|
context: *anyopaque,
|
||||||
|
fullName: FullName,
|
||||||
|
) bool {
|
||||||
|
const self: *LocalContentProvider = @ptrCast(@alignCast(context));
|
||||||
|
return self.canHandle(fullName);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinitGeneric(_: *anyopaque) void {}
|
||||||
|
|
||||||
|
pub fn getFullNameByNativePath(allocator: std.mem.Allocator, nativePath: NativePath) !FullName {
|
||||||
|
const correct_sep = try std.mem.replaceOwned(u8, allocator, nativePath.path, std.fs.path.sep_str, "/");
|
||||||
|
defer allocator.free(correct_sep);
|
||||||
|
|
||||||
|
const asd = if (std.mem.startsWith(u8, correct_sep, "/"))
|
||||||
|
correct_sep[1..]
|
||||||
|
else
|
||||||
|
correct_sep;
|
||||||
|
|
||||||
|
const full_name_path = try std.fmt.allocPrint(allocator, "{s}/{s}", .{ LocalProviderId, asd });
|
||||||
|
|
||||||
|
return .{ .path = full_name_path };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getNativePathByFullName(allocator: std.mem.Allocator, fullName: FullName) ![]u8 {
|
||||||
|
const fullNameWithoutId = fullName.path[LocalProviderId.len + 1 ..];
|
||||||
|
var native_path = try std.mem.replaceOwned(u8, allocator, fullNameWithoutId, "/", std.fs.path.sep_str);
|
||||||
|
|
||||||
|
if (native_os == .linux) {
|
||||||
|
const linux_native_path = try std.fmt.allocPrint(allocator, "/{s}", .{native_path});
|
||||||
|
allocator.free(native_path);
|
||||||
|
native_path = linux_native_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
return native_path;
|
||||||
|
}
|
||||||
|
|
||||||
pub const LocalContentProvider = struct {
|
pub const LocalContentProvider = struct {
|
||||||
threadPool: *std.Thread.Pool,
|
threadPool: *std.Thread.Pool,
|
||||||
|
|
||||||
@@ -56,7 +85,7 @@ pub const LocalContentProvider = struct {
|
|||||||
initContext: *const InitContext,
|
initContext: *const InitContext,
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
) GetItemsError!*Item {
|
) GetItemsError!*Item {
|
||||||
const native_path = try std.mem.replaceOwned(u8, allocator, fullName.path, "/", std.fs.path.sep_str);
|
const native_path = try getNativePathByFullName(allocator, fullName);
|
||||||
defer allocator.free(native_path);
|
defer allocator.free(native_path);
|
||||||
|
|
||||||
const kind: union(enum) { directory, file } = blk: {
|
const kind: union(enum) { directory, file } = blk: {
|
||||||
@@ -139,7 +168,10 @@ pub const LocalContentProvider = struct {
|
|||||||
const name = try allocator.dupe(u8, basename);
|
const name = try allocator.dupe(u8, basename);
|
||||||
const displayName = try allocator.dupe(u8, basename);
|
const displayName = try allocator.dupe(u8, basename);
|
||||||
const fullName2 = try allocator.dupe(u8, fullName.path);
|
const fullName2 = try allocator.dupe(u8, fullName.path);
|
||||||
const nativePath = try allocator.dupe(u8, fullName.path);
|
const nativePath = try getNativePathByFullName(allocator, fullName);
|
||||||
|
|
||||||
|
const parentFullName = try fullName.getParent(allocator);
|
||||||
|
const parent = if (parentFullName) |p| models.AbsolutePath{ .path = p, .type = .container } else null;
|
||||||
|
|
||||||
item.* = Item{
|
item.* = Item{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
@@ -148,12 +180,19 @@ pub const LocalContentProvider = struct {
|
|||||||
.displayName = displayName,
|
.displayName = displayName,
|
||||||
.fullName = .{ .path = fullName2 },
|
.fullName = .{ .path = fullName2 },
|
||||||
.nativePath = models.NativePath{ .path = nativePath },
|
.nativePath = models.NativePath{ .path = nativePath },
|
||||||
.parent = null,
|
.parent = parent,
|
||||||
.item = innerItem,
|
.item = innerItem,
|
||||||
.errors = std.ArrayList(models.Error).init(allocator),
|
.errors = std.ArrayList(models.Error).init(allocator),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn canHandle(
|
||||||
|
_: *LocalContentProvider,
|
||||||
|
fullName: FullName,
|
||||||
|
) bool {
|
||||||
|
return std.mem.startsWith(u8, fullName.path, "local/");
|
||||||
|
}
|
||||||
|
|
||||||
pub fn provider(self: *LocalContentProvider) Provider {
|
pub fn provider(self: *LocalContentProvider) Provider {
|
||||||
return Provider{
|
return Provider{
|
||||||
.object = self,
|
.object = self,
|
||||||
@@ -161,3 +200,18 @@ pub const LocalContentProvider = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const models = @import("../models.zig");
|
||||||
|
const Provider = @import("provider.zig").Provider;
|
||||||
|
const ProviderVTable = @import("provider.zig").VTable;
|
||||||
|
const GetItemsError = @import("provider.zig").GetItemsError;
|
||||||
|
const InitContext = @import("provider.zig").InitContext;
|
||||||
|
|
||||||
|
const FullName = models.FullName;
|
||||||
|
const NativePath = models.NativePath;
|
||||||
|
const Item = models.Item;
|
||||||
|
const ItemEnum = models.ItemEnum;
|
||||||
|
const Element = models.Element;
|
||||||
|
const Container = models.Container;
|
||||||
|
const native_os = @import("builtin").os.tag;
|
||||||
|
|||||||
@@ -5,6 +5,13 @@ pub const VTable = struct {
|
|||||||
initContext: *const InitContext,
|
initContext: *const InitContext,
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
) GetItemsError!*Item,
|
) GetItemsError!*Item,
|
||||||
|
|
||||||
|
canHandle: *const fn (
|
||||||
|
self: *anyopaque,
|
||||||
|
fullName: FullName,
|
||||||
|
) bool,
|
||||||
|
|
||||||
|
deinit: *const fn (self: *anyopaque) void,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const GetItemsError = error{
|
pub const GetItemsError = error{
|
||||||
@@ -25,6 +32,17 @@ pub const Provider = struct {
|
|||||||
) GetItemsError!*Item {
|
) GetItemsError!*Item {
|
||||||
return self.vtable.getItemByFullName(self.object, fullName, initContext, allocator);
|
return self.vtable.getItemByFullName(self.object, fullName, initContext, allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub inline fn canHandle(
|
||||||
|
self: *const Provider,
|
||||||
|
fullName: FullName,
|
||||||
|
) bool {
|
||||||
|
return self.vtable.canHandle(self.object, fullName);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn deinit(self: *const Provider) void {
|
||||||
|
return self.vtable.deinit(self.object);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const InitContext = struct {
|
pub const InitContext = struct {
|
||||||
|
|||||||
45
src/core/provider/root.zig
Normal file
45
src/core/provider/root.zig
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
pub const RootGetItemsError = GetItemsError || error{ProviderNotFound};
|
||||||
|
pub const RootProvider = struct {
|
||||||
|
providers: std.ArrayList(*Provider),
|
||||||
|
pub fn init(allocator: std.mem.Allocator) RootProvider {
|
||||||
|
return .{
|
||||||
|
.providers = std.ArrayList(*Provider).init(allocator),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getItemByFullName(
|
||||||
|
self: *const RootProvider,
|
||||||
|
fullName: FullName,
|
||||||
|
initContext: *const InitContext,
|
||||||
|
allocator: std.mem.Allocator,
|
||||||
|
) RootGetItemsError!*Item {
|
||||||
|
const provider = for (self.providers.items) |provider| {
|
||||||
|
if (provider.canHandle(fullName)) {
|
||||||
|
break provider;
|
||||||
|
}
|
||||||
|
} else return error.ProviderNotFound;
|
||||||
|
|
||||||
|
return provider.getItemByFullName(fullName, initContext, allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addProvider(self: *Provider, provider: *Provider) !void {
|
||||||
|
try self.providers.append(provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(
|
||||||
|
self: *const RootProvider,
|
||||||
|
) void {
|
||||||
|
for (self.providers.items) |p| {
|
||||||
|
p.deinit();
|
||||||
|
}
|
||||||
|
self.providers.deinit();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const Provider = @import("./provider.zig").Provider;
|
||||||
|
const InitContext = @import("./provider.zig").InitContext;
|
||||||
|
const GetItemsError = @import("./provider.zig").GetItemsError;
|
||||||
|
const models = @import("../models.zig");
|
||||||
|
const FullName = models.FullName;
|
||||||
|
const Item = models.Item;
|
||||||
@@ -1,19 +1,12 @@
|
|||||||
const std = @import("std");
|
|
||||||
const assert = std.debug.assert;
|
|
||||||
const Mutex = std.Thread.Mutex;
|
|
||||||
|
|
||||||
const models = @import("../models.zig");
|
|
||||||
const Container = models.Container;
|
|
||||||
const Item = models.Item;
|
|
||||||
|
|
||||||
const locked = @import("../sync.zig").locked;
|
|
||||||
|
|
||||||
pub const Tab = struct {
|
pub const Tab = struct {
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
currentLocation: ?*Container,
|
currentLocation: ?*Container,
|
||||||
currentItems: locked(?std.ArrayList(*Item)),
|
currentItems: locked(?std.ArrayList(*Item)),
|
||||||
|
currentLocationChanged: Observable(?*Container),
|
||||||
currentItemsChanged: bool = false,
|
currentItemsChanged: bool = false,
|
||||||
|
preCurrentItemsUnload: Observable(*Tab),
|
||||||
threadPool: *std.Thread.Pool,
|
threadPool: *std.Thread.Pool,
|
||||||
|
rootProvider: *RootProvider,
|
||||||
_private: Private,
|
_private: Private,
|
||||||
|
|
||||||
const Private = struct {
|
const Private = struct {
|
||||||
@@ -23,44 +16,67 @@ pub const Tab = struct {
|
|||||||
pub fn init(
|
pub fn init(
|
||||||
self: *Tab,
|
self: *Tab,
|
||||||
threadPool: *std.Thread.Pool,
|
threadPool: *std.Thread.Pool,
|
||||||
|
rootProvider: *RootProvider,
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
) void {
|
) void {
|
||||||
self.* = Tab{
|
self.* = Tab{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.currentItems = .{ .data = null },
|
.currentItems = .{ .data = null },
|
||||||
|
.currentLocationChanged = Observable(?*Container).init(allocator),
|
||||||
.currentLocation = null,
|
.currentLocation = null,
|
||||||
.threadPool = threadPool,
|
.threadPool = threadPool,
|
||||||
|
.rootProvider = rootProvider,
|
||||||
|
.preCurrentItemsUnload = Observable(*Tab).init(allocator),
|
||||||
._private = .{
|
._private = .{
|
||||||
.currentItemsAllocator = std.heap.ArenaAllocator.init(allocator),
|
.currentItemsAllocator = std.heap.ArenaAllocator.init(allocator),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setCurrentLocation(self: *Tab, newLocation: *Container) 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.allocator.destroy(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.currentLocation = newLocation;
|
errdefer {
|
||||||
|
self.currentLocation = null;
|
||||||
|
self.currentLocationChanged.notify(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
const newLocation = try self.rootProvider.getItemByFullName(newLocationFullName, &.{}, self.allocator);
|
||||||
|
|
||||||
|
const newLocationContainer = switch (newLocation.item) {
|
||||||
|
.container => |c| c,
|
||||||
|
.element => return error.NotContainer,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.currentLocation = newLocationContainer;
|
||||||
|
self.currentLocationChanged.notify(newLocationContainer);
|
||||||
|
|
||||||
//TODO: Proper error handling
|
//TODO: Proper error handling
|
||||||
std.Thread.Pool.spawn(self.threadPool, loadItemsWrapper, .{ self, newLocation }) catch unreachable;
|
std.Thread.Pool.spawn(self.threadPool, loadItemsWrapper, .{ self, newLocationContainer }) catch unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn loadItemsWrapper(self: *Tab, location: *Container) void {
|
fn loadItemsWrapper(self: *Tab, location: *Container) void {
|
||||||
loadItems(self, location) catch return;
|
loadItems(self, location) catch return;
|
||||||
}
|
}
|
||||||
fn loadItems(self: *Tab, location: *Container) !void {
|
fn loadItems(self: *Tab, location: *Container) !void {
|
||||||
_ = self._private.currentItemsAllocator.reset(.retain_capacity);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
self.currentItems.mutex.lock();
|
self.currentItems.mutex.lock();
|
||||||
defer self.currentItems.mutex.unlock();
|
defer self.currentItems.mutex.unlock();
|
||||||
|
|
||||||
|
self.preCurrentItemsUnload.notify(self);
|
||||||
|
|
||||||
if (self.currentItems.data) |items| {
|
if (self.currentItems.data) |items| {
|
||||||
items.deinit();
|
items.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.currentItems.data = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_ = self._private.currentItemsAllocator.reset(.retain_capacity);
|
||||||
|
|
||||||
const arenaAllocator = &self._private.currentItemsAllocator;
|
const arenaAllocator = &self._private.currentItemsAllocator;
|
||||||
const arena = arenaAllocator.allocator();
|
const arena = arenaAllocator.allocator();
|
||||||
|
|
||||||
@@ -90,7 +106,7 @@ pub const Tab = struct {
|
|||||||
for (location.children.items) |item| {
|
for (location.children.items) |item| {
|
||||||
const resolvedItem = location.item.provider.getItemByFullName(item, &.{ .skipChildInit = true }, allocator) catch |e| {
|
const resolvedItem = location.item.provider.getItemByFullName(item, &.{ .skipChildInit = true }, 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.path });
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -98,6 +114,11 @@ pub const Tab = struct {
|
|||||||
defer self.currentItems.mutex.unlock();
|
defer self.currentItems.mutex.unlock();
|
||||||
|
|
||||||
try self.currentItems.data.?.append(resolvedItem);
|
try self.currentItems.data.?.append(resolvedItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
self.currentItems.mutex.lock();
|
||||||
|
defer self.currentItems.mutex.unlock();
|
||||||
self.currentItemsChanged = true;
|
self.currentItemsChanged = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,3 +130,15 @@ pub const Tab = struct {
|
|||||||
self._private.currentItemsAllocator.deinit();
|
self._private.currentItemsAllocator.deinit();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
const Mutex = std.Thread.Mutex;
|
||||||
|
|
||||||
|
const models = @import("../models.zig");
|
||||||
|
const Container = models.Container;
|
||||||
|
const Item = models.Item;
|
||||||
|
|
||||||
|
const locked = @import("../sync.zig").locked;
|
||||||
|
const Observable = @import("../observable.zig").Observable;
|
||||||
|
const RootProvider = @import("../provider/root.zig").RootProvider;
|
||||||
|
|||||||
@@ -1,12 +1,3 @@
|
|||||||
const std = @import("std");
|
|
||||||
const CoreModel = @import("../app_common/Model.zig");
|
|
||||||
const models = @import("../core/models.zig");
|
|
||||||
const provider = @import("../core/provider/provider.zig");
|
|
||||||
const local_provider = @import("../core/provider/local.zig");
|
|
||||||
const Tab = @import("../core/tab/tab.zig").Tab;
|
|
||||||
const core = @import("../app_common/root.zig");
|
|
||||||
|
|
||||||
const dvui = @import("dvui");
|
|
||||||
const RaylibBackend = dvui.backend;
|
const RaylibBackend = dvui.backend;
|
||||||
comptime {
|
comptime {
|
||||||
std.debug.assert(@hasDecl(RaylibBackend, "RaylibBackend"));
|
std.debug.assert(@hasDecl(RaylibBackend, "RaylibBackend"));
|
||||||
@@ -46,31 +37,41 @@ pub fn main() !void {
|
|||||||
defer pool.deinit();
|
defer pool.deinit();
|
||||||
|
|
||||||
var localContentProvider = local_provider.LocalContentProvider{ .threadPool = &pool };
|
var localContentProvider = local_provider.LocalContentProvider{ .threadPool = &pool };
|
||||||
|
var localContentProv = localContentProvider.provider();
|
||||||
|
|
||||||
const homeFullName: models.FullName = .{ .path = "/home/adam" };
|
var rootProvider = RootProvider.init(allocator);
|
||||||
const homeItem = try localContentProvider.getItemByFullName(homeFullName, &.{}, allocator);
|
defer rootProvider.deinit();
|
||||||
const startLocation = switch (homeItem.item) {
|
|
||||||
.container => |c1| c1,
|
try rootProvider.providers.append(&localContentProv);
|
||||||
.element => unreachable,
|
|
||||||
};
|
const home_path = try std.fs.cwd().realpathAlloc(allocator, ".");
|
||||||
|
defer allocator.free(home_path);
|
||||||
|
|
||||||
|
const start_path = try std.fmt.allocPrint(allocator, "local/{s}", .{home_path});
|
||||||
|
defer allocator.free(start_path);
|
||||||
|
|
||||||
|
const homeFullName: models.FullName = .{ .path = start_path };
|
||||||
|
|
||||||
var tab1 = try allocator.create(Tab);
|
var tab1 = try allocator.create(Tab);
|
||||||
defer allocator.destroy(tab1);
|
defer allocator.destroy(tab1);
|
||||||
|
|
||||||
tab1.init(&pool, allocator);
|
tab1.init(&pool, &rootProvider, allocator);
|
||||||
defer tab1.deinit();
|
defer tab1.deinit();
|
||||||
|
|
||||||
tab1.setCurrentLocation(startLocation);
|
try tab1.setCurrentLocation(homeFullName);
|
||||||
|
|
||||||
|
var appState: AppState = AppState.init(allocator);
|
||||||
|
appState.currentTab = tab1;
|
||||||
|
|
||||||
const model = try allocator.create(Model);
|
const model = try allocator.create(Model);
|
||||||
defer allocator.destroy(model);
|
defer allocator.destroy(model);
|
||||||
|
|
||||||
|
var core_model: CoreModel = undefined;
|
||||||
|
try CoreModel.init(&core_model, std.heap.ArenaAllocator.init(allocator), appState);
|
||||||
|
|
||||||
model.* = .{
|
model.* = .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.core_model = .{
|
.core_model = core_model,
|
||||||
.current_items_allocator = std.heap.ArenaAllocator.init(allocator),
|
|
||||||
.tab = tab1,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
defer model.core_model.deinit();
|
defer model.core_model.deinit();
|
||||||
@@ -193,3 +194,15 @@ fn dvui_frame(model: *Model) !void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const CoreModel = @import("../app_common/Model.zig");
|
||||||
|
const models = @import("../core/models.zig");
|
||||||
|
const provider = @import("../core/provider/provider.zig");
|
||||||
|
const RootProvider = @import("../core/provider/root.zig").RootProvider;
|
||||||
|
const local_provider = @import("../core/provider/local.zig");
|
||||||
|
const Tab = @import("../core/tab/tab.zig").Tab;
|
||||||
|
const core = @import("../app_common/root.zig");
|
||||||
|
const AppState = @import("../core/app_state.zig").AppState;
|
||||||
|
|
||||||
|
const dvui = @import("dvui");
|
||||||
|
|||||||
Reference in New Issue
Block a user