diff --git a/src/components/Session.zig b/src/components/Session.zig index 6cb252a..fe8c498 100644 --- a/src/components/Session.zig +++ b/src/components/Session.zig @@ -14,19 +14,19 @@ const Env = struct { environment: Environment, index: usize, }; -const EnvironmentLabel = CyclableLabel(Env, *UserList); +const EnvironmentLabel = CyclableLabel(Env, *?UserList); const Session = @This(); instance: ?Widget = null, label: *EnvironmentLabel, -user_list: *UserList, +user_list: *?UserList, pub fn init( allocator: Allocator, io: std.Io, buffer: *TerminalBuffer, - user_list: *UserList, + user_list: *?UserList, width: usize, text_in_center: bool, fg: u32, @@ -79,7 +79,7 @@ pub fn addEnvironment(self: *Session, environment: Environment) !void { const env = Env{ .environment = environment, .index = self.label.list.items.len }; try self.label.addItem(env); - addedSession(env, self.user_list); + if (self.user_list.*) |w| addedSession(env, w); } fn draw(self: *Session) void { @@ -90,16 +90,16 @@ fn handle(self: *Session, maybe_key: ?keyboard.Key) !void { try self.label.handle(maybe_key); } -fn addedSession(env: Env, user_list: *UserList) void { +fn addedSession(env: Env, user_list: UserList) void { const user = user_list.label.list.items[user_list.label.current]; if (!user.first_run) return; user.session_index.* = env.index; } -fn sessionChanged(env: Env, maybe_user_list: ?*UserList) void { +fn sessionChanged(env: Env, maybe_user_list: ?*?UserList) void { if (maybe_user_list) |user_list| { - user_list.label.list.items[user_list.label.current].session_index.* = env.index; + if (user_list.*) |w| w.label.list.items[w.label.current].session_index.* = env.index; } } diff --git a/src/main.zig b/src/main.zig index 4da9378..151e840 100644 --- a/src/main.zig +++ b/src/main.zig @@ -106,8 +106,9 @@ const UiState = struct { info_line: InfoLine, animate: bool, session: Session, + saved_username: ?[]const u8, saved_users: SavedUsers, - login: UserList, + login: ?UserList, login_text: ?*Text, password: *Text, password_widget: *Widget, @@ -300,6 +301,7 @@ pub fn main(init: std.process.Init) !void { } state.has_old_save = false; + state.saved_username = null; if (state.config.save) read_save_file: { old_save_parser = migrator.tryMigrateIniSaveFile(state.allocator, state.io, state.old_save_path, &state.saved_users, usernames.items) catch break :read_save_file; @@ -317,8 +319,19 @@ pub fn main(init: std.process.Init) !void { var file_reader = save_file.reader(state.io, &file_buffer); var reader = &file_reader.interface; - const last_username_index_str = reader.takeDelimiterInclusive('\n') catch break :read_save_file; - state.saved_users.last_username_index = std.fmt.parseInt(usize, last_username_index_str[0..(last_username_index_str.len - 1)], 10) catch break :read_save_file; + const username_line = reader.takeDelimiterInclusive('\n') catch break :read_save_file; + + if (std.mem.containsAtLeastScalar2(u8, username_line, '-', 1)) read_username: { + var iterator = std.mem.splitScalar(u8, username_line[0..(username_line.len - 1)], '-'); + if (iterator.next() == null) break :read_username; // Would be index + + const maybe_username = iterator.next(); + if (maybe_username) |username| { + state.saved_username = try state.allocator.dupe(u8, username); + } + } else if (!state.config.type_username) { + state.saved_users.last_username_index = std.fmt.parseInt(usize, username_line[0..(username_line.len - 1)], 10) catch break :read_save_file; + } while (reader.seek < reader.buffer.len) { const line = reader.takeDelimiterInclusive('\n') catch break; @@ -768,24 +781,25 @@ pub fn main(init: std.process.Init) !void { ); defer state.login_label.deinit(); - state.login = try UserList.init( - state.allocator, - state.io, - &state.buffer, - usernames, - &state.saved_users, - &state.session, - state.box.width - 2 * state.box.horizontal_margin - state.labels_max_length - 1, - state.config.text_in_center, - state.buffer.fg, - state.buffer.bg, - ); - defer state.login.deinit(); - + state.login = null; if (!state.config.type_username) { - try state.buffer.registerKeybind(state.io, &state.login.label.keybinds, "H", &viGoLeft, &state); - try state.buffer.registerKeybind(state.io, &state.login.label.keybinds, "L", &viGoRight, &state); + state.login = try UserList.init( + state.allocator, + state.io, + &state.buffer, + usernames, + &state.saved_users, + &state.session, + state.box.width - 2 * state.box.horizontal_margin - state.labels_max_length - 1, + state.config.text_in_center, + state.buffer.fg, + state.buffer.bg, + ); + + try state.buffer.registerKeybind(state.io, &state.login.?.label.keybinds, "H", &viGoLeft, &state); + try state.buffer.registerKeybind(state.io, &state.login.?.label.keybinds, "L", &viGoRight, &state); } + defer if (state.login) |*w| w.deinit(); if (state.config.shell) { addOtherEnvironment(&state.session, state.lang, .shell, null) catch |err| { @@ -927,6 +941,7 @@ pub fn main(init: std.process.Init) !void { try state.buffer.registerKeybind(state.io, &state.password.keybinds, "L", &viGoRight, &state); state.password_widget = state.password.widget(); + state.login_text = null; if (state.config.type_username) { state.login_text = try Text.init( @@ -940,8 +955,6 @@ pub fn main(init: std.process.Init) !void { state.buffer.fg, state.buffer.bg, ); - } else { - state.login_text = null; } defer if (state.login_text) |lt| lt.deinit(); @@ -998,13 +1011,18 @@ pub fn main(init: std.process.Init) !void { ); state.session.label.current = session_index; - for (state.login.label.list.items, 0..) |username, i| { - if (std.mem.eql(u8, username.name, auto_user)) { - state.login.label.current = i; - break; + state.is_autologin = true; + + if (state.login_text) |box| { + try box.writeText(auto_user); + } else { + for (state.login.?.label.list.items, 0..) |username, i| { + if (std.mem.eql(u8, username.name, auto_user)) { + state.login.?.label.current = i; + break; + } } } - state.is_autologin = true; } // Switch to selected TTY @@ -1140,22 +1158,33 @@ pub fn main(init: std.process.Init) !void { var default_input = state.config.default_input; if (state.config.save and !state.is_autologin) { - if (state.saved_users.last_username_index) |index| load_last_user: { + if (state.login_text) |box| { + if (state.saved_username) |username| { + defer state.allocator.free(username); + + try box.writeText(username); + + default_input = .password; + + for (state.saved_users.user_list.items) |user| { + if (std.mem.eql(u8, username, user.username)) { + state.session.label.current = @min(user.session_index, state.session.label.list.items.len - 1); + break; + } + } + } + } else if (state.saved_users.last_username_index) |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; const user = state.saved_users.user_list.items[index]; - if (state.login_text) |box| { - try box.writeText(user.username); - } else { - // Find user with saved name, and switch over to it - // If it doesn't exist (anymore), we don't change the value - for (usernames.items, 0..) |username, i| { - if (std.mem.eql(u8, username, user.username)) { - state.login.label.current = i; - break; - } + // Find user with saved name, and switch over to it + // If it doesn't exist (anymore), we don't change the value + for (usernames.items, 0..) |username, i| { + if (std.mem.eql(u8, username, user.username)) { + state.login.?.label.current = i; + break; } } @@ -1167,7 +1196,7 @@ pub fn main(init: std.process.Init) !void { const info_line_widget = state.info_line.widget(); const session_widget = state.session.widget(); - const login_widget = if (state.config.type_username) state.login_text.?.widget() else state.login.widget(); + const login_widget = if (state.config.type_username) state.login_text.?.widget() else state.login.?.widget(); var widgets: std.ArrayList([]*Widget) = .empty; defer widgets.deinit(state.allocator); @@ -1535,7 +1564,7 @@ fn authenticate(ptr: *anyopaque) !bool { state.info_line.label.draw(); try TerminalBuffer.presentBuffer(); - if (state.config.save and !state.config.type_username) save_last_settings: { + if (state.config.save) save_last_settings: { // It isn't worth cluttering the code with precise error // handling, so let's just report a generic error message, // that should be good enough for debugging anyway. @@ -1561,7 +1590,11 @@ fn authenticate(ptr: *anyopaque) !bool { var file_writer = file.writer(state.io, &file_buffer); var writer = &file_writer.interface; - try writer.print("{d}\n", .{state.login.label.current}); + if (state.login_text) |box| { + try writer.print("0-{s}\n", .{box.text.items}); + } else { + try writer.print("{d}\n", .{state.login.?.label.current}); + } for (state.saved_users.user_list.items) |user| { try writer.print("{s}:{d}\n", .{ user.username, user.session_index }); } @@ -1619,7 +1652,7 @@ fn authenticate(ptr: *anyopaque) !bool { &state.log_file, auth_options, current_environment, - if (state.login_text) |box| box.text.items else state.login.getCurrentUsername(), + if (state.login_text) |box| box.text.items else state.login.?.getCurrentUsername(), password_text, ) catch |err| { shared_err.writeError(err); @@ -2149,7 +2182,7 @@ fn positionWidgets(ptr: *anyopaque) !void { .childrenPosition() .addX(state.labels_max_length - TerminalBuffer.strWidth(state.login_label.text) + 1)); } else { - state.login.label.positionY(state.login_label + state.login.?.label.positionY(state.login_label .childrenPosition() .addX(state.labels_max_length - TerminalBuffer.strWidth(state.login_label.text) + 1)); } @@ -2157,7 +2190,7 @@ fn positionWidgets(ptr: *anyopaque) !void { const login_children_pos = if (state.login_text) |box| box.childrenPosition() else - state.login.label.childrenPosition(); + state.login.?.label.childrenPosition(); state.password_label.positionX(login_children_pos .resetXFrom(state.info_line.label.childrenPosition())