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,
|
||||
usage_number: locked(u16) = .{ .data = 0 },
|
||||
current_items: locked(?[]*models.Item) = .{ .data = null },
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
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);
|
||||
|
||||
vm.tab.currentItems.mutex.lock();
|
||||
defer vm.tab.currentItems.mutex.unlock();
|
||||
tab.currentItems.mutex.lock();
|
||||
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);
|
||||
const allocator = vm.current_items_allocator.allocator();
|
||||
|
||||
const items = try allocator.alloc(*models.Item, current_items.items.len);
|
||||
for (current_items.items, 0..) |item, i| {
|
||||
const items = try allocator.alloc(*models.Item, tab_current_items.items.len);
|
||||
for (tab_current_items.items, 0..) |item, i| {
|
||||
items[i] = item;
|
||||
}
|
||||
|
||||
@@ -37,8 +43,7 @@ fn inner_loop(vm: *Model) !void {
|
||||
vm.current_items.mutex.lock();
|
||||
defer vm.current_items.mutex.unlock();
|
||||
vm.current_items.data = items;
|
||||
|
||||
vm.tab.currentItemsChanged = false;
|
||||
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
|
||||
const Model = struct {
|
||||
crash: bool = false,
|
||||
allocator: std.mem.Allocator,
|
||||
current_items_view: *vxfw.ListView,
|
||||
core_model: CoreModel,
|
||||
root_provider: *RootProvider,
|
||||
|
||||
/// Helper function to return a vxfw.Widget struct
|
||||
pub fn widget(self: *Model) vxfw.Widget {
|
||||
@@ -36,11 +25,17 @@ const Model = struct {
|
||||
ctx.quit = true;
|
||||
return;
|
||||
}
|
||||
if (key.matches('r', .{ .ctrl = true })) {
|
||||
vm.crash = true;
|
||||
if (key.matches('r', .{})) {
|
||||
// vm.crash = true;
|
||||
ctx.redraw = true;
|
||||
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()),
|
||||
else => {},
|
||||
@@ -93,7 +88,7 @@ const Model = struct {
|
||||
};
|
||||
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);
|
||||
current_location_text_element.* = vxfw.Text{
|
||||
.text = current_location_text,
|
||||
@@ -218,24 +213,26 @@ pub fn main() !void {
|
||||
defer pool.deinit();
|
||||
|
||||
var localContentProvider = local_provider.LocalContentProvider{ .threadPool = &pool };
|
||||
var localContentProv = localContentProvider.provider();
|
||||
|
||||
const homeFullName: models.FullName = .{ .path = "/home/adam" };
|
||||
const homeItem = try localContentProvider.getItemByFullName(homeFullName, &.{}, allocator);
|
||||
const c = switch (homeItem.item) {
|
||||
.container => |c| c,
|
||||
.element => unreachable,
|
||||
};
|
||||
var rootProvider = RootProvider.init(allocator);
|
||||
defer rootProvider.deinit();
|
||||
|
||||
try rootProvider.providers.append(&localContentProv);
|
||||
|
||||
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);
|
||||
defer allocator.destroy(tab1);
|
||||
|
||||
tab1.init(&pool, allocator);
|
||||
tab1.init(&pool, &rootProvider, allocator);
|
||||
defer tab1.deinit();
|
||||
|
||||
tab1.setCurrentLocation(c);
|
||||
|
||||
const model = try allocator.create(Model);
|
||||
defer allocator.destroy(model);
|
||||
try tab1.setCurrentLocation(start_full_name);
|
||||
|
||||
// TODO: remove
|
||||
std.Thread.sleep(1 * std.time.ns_per_s);
|
||||
@@ -260,13 +257,21 @@ pub fn main() !void {
|
||||
.draw_cursor = false,
|
||||
.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.* = .{
|
||||
.allocator = allocator,
|
||||
.core_model = .{
|
||||
.current_items_allocator = std.heap.ArenaAllocator.init(allocator),
|
||||
.tab = tab1,
|
||||
},
|
||||
.core_model = core_model,
|
||||
.current_items_view = &list,
|
||||
.root_provider = &rootProvider,
|
||||
};
|
||||
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.children.deinit();
|
||||
self.item.allocator.destroy(self);
|
||||
}
|
||||
};
|
||||
|
||||
pub const FullName = struct {
|
||||
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 });
|
||||
|
||||
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 {
|
||||
@@ -73,7 +81,7 @@ pub const NativePath = struct {
|
||||
};
|
||||
|
||||
pub const AbsolutePath = struct {
|
||||
path: []const u8,
|
||||
path: FullName,
|
||||
type: AbsolutePathType,
|
||||
};
|
||||
|
||||
@@ -81,7 +89,7 @@ pub const Error = struct {
|
||||
content: []const u8,
|
||||
};
|
||||
|
||||
pub const AbsolutePathType = enum {
|
||||
Container,
|
||||
Item,
|
||||
pub const AbsolutePathType = union(enum) {
|
||||
container,
|
||||
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");
|
||||
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;
|
||||
pub const LocalProviderId = "local";
|
||||
|
||||
// TODO: the container might be freed while this runs
|
||||
// Tab should hold something at pass it here
|
||||
@@ -18,6 +7,7 @@ fn loadChildren(container: *Container) void {
|
||||
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 {
|
||||
// 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;
|
||||
@@ -35,6 +25,8 @@ fn loadChildren(container: *Container) void {
|
||||
|
||||
const VTable: ProviderVTable = .{
|
||||
.getItemByFullName = getItemByFullNameGeneric,
|
||||
.canHandle = canHandleGeneric,
|
||||
.deinit = deinitGeneric,
|
||||
};
|
||||
|
||||
pub fn getItemByFullNameGeneric(
|
||||
@@ -47,6 +39,43 @@ pub fn getItemByFullNameGeneric(
|
||||
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 {
|
||||
threadPool: *std.Thread.Pool,
|
||||
|
||||
@@ -56,7 +85,7 @@ pub const LocalContentProvider = struct {
|
||||
initContext: *const InitContext,
|
||||
allocator: std.mem.Allocator,
|
||||
) 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);
|
||||
|
||||
const kind: union(enum) { directory, file } = blk: {
|
||||
@@ -139,7 +168,10 @@ pub const LocalContentProvider = struct {
|
||||
const name = try allocator.dupe(u8, basename);
|
||||
const displayName = try allocator.dupe(u8, basename);
|
||||
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{
|
||||
.allocator = allocator,
|
||||
@@ -148,12 +180,19 @@ pub const LocalContentProvider = struct {
|
||||
.displayName = displayName,
|
||||
.fullName = .{ .path = fullName2 },
|
||||
.nativePath = models.NativePath{ .path = nativePath },
|
||||
.parent = null,
|
||||
.parent = parent,
|
||||
.item = innerItem,
|
||||
.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 {
|
||||
return Provider{
|
||||
.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,
|
||||
allocator: std.mem.Allocator,
|
||||
) GetItemsError!*Item,
|
||||
|
||||
canHandle: *const fn (
|
||||
self: *anyopaque,
|
||||
fullName: FullName,
|
||||
) bool,
|
||||
|
||||
deinit: *const fn (self: *anyopaque) void,
|
||||
};
|
||||
|
||||
pub const GetItemsError = error{
|
||||
@@ -25,6 +32,17 @@ pub const Provider = struct {
|
||||
) GetItemsError!*Item {
|
||||
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 {
|
||||
|
||||
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 {
|
||||
allocator: std.mem.Allocator,
|
||||
currentLocation: ?*Container,
|
||||
currentItems: locked(?std.ArrayList(*Item)),
|
||||
currentLocationChanged: Observable(?*Container),
|
||||
currentItemsChanged: bool = false,
|
||||
preCurrentItemsUnload: Observable(*Tab),
|
||||
threadPool: *std.Thread.Pool,
|
||||
rootProvider: *RootProvider,
|
||||
_private: Private,
|
||||
|
||||
const Private = struct {
|
||||
@@ -23,44 +16,67 @@ pub const Tab = struct {
|
||||
pub fn init(
|
||||
self: *Tab,
|
||||
threadPool: *std.Thread.Pool,
|
||||
rootProvider: *RootProvider,
|
||||
allocator: std.mem.Allocator,
|
||||
) void {
|
||||
self.* = Tab{
|
||||
.allocator = allocator,
|
||||
.currentItems = .{ .data = null },
|
||||
.currentLocationChanged = Observable(?*Container).init(allocator),
|
||||
.currentLocation = null,
|
||||
.threadPool = threadPool,
|
||||
.rootProvider = rootProvider,
|
||||
.preCurrentItemsUnload = Observable(*Tab).init(allocator),
|
||||
._private = .{
|
||||
.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| {
|
||||
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
|
||||
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 {
|
||||
loadItems(self, location) catch return;
|
||||
}
|
||||
fn loadItems(self: *Tab, location: *Container) !void {
|
||||
_ = self._private.currentItemsAllocator.reset(.retain_capacity);
|
||||
|
||||
{
|
||||
self.currentItems.mutex.lock();
|
||||
defer self.currentItems.mutex.unlock();
|
||||
|
||||
self.preCurrentItemsUnload.notify(self);
|
||||
|
||||
if (self.currentItems.data) |items| {
|
||||
items.deinit();
|
||||
}
|
||||
|
||||
self.currentItems.data = null;
|
||||
}
|
||||
|
||||
_ = self._private.currentItemsAllocator.reset(.retain_capacity);
|
||||
|
||||
const arenaAllocator = &self._private.currentItemsAllocator;
|
||||
const arena = arenaAllocator.allocator();
|
||||
|
||||
@@ -98,6 +114,11 @@ pub const Tab = struct {
|
||||
defer self.currentItems.mutex.unlock();
|
||||
|
||||
try self.currentItems.data.?.append(resolvedItem);
|
||||
}
|
||||
|
||||
{
|
||||
self.currentItems.mutex.lock();
|
||||
defer self.currentItems.mutex.unlock();
|
||||
self.currentItemsChanged = true;
|
||||
}
|
||||
}
|
||||
@@ -109,3 +130,15 @@ pub const Tab = struct {
|
||||
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;
|
||||
comptime {
|
||||
std.debug.assert(@hasDecl(RaylibBackend, "RaylibBackend"));
|
||||
@@ -46,31 +37,41 @@ pub fn main() !void {
|
||||
defer pool.deinit();
|
||||
|
||||
var localContentProvider = local_provider.LocalContentProvider{ .threadPool = &pool };
|
||||
var localContentProv = localContentProvider.provider();
|
||||
|
||||
const homeFullName: models.FullName = .{ .path = "/home/adam" };
|
||||
const homeItem = try localContentProvider.getItemByFullName(homeFullName, &.{}, allocator);
|
||||
const startLocation = switch (homeItem.item) {
|
||||
.container => |c1| c1,
|
||||
.element => unreachable,
|
||||
};
|
||||
var rootProvider = RootProvider.init(allocator);
|
||||
defer rootProvider.deinit();
|
||||
|
||||
try rootProvider.providers.append(&localContentProv);
|
||||
|
||||
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);
|
||||
defer allocator.destroy(tab1);
|
||||
|
||||
tab1.init(&pool, allocator);
|
||||
tab1.init(&pool, &rootProvider, allocator);
|
||||
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);
|
||||
defer allocator.destroy(model);
|
||||
|
||||
var core_model: CoreModel = undefined;
|
||||
try CoreModel.init(&core_model, std.heap.ArenaAllocator.init(allocator), appState);
|
||||
|
||||
model.* = .{
|
||||
.allocator = allocator,
|
||||
.core_model = .{
|
||||
.current_items_allocator = std.heap.ArenaAllocator.init(allocator),
|
||||
.tab = tab1,
|
||||
},
|
||||
.core_model = core_model,
|
||||
};
|
||||
|
||||
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