From 9df08455302ba4a195b479f0eed716abe0522169 Mon Sep 17 00:00:00 2001 From: utox39 Date: Thu, 31 Jul 2025 01:43:40 +0200 Subject: [PATCH 1/6] feat: add a utility function to retrieve the terminal size --- src/utils.zig | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/utils.zig diff --git a/src/utils.zig b/src/utils.zig new file mode 100644 index 0000000..0520d6c --- /dev/null +++ b/src/utils.zig @@ -0,0 +1,51 @@ +const std = @import("std"); +const builtin = @import("builtin"); + +pub const TermSize = struct { + width: u16, + height: u16, +}; + +pub fn getTerminalSize() !TermSize { + // https://github.com/softprops/zig-termsize (https://github.com/softprops/zig-termsize/blob/main/src/main.zig) + + const stdout = std.io.getStdIn(); + + switch (builtin.os.tag) { + .windows => { + var buf: std.os.windows.CONSOLE_SCREEN_BUFFER_INFO = undefined; + switch (std.os.windows.kernel32.GetConsoleScreenBufferInfo(stdout.handle, &buf)) { + std.os.windows.TRUE => return TermSize{ + .width = @intCast(buf.srWindow.Right - buf.srWindow.Left + 1), + .height = @intCast(buf.srWindow.Bottom - buf.srWindow.Top + 1), + }, + else => return error.GetConsoleScreenBufferInfoFailed, + } + }, + .linux, .macos => { + var buf: std.posix.winsize = undefined; + switch (std.posix.errno( + std.posix.system.ioctl( + stdout.handle, + std.posix.T.IOCGWINSZ, + @intFromPtr(&buf), + ), + )) { + std.posix.E.SUCCESS => return TermSize{ + .width = buf.col, + .height = buf.row, + }, + else => return error.IoctlFailed, + } + }, + else => return error.UnsupportedOperatingSystem, + } +} + +test "getTerminalSize" { + const terminal_size = try getTerminalSize(); + + std.debug.print("Height: {}, Width {}\n", .{ terminal_size.height, terminal_size.width }); + + try std.testing.expect((terminal_size.height > 0) and (terminal_size.width > 0)); +} From f6d1c2dc7251d80783baa6c721f789599148e888 Mon Sep 17 00:00:00 2001 From: utox39 Date: Thu, 31 Jul 2025 01:47:12 +0200 Subject: [PATCH 2/6] feat: add adaptive printing based on terminal width --- src/ascii.zig | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/ascii.zig b/src/ascii.zig index bed067d..527424e 100644 --- a/src/ascii.zig +++ b/src/ascii.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const utils = @import("./utils.zig"); pub const Reset = "\x1b[0m"; pub const Bold = "\x1b[1m"; @@ -93,6 +94,9 @@ pub fn printAscii(allocator: std.mem.Allocator, sys_info_list: std.ArrayList([]u const sys_info_len: usize = sys_info_items.len; const max_len: usize = if (ascii_art_len > sys_info_len) ascii_art_len else sys_info_len; + const terminal_size = try utils.getTerminalSize(); + const terminal_width: usize = @intCast(terminal_size.width); + var i: usize = 0; while (i < max_len) : (i += 1) { if (i < ascii_art_len) { @@ -103,7 +107,17 @@ pub fn printAscii(allocator: std.mem.Allocator, sys_info_list: std.ArrayList([]u try bw.flush(); if (i < sys_info_len) { - try stdout.print("{s}\n", .{sys_info_items[i]}); + // Ignore the username@host and the separator + if (i >= 2) { + var start: usize = std.mem.indexOf(u8, sys_info_items[i], Reset) orelse 0; + // `start` is the index of the last character of the ANSI reset escape sequence + 1 + start += Reset.len + 1; + + // If the visual length of the string is greater than the width of the terminal, characters exceeding that width will not be printed + try stdout.print("{s}\n", .{sys_info_items[i][0..(if (sys_info_items[i][start..].len > terminal_width) start + terminal_width else sys_info_items[i].len)]}); + } else { + try stdout.print("{s}\n", .{sys_info_items[i]}); + } } else if (i == sys_info_len + 1) { // Print the first row of colors for (0..8) |j| { From 2aa90c04ffc17deb28601be69d61184102d8c62b Mon Sep 17 00:00:00 2001 From: utox39 Date: Fri, 1 Aug 2025 03:51:11 +0200 Subject: [PATCH 3/6] feat: add a utility function to get the length of the longest sys info string --- src/utils.zig | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/utils.zig b/src/utils.zig index 0520d6c..a15816d 100644 --- a/src/utils.zig +++ b/src/utils.zig @@ -49,3 +49,29 @@ test "getTerminalSize" { try std.testing.expect((terminal_size.height > 0) and (terminal_size.width > 0)); } + +pub fn getLongestSysInfoStringLen(strings: []const []const u8) usize { + const ansi_reset = "\x1b[0m"; + var longest_len: usize = 0; + + // Ignore the username@host and the separator + for (strings[2..]) |s| { + const ansi_restet_index = std.mem.indexOf(u8, s, ansi_reset); + var start: usize = 0; + + if (ansi_restet_index != null) { + // `start` is the index of the last character of the ANSI reset escape sequence + 1 + start = ansi_restet_index.? + ansi_reset.len + 1; + } + + longest_len = @max(longest_len, s[start..].len); + } + + return longest_len; +} + +test "getLongestSysInfoStringLen" { + const strings = [_][]const u8{ "", "", "test", "test-test", "test1" }; + + try std.testing.expectEqual(strings[3].len, getLongestSysInfoStringLen(strings[0..])); +} From 1267a7125081787fc424b96076ed0bc0e5d675e7 Mon Sep 17 00:00:00 2001 From: utox39 Date: Fri, 1 Aug 2025 04:10:00 +0200 Subject: [PATCH 4/6] feat: print the ascii art if the width of the terminal is greater than the left alignment (45) + the longest sys info string length --- src/ascii.zig | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/ascii.zig b/src/ascii.zig index 527424e..4630049 100644 --- a/src/ascii.zig +++ b/src/ascii.zig @@ -90,34 +90,34 @@ pub fn printAscii(allocator: std.mem.Allocator, sys_info_list: std.ArrayList([]u const ascii_art_items = ascii_art_content_list.items; const sys_info_items = sys_info_list.items; - const ascii_art_len: usize = ascii_art_items.len; - const sys_info_len: usize = sys_info_items.len; - const max_len: usize = if (ascii_art_len > sys_info_len) ascii_art_len else sys_info_len; - const terminal_size = try utils.getTerminalSize(); const terminal_width: usize = @intCast(terminal_size.width); + const left_alignment: usize = 45; + + const longest_sys_info_string_len = utils.getLongestSysInfoStringLen(sys_info_items); + const can_print_ascii_art: bool = terminal_width > left_alignment + longest_sys_info_string_len; + + const ascii_art_len: usize = ascii_art_items.len; + const sys_info_len: usize = sys_info_items.len; + + // NOTE: sys_info_len + 3 to be able to print the colors + const max_len: usize = if ((ascii_art_len > sys_info_len) and can_print_ascii_art) ascii_art_len else sys_info_len + 3; + var i: usize = 0; while (i < max_len) : (i += 1) { - if (i < ascii_art_len) { - try stdout.print("{s:<40} \t", .{ascii_art_items[i]}); - } else { - try stdout.print("{s:<40}", .{""}); + // Print the ascii art if the width of the terminal is greater than the left alignment (45) + the longest sys info string length + if (can_print_ascii_art) { + if (i < ascii_art_len) { + try stdout.print("{s:<45}", .{ascii_art_items[i]}); + } else { + try stdout.print("{s:<45}", .{""}); + } + try bw.flush(); } - try bw.flush(); if (i < sys_info_len) { - // Ignore the username@host and the separator - if (i >= 2) { - var start: usize = std.mem.indexOf(u8, sys_info_items[i], Reset) orelse 0; - // `start` is the index of the last character of the ANSI reset escape sequence + 1 - start += Reset.len + 1; - - // If the visual length of the string is greater than the width of the terminal, characters exceeding that width will not be printed - try stdout.print("{s}\n", .{sys_info_items[i][0..(if (sys_info_items[i][start..].len > terminal_width) start + terminal_width else sys_info_items[i].len)]}); - } else { - try stdout.print("{s}\n", .{sys_info_items[i]}); - } + try stdout.print("{s}\n", .{sys_info_items[i]}); } else if (i == sys_info_len + 1) { // Print the first row of colors for (0..8) |j| { From 7669da5ae8e071765ea1f7f8b3d2e0817897d635 Mon Sep 17 00:00:00 2001 From: utox39 Date: Fri, 1 Aug 2025 05:55:11 +0200 Subject: [PATCH 5/6] refactor(formatters): remove unnecessary spaces in the formatted uptime string --- src/formatters.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/formatters.zig b/src/formatters.zig index 91d9786..5931087 100644 --- a/src/formatters.zig +++ b/src/formatters.zig @@ -78,7 +78,7 @@ pub fn getDefaultFormattedUptimeInfo(allocator: std.mem.Allocator) !Result { pub fn getFormattedUptimeInfo(allocator: std.mem.Allocator, key: []const u8, key_color: []const u8) !Result { const uptime = try detection.system.getSystemUptime(); - return Result{ .string = try std.fmt.allocPrint(allocator, "{s}{s}:{s} {} days, {} hours, {} minutes ", .{ key_color, key, ascii.Reset, uptime.days, uptime.hours, uptime.minutes }) }; + return Result{ .string = try std.fmt.allocPrint(allocator, "{s}{s}:{s} {} days, {} hours, {} minutes", .{ key_color, key, ascii.Reset, uptime.days, uptime.hours, uptime.minutes }) }; } pub fn getDefaultFormattedPackagesInfo(allocator: std.mem.Allocator) !Result { From 0beec60a8a5f42a68a7c27e1b8ea253536cb5191 Mon Sep 17 00:00:00 2001 From: utox39 Date: Fri, 1 Aug 2025 06:25:30 +0200 Subject: [PATCH 6/6] fix(linux-kernel): fix kernel info parsing by trimming null bytes --- src/linux/system.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/linux/system.zig b/src/linux/system.zig index 4609940..071a6d8 100644 --- a/src/linux/system.zig +++ b/src/linux/system.zig @@ -70,8 +70,8 @@ pub fn getKernelInfo(allocator: std.mem.Allocator) !KernelInfo { } return KernelInfo{ - .kernel_name = try allocator.dupe(u8, &uts.sysname), - .kernel_release = try allocator.dupe(u8, &uts.release), + .kernel_name = try allocator.dupe(u8, std.mem.sliceTo(&uts.sysname, 0)), + .kernel_release = try allocator.dupe(u8, std.mem.sliceTo(&uts.release, 0)), }; }