feat: per tty last user caching

re #1040

also fix using the saved_users list in places it
shouldn't be

now this is only used on load and properly saved
using the latest valid state, overwriting aged
values.
This commit is contained in:
urly3 2026-08-20 00:53:37 +01:00
commit d4e18caab2

View file

@ -126,6 +126,7 @@ const UiState = struct {
bigclock_buf: [32:0]u8,
custom_binds: std.ArrayList(CustomBindLabel),
custom_info: std.ArrayList(CustomInfoLabel),
tty_cache: [256]?u8,
};
var shutdown = false;
@ -186,6 +187,8 @@ pub fn main(init: std.process.Init) !void {
state.saved_users = SavedUsers.init();
defer state.saved_users.deinit(state.allocator);
state.tty_cache = @splat(null);
var config_parent_path: []const u8 = build_options.config_directory ++ "/ly";
if (maybe_res) |*res| {
if (res.args.help != 0) {
@ -319,33 +322,37 @@ pub fn main(init: std.process.Init) !void {
}
while (reader.seek < reader.buffer.len) {
const line = reader.takeDelimiterInclusive('\n') catch break;
var line = reader.takeDelimiterInclusive('\n') catch break;
var user = std.mem.splitScalar(u8, line[0..(line.len - 1)], ':');
const username = user.next() orelse continue;
const session_index_str = user.next() orelse continue;
if (std.mem.startsWith(u8, line, "ly/tty")) {
line = line[6..];
var entry = std.mem.splitScalar(u8, line[0..(line.len - 1)], ':');
const tty_num_str = entry.next() orelse continue;
const username = entry.next() orelse continue;
const session_index = std.fmt.parseInt(usize, session_index_str, 10) catch continue;
const tty_num = std.fmt.parseInt(usize, tty_num_str, 10) catch continue;
try state.saved_users.user_list.append(state.allocator, .{
.username = try state.allocator.dupe(u8, username),
.session_index = session_index,
.first_run = false,
.allocated_username = true,
});
}
}
// Cache tty users only if they exist
for (usernames.items, 0..) |u, u_index| {
if (std.mem.eql(u8, u, username)) {
if (tty_num < std.math.maxInt(@TypeOf(state.active_tty)))
state.tty_cache[tty_num] = @intCast(u_index);
}
}
} else {
var user = std.mem.splitScalar(u8, line[0..(line.len - 1)], ':');
const username = user.next() orelse continue;
const session_index_str = user.next() orelse continue;
// If no save file previously existed, fill it up with all usernames
// TODO: Add new username with existing save file
if (state.config.save_file_dir != null and state.saved_users.user_list.items.len == 0) {
for (usernames.items) |user| {
try state.saved_users.user_list.append(state.allocator, .{
.username = user,
.session_index = 0,
.first_run = true,
.allocated_username = false,
});
const session_index = std.fmt.parseInt(usize, session_index_str, 10) catch continue;
try state.saved_users.user_list.append(state.allocator, .{
.username = try state.allocator.dupe(u8, username),
.session_index = session_index,
.first_run = false,
.allocated_username = true,
});
}
}
}
@ -1137,11 +1144,14 @@ pub fn main(init: std.process.Init) !void {
}
}
}
} else if (state.saved_users.last_username_index) |index| load_last_user: {
} else if (state.tty_cache[state.active_tty]) |tty_index| {
state.login.?.label.current = tty_index;
state.session.label.current = @min(state.login.?.label.list.items[tty_index].session_index.*, state.session.label.list.items.len - 1);
} else if (state.saved_users.last_username_index) |last_index| load_last_user: {
// If the saved index isn't valid, bail out
if (index >= state.saved_users.user_list.items.len) break :load_last_user;
if (last_index >= state.saved_users.user_list.items.len) break :load_last_user;
const user = state.saved_users.user_list.items[index];
const user = state.saved_users.user_list.items[last_index];
// Find user with saved name, and switch over to it
// If it doesn't exist (anymore), we don't change the value
@ -1516,6 +1526,8 @@ fn authenticate(ptr: *anyopaque) !bool {
.{},
) catch {};
const current: u8 = @intCast(state.login.?.label.current);
var file = std.Io.Dir.cwd().createFile(state.io, state.save_path, .{}) catch |err| {
state.log_file.err(
state.io,
@ -1531,13 +1543,56 @@ fn authenticate(ptr: *anyopaque) !bool {
var file_writer = file.writer(state.io, &file_buffer);
var writer = &file_writer.interface;
// Update the local tty cache before overwriting
// since multiple instances can be running
//
// A little code dupe but the end comparison
// is on a different type
update_tty_cache: {
var save_file = std.Io.Dir.cwd().openFile(state.io, state.save_path, .{}) catch break :update_tty_cache;
defer save_file.close(state.io);
var file_reader = save_file.reader(state.io, &file_buffer);
var reader = &file_reader.interface;
while (reader.seek < reader.buffer.len) {
var line = reader.takeDelimiterInclusive('\n') catch break;
if (std.mem.startsWith(u8, line, "ly/tty")) {
line = line[6..];
var entry = std.mem.splitScalar(u8, line[0..(line.len - 1)], ':');
const tty_num_str = entry.next() orelse continue;
const username = entry.next() orelse continue;
const tty_num = std.fmt.parseInt(usize, tty_num_str, 10) catch continue;
// Cache tty users only if they exist
for (state.login.?.label.list.items, 0..) |u, u_index| {
if (std.mem.eql(u8, u.name, username)) {
if (tty_num < std.math.maxInt(@TypeOf(state.active_tty)))
state.tty_cache[tty_num] = @intCast(u_index);
}
}
}
}
}
if (state.login_text) |box| {
try writer.print("0-{s}\n", .{box.text.items});
} else {
try writer.print("{d}\n", .{state.login.?.label.current});
try writer.print("{d}\n", .{current});
}
for (state.saved_users.user_list.items) |user| {
try writer.print("{s}:{d}\n", .{ user.username, user.session_index });
for (state.login.?.label.list.items) |user| {
try writer.print("{s}:{d}\n", .{ user.name, user.session_index.* });
}
state.tty_cache[state.active_tty] = current;
for (state.tty_cache, 0..) |maybe_user_index, tty_num| {
if (maybe_user_index) |user_index| {
// Posix usernames can't contain a '/'
// And, well, if your username is this string...
try writer.print("ly/tty{d}:{s}\n", .{ tty_num, state.login.?.label.list.items[user_index].name });
}
}
try writer.flush();