feat(palette): persist command last used times
This commit is contained in:
parent
e1a94bf8f2
commit
77b949306e
1 changed files with 56 additions and 13 deletions
|
@ -3,6 +3,7 @@ const tp = @import("thespian");
|
||||||
const log = @import("log");
|
const log = @import("log");
|
||||||
const cbor = @import("cbor");
|
const cbor = @import("cbor");
|
||||||
const fuzzig = @import("fuzzig");
|
const fuzzig = @import("fuzzig");
|
||||||
|
const root = @import("root");
|
||||||
|
|
||||||
const Plane = @import("renderer").Plane;
|
const Plane = @import("renderer").Plane;
|
||||||
const key = @import("renderer").input.key;
|
const key = @import("renderer").input.key;
|
||||||
|
@ -45,7 +46,6 @@ const Command = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn create(a: std.mem.Allocator) !tui.Mode {
|
pub fn create(a: std.mem.Allocator) !tui.Mode {
|
||||||
if (mru_list == null) mru_list = std.ArrayList(i64).init(a);
|
|
||||||
const mv = if (tui.current().mainview.dynamic_cast(mainview)) |mv_| mv_ else return error.NotFound;
|
const mv = if (tui.current().mainview.dynamic_cast(mainview)) |mv_| mv_ else return error.NotFound;
|
||||||
const self: *Self = try a.create(Self);
|
const self: *Self = try a.create(Self);
|
||||||
self.* = .{
|
self.* = .{
|
||||||
|
@ -73,9 +73,10 @@ pub fn create(a: std.mem.Allocator) !tui.Mode {
|
||||||
(self.commands.addOne() catch @panic("oom")).* = .{
|
(self.commands.addOne() catch @panic("oom")).* = .{
|
||||||
.name = p.name,
|
.name = p.name,
|
||||||
.id = p.id,
|
.id = p.id,
|
||||||
.used_time = get_used_time(p.id),
|
.used_time = 0,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
self.restore_state() catch {};
|
||||||
self.sort_by_used_time();
|
self.sort_by_used_time();
|
||||||
try self.palette_commands.init(self);
|
try self.palette_commands.init(self);
|
||||||
try self.start_query();
|
try self.start_query();
|
||||||
|
@ -162,7 +163,7 @@ fn menu_action_execute_command(menu: **Menu.State(*Self), button: *Button.State(
|
||||||
var iter = button.opts.label;
|
var iter = button.opts.label;
|
||||||
if (!(cbor.matchString(&iter, &command_name) catch false)) return;
|
if (!(cbor.matchString(&iter, &command_name) catch false)) return;
|
||||||
if (!(cbor.matchValue(&iter, cbor.extract(&command_id)) catch false)) return;
|
if (!(cbor.matchValue(&iter, cbor.extract(&command_id)) catch false)) return;
|
||||||
update_used_time(command_id);
|
menu.*.opts.ctx.update_used_time(command_id);
|
||||||
tp.self_pid().send(.{ "cmd", "exit_overlay_mode" }) catch |e| menu.*.opts.ctx.logger.err("navigate", e);
|
tp.self_pid().send(.{ "cmd", "exit_overlay_mode" }) catch |e| menu.*.opts.ctx.logger.err("navigate", e);
|
||||||
tp.self_pid().send(.{ "cmd", command_name, .{} }) catch |e| menu.*.opts.ctx.logger.err("navigate", e);
|
tp.self_pid().send(.{ "cmd", command_name, .{} }) catch |e| menu.*.opts.ctx.logger.err("navigate", e);
|
||||||
}
|
}
|
||||||
|
@ -416,18 +417,60 @@ fn sort_by_used_time(self: *Self) void {
|
||||||
std.mem.sort(Command, self.commands.items, {}, less_fn);
|
std.mem.sort(Command, self.commands.items, {}, less_fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
var mru_list: ?std.ArrayList(i64) = null;
|
fn update_used_time(self: *Self, id: command.ID) void {
|
||||||
|
self.set_used_time(id, std.time.milliTimestamp());
|
||||||
fn update_used_time(id: command.ID) void {
|
self.write_state() catch {};
|
||||||
const list = if (mru_list) |*p| p else @panic("missing mru_list");
|
|
||||||
while (list.items.len < id + 1)
|
|
||||||
(list.addOne() catch @panic("oom")).* = 0;
|
|
||||||
list.items[id] = std.time.milliTimestamp();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_used_time(id: command.ID) i64 {
|
fn set_used_time(self: *Self, id: command.ID, used_time: i64) void {
|
||||||
const list = mru_list orelse @panic("missing mru_list");
|
self.commands.items[id].used_time = used_time;
|
||||||
return if (list.items.len < id + 1) 0 else list.items[id];
|
}
|
||||||
|
|
||||||
|
fn write_state(self: *Self) !void {
|
||||||
|
var state_file_buffer: [std.fs.max_path_bytes]u8 = undefined;
|
||||||
|
const state_file = try std.fmt.bufPrint(&state_file_buffer, "{s}/{s}", .{ try root.get_state_dir(), "commands" });
|
||||||
|
var file = try std.fs.createFileAbsolute(state_file, .{ .truncate = true });
|
||||||
|
defer file.close();
|
||||||
|
var buffer = std.io.bufferedWriter(file.writer());
|
||||||
|
defer buffer.flush() catch {};
|
||||||
|
const writer = buffer.writer();
|
||||||
|
|
||||||
|
for (self.commands.items) |cmd_| {
|
||||||
|
if (cmd_.used_time == 0) continue;
|
||||||
|
try cbor.writeArrayHeader(writer, 2);
|
||||||
|
try cbor.writeValue(writer, cmd_.name);
|
||||||
|
try cbor.writeValue(writer, cmd_.used_time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn restore_state(self: *Self) !void {
|
||||||
|
var state_file_buffer: [std.fs.max_path_bytes]u8 = undefined;
|
||||||
|
const state_file = try std.fmt.bufPrint(&state_file_buffer, "{s}/{s}", .{ try root.get_state_dir(), "commands" });
|
||||||
|
const a = std.heap.c_allocator;
|
||||||
|
var file = std.fs.openFileAbsolute(state_file, .{ .mode = .read_only }) catch |e| switch (e) {
|
||||||
|
error.FileNotFound => return,
|
||||||
|
else => return e,
|
||||||
|
};
|
||||||
|
defer file.close();
|
||||||
|
const stat = try file.stat();
|
||||||
|
var buffer = try a.alloc(u8, stat.size);
|
||||||
|
defer a.free(buffer);
|
||||||
|
const size = try file.readAll(buffer);
|
||||||
|
const data = buffer[0..size];
|
||||||
|
|
||||||
|
var name: []const u8 = undefined;
|
||||||
|
var used_time: i64 = undefined;
|
||||||
|
var iter: []const u8 = data;
|
||||||
|
while (cbor.matchValue(&iter, .{
|
||||||
|
tp.extract(&name),
|
||||||
|
tp.extract(&used_time),
|
||||||
|
}) catch |e| switch (e) {
|
||||||
|
error.CborTooShort => return,
|
||||||
|
else => return e,
|
||||||
|
}) {
|
||||||
|
const id = command.getId(name) orelse continue;
|
||||||
|
self.set_used_time(id, used_time);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const cmds = struct {
|
const cmds = struct {
|
||||||
|
|
Loading…
Add table
Reference in a new issue