feat: requested selected item+

This commit is contained in:
2025-05-27 16:12:46 +02:00
parent f4acf951d4
commit ae8ead1e5d
5 changed files with 115 additions and 53 deletions

View File

@@ -3,8 +3,10 @@ pub const Tab = struct {
currentLocation: ?*Container,
currentItems: locked(?std.ArrayList(Arc(*Item))),
currentLocationChanged: Observable(?*Container),
currentItem: ?models.FullName,
currentRequestedItem: ?models.FullName,
currentItemFullName: ?models.FullName,
currentItem: ?Arc(*models.Item),
currentRequested: ?union(enum) { item: Arc(*models.Item), name: models.FullName },
itemComparer: *const fn (item1: *const models.Item, item2: *const models.Item) std.math.Order,
threadPool: *std.Thread.Pool,
rootProvider: *RootProvider,
@@ -19,8 +21,10 @@ pub const Tab = struct {
.currentItems = .{ .data = null },
.currentLocationChanged = Observable(?*Container).init(allocator),
.currentLocation = null,
.currentRequestedItem = null,
.currentRequested = null,
.currentItem = null,
.currentItemFullName = null,
.itemComparer = order.orderByDisplayName,
.threadPool = threadPool,
.rootProvider = rootProvider,
};
@@ -31,10 +35,7 @@ pub const Tab = struct {
c.item.deinit();
}
if (self.currentItem) |i| {
self.allocator.free(i.path);
self.currentItem = null;
}
self.cleanCurrentItem();
const newLocationContainer = blk: {
const newLocation = try self.rootProvider.getItemByFullName(newLocationFullName, &.{}, self.allocator);
@@ -55,6 +56,7 @@ pub const Tab = struct {
self.currentLocationChanged.notify(newLocationContainer);
self.updateCurrentItem() catch {
self.currentItemFullName = null;
self.currentItem = null;
};
@@ -66,47 +68,80 @@ pub const Tab = struct {
self.currentItems.mutex.lock();
defer self.currentItems.mutex.unlock();
self.currentRequestedItem = models.FullName{
.path = try self.allocator.dupe(u8, requested_selected.path),
self.cleanCurrentRequested();
self.currentRequested = .{
.name = models.FullName{
.path = try self.allocator.dupe(u8, requested_selected.path),
},
};
return self.updateCurrentItem();
}
fn updateCurrentItem(self: *Tab) !void {
const currentRequestedItem = self.currentRequestedItem orelse return;
fn cleanCurrentRequested(self: *Tab) void {
const requested = self.currentRequested orelse return;
switch (requested) {
.item => |item| {
if (item.releaseUnwrap()) |i| i.deinit();
},
.name => |fullName| self.allocator.free(fullName.path),
}
self.currentRequested = null;
}
fn updateCurrentItem(self: *Tab) !void {
const currentRequested = self.currentRequested orelse return;
const requestedFullName = switch (currentRequested) {
.item => |*item| item.value.*.fullName,
.name => |fullName| fullName,
};
// The requested is already selected
if (self.currentItem) |currentItem| {
if (std.mem.order(u8, currentRequestedItem.path, currentItem.path) == .eq) return;
if (self.currentItemFullName) |currentItem| {
if (std.mem.order(u8, requestedFullName.path, currentItem.path) == .eq) {
return;
}
}
const currentItems = self.currentItems.data orelse return error.Error;
if (currentItems.items.len == 0) return error.Error;
// Looking for the requested
const foundIndex = for (0..currentItems.items.len) |i| {
const foundIndex = index: for (0..currentItems.items.len) |i| {
const arc_item = currentItems.items[i];
const arc_copy = arc_item.retain();
defer if (arc_copy.releaseUnwrap()) |item| item.deinit();
const comp = std.mem.order(u8, arc_copy.value.*.fullName.path, currentRequestedItem.path);
if (comp == .eq) {
break i;
}
if (comp == .lt) {
break i -| 1;
switch (currentRequested) {
.item => |*itemArc| {
const comp = self.itemComparer(itemArc.value.*, arc_copy.value.*);
if (comp == .eq) {
break :index i;
}
if (comp == .lt) {
break :index i -| 1;
}
},
.name => |fullName| {
if (std.mem.order(u8, fullName.path, arc_copy.value.*.fullName.path) == .eq) {
break :index i;
}
},
}
} else null;
if (foundIndex) |i| {
const arc_item = currentItems.items[i];
const arc_copy = arc_item.retain();
defer if (arc_copy.releaseUnwrap()) |item| item.deinit();
self.setSelectedItemInner(models.FullName{
.path = try self.allocator.dupe(u8, arc_copy.value.*.fullName.path),
});
self.cleanCurrentRequested();
self.currentRequested = .{
.item = arc_item.retain(),
};
try self.setSelectedItemInner(arc_item.retain());
return;
}
@@ -116,21 +151,21 @@ pub const Tab = struct {
// Fallback to first item
{
const arc_item = currentItems.items[0];
const arc_copy = arc_item.retain();
defer if (arc_copy.releaseUnwrap()) |item| item.deinit();
self.setSelectedItemInner(models.FullName{
.path = try self.allocator.dupe(u8, arc_copy.value.*.fullName.path),
});
try self.setSelectedItemInner(arc_item.retain());
}
}
fn setSelectedItemInner(self: *Tab, newSelectedItem: models.FullName) void {
if (self.currentItem) |current| {
self.allocator.free(current.path);
}
fn setSelectedItemInner(self: *Tab, newSelectedItemArc: Arc(*models.Item)) !void {
const arc = newSelectedItemArc.retain();
defer if (arc.releaseUnwrap()) |item| item.deinit();
self.currentItem = newSelectedItem;
self.cleanCurrentItem();
self.currentItem = newSelectedItemArc;
self.currentItemFullName = models.FullName{
.path = try self.allocator.dupe(u8, arc.value.*.fullName.path),
};
}
fn loadItemsWrapper(self: *Tab, location: *Container) void {
@@ -177,8 +212,8 @@ pub const Tab = struct {
self.currentItems.mutex.lock();
defer self.currentItems.mutex.unlock();
const insertIndex = for (self.currentItems.data.?.items, 0..) |item, i| {
if (compareByDisplayName(resolvedItem, item.value.*)) break i;
const insertIndex = for (self.currentItems.data.?.items, 0..) |*item, i| {
if (order.orderByDisplayName(resolvedItem, item.value.*) == .lt) break i;
} else null;
const arc = try Arc(*Item).init(self.allocator, resolvedItem);
@@ -208,17 +243,23 @@ pub const Tab = struct {
currentItems.deinit();
}
if (self.currentItem) |currentItem| {
self.allocator.free(currentItem.path);
}
self.cleanCurrentItem();
self.cleanCurrentRequested();
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;
fn cleanCurrentItem(self: *Tab) void {
if (self.currentItemFullName) |currentItem| {
self.allocator.free(currentItem.path);
self.currentItemFullName = null;
}
if (self.currentItem) |currentItem| {
if (currentItem.releaseUnwrap()) |item| item.deinit();
self.currentItem = null;
}
}
};
@@ -226,6 +267,8 @@ const std = @import("std");
const assert = std.debug.assert;
const Mutex = std.Thread.Mutex;
const order = @import("./order.zig");
const models = @import("../models.zig");
const Container = models.Container;
const Item = models.Item;