Add type_username option

This commit is contained in:
HigherOrderLogic 2026-06-07 08:36:27 +00:00
commit c6a987af4e
3 changed files with 51 additions and 12 deletions

View file

@ -292,6 +292,10 @@ login_cmd = null
# Linux)
login_defs_path = /etc/login.defs
# If true, user need to manually type username instead of selecting from the list
# of discovered users
type_username = false
# Command executed when logging out
# If null, no command will be executed
# Important: the session will already be terminated when this command is executed, so

View file

@ -73,6 +73,7 @@ input_len: u8 = 34,
lang: []const u8 = "en",
login_cmd: ?[]const u8 = null,
login_defs_path: []const u8 = "/etc/login.defs",
type_username: bool = false,
logout_cmd: ?[]const u8 = null,
ly_log: ?[]const u8 = "/var/log/ly.log",
margin_box_h: u8 = 2,

View file

@ -108,6 +108,7 @@ const UiState = struct {
session: Session,
saved_users: SavedUsers,
login: UserList,
login_text: ?*Text,
password: *Text,
password_widget: *Widget,
insert_mode: bool,
@ -781,8 +782,10 @@ pub fn main(init: std.process.Init) !void {
);
defer state.login.deinit();
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);
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);
}
if (state.config.shell) {
addOtherEnvironment(&state.session, state.lang, .shell, null) catch |err| {
@ -886,7 +889,7 @@ pub fn main(init: std.process.Init) !void {
);
}
if (usernames.items.len == 0) {
if (usernames.items.len == 0 and !state.config.type_username) {
// If we have no usernames, simply add an error to the info line.
// This effectively means you can't login, since there would be no local
// accounts *and* no root account...but at this point, if that's the
@ -925,6 +928,23 @@ pub fn main(init: std.process.Init) !void {
state.password_widget = state.password.widget();
if (state.config.type_username) {
state.login_text = try Text.init(
state.allocator,
state.io,
&state.buffer,
state.insert_mode,
false,
null,
state.box.width - 2 * state.box.horizontal_margin - state.labels_max_length - 1,
state.buffer.fg,
state.buffer.bg,
);
} else {
state.login_text = null;
}
defer if (state.login_text) |lt| lt.deinit();
state.version_label = Label.init(
ly_version_str,
null,
@ -938,6 +958,8 @@ pub fn main(init: std.process.Init) !void {
state.is_autologin = false;
check_autologin: {
if (state.config.type_username) break :check_autologin;
const auto_user = state.config.auto_login_user orelse break :check_autologin;
const auto_session = state.config.auto_login_session orelse break :check_autologin;
@ -1119,7 +1141,7 @@ pub fn main(init: std.process.Init) !void {
// Skip if autologin is active to prevent overriding autologin session
var default_input = state.config.default_input;
if (state.config.save and !state.is_autologin) {
if (state.config.save and !state.is_autologin and !state.config.type_username) {
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;
@ -1143,7 +1165,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 = 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);
@ -1387,6 +1409,7 @@ fn disableInsertMode(ptr: *anyopaque) !bool {
if (state.config.vi_mode and state.insert_mode) {
state.insert_mode = false;
state.password.should_insert = false;
if (state.login_text) |lt| lt.should_insert = false;
state.buffer.drawNextFrame(true);
}
return false;
@ -1398,6 +1421,7 @@ fn enableInsertMode(ptr: *anyopaque) !bool {
state.insert_mode = true;
state.password.should_insert = true;
if (state.login_text) |lt| lt.should_insert = true;
state.buffer.drawNextFrame(true);
return false;
}
@ -1509,7 +1533,7 @@ fn authenticate(ptr: *anyopaque) !bool {
state.info_line.label.draw();
try TerminalBuffer.presentBuffer();
if (state.config.save) save_last_settings: {
if (state.config.save and !state.config.type_username) 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.
@ -1593,7 +1617,7 @@ fn authenticate(ptr: *anyopaque) !bool {
&state.log_file,
auth_options,
current_environment,
state.login.getCurrentUsername(),
if (state.config.type_username) state.login_text.?.text.items else state.login.getCurrentUsername(),
password_text,
) catch |err| {
shared_err.writeError(err);
@ -2118,12 +2142,22 @@ fn positionWidgets(ptr: *anyopaque) !void {
.childrenPosition()
.resetXFrom(state.info_line.label.childrenPosition())
.addY(1));
state.login.label.positionY(state.login_label
.childrenPosition()
.addX(state.labels_max_length - TerminalBuffer.strWidth(state.login_label.text) + 1));
if (state.config.type_username) {
state.login_text.?.positionY(state.login_label
.childrenPosition()
.addX(state.labels_max_length - TerminalBuffer.strWidth(state.login_label.text) + 1));
} else {
state.login.label.positionY(state.login_label
.childrenPosition()
.addX(state.labels_max_length - TerminalBuffer.strWidth(state.login_label.text) + 1));
}
state.password_label.positionX(state.login.label
.childrenPosition()
const login_children_pos = if (state.config.type_username)
state.login_text.?.childrenPosition()
else
state.login.label.childrenPosition();
state.password_label.positionX(login_children_pos
.resetXFrom(state.info_line.label.childrenPosition())
.addY(1));
state.password.positionY(state.password_label