diff --git a/src/assets/freebsd.png b/src/assets/orby.png similarity index 100% rename from src/assets/freebsd.png rename to src/assets/orby.png diff --git a/src/assets/tux.png b/src/assets/tux.png new file mode 100644 index 0000000..988f2e2 Binary files /dev/null and b/src/assets/tux.png differ diff --git a/src/assets/ziggy.png b/src/assets/ziggy.png new file mode 100644 index 0000000..a9d0d46 Binary files /dev/null and b/src/assets/ziggy.png differ diff --git a/src/linux.zig b/src/linux.zig new file mode 100644 index 0000000..920c270 --- /dev/null +++ b/src/linux.zig @@ -0,0 +1,25 @@ +const std = @import("std"); + +pub fn kernel_version() ![]const u8 { + var uname_buf: std.posix.utsname = undefined; + + try std.posix.uname(&uname_buf); + + return uname_buf.version; +} + +pub fn distribution() ![]const u8 { + const os_release_path = "/etc/os-release"; + var file = try std.fs.openDirAbsolute(os_release_path, .{}); + defer file.close(); + + var buffered = std.io.bufferedReader(file.reader()); + + while (try buffered.reader().readUntilDelimiterOrEofAlloc(std.heap.page_allocator, '\n')) |line| { + if (std.mem.startsWith(u8, line, "PRETTY_NAME=")) { + return line[13 .. line.len - 1]; + } + } + + return "Uknown distro"; +} diff --git a/src/macos.zig b/src/macos.zig index 8af4483..dd5253f 100644 --- a/src/macos.zig +++ b/src/macos.zig @@ -34,7 +34,7 @@ pub fn macosVersionAtLeast(major: i64, minor: i64, patch: i64) bool { }); } -pub fn macos_version(allocator: std.mem.Allocator) ![]const u8 { +pub fn macos_version(buf: []u8) ![]const u8 { const NSProcessInfo = objc.getClass("NSProcessInfo").?; // Call a class method with no arguments that returns another objc object. @@ -42,12 +42,10 @@ pub fn macos_version(allocator: std.mem.Allocator) ![]const u8 { const koko = info.msgSend(NSOperatingSystemVersion, "operatingSystemVersion", .{}); - const buf = try std.fmt.allocPrint(allocator, ": macOS {s} {d}.{d}.{d}\n", .{ version_to_name(koko), koko.major, koko.minor, koko.patch }); - - return buf; + return try std.fmt.bufPrint(buf, ": macOS {s} {d}.{d}.{d}\n", .{ version_to_name(koko), koko.major, koko.minor, koko.patch }); } -pub fn macos_kernel_version(allocator: std.mem.Allocator) ![]const u8 { +pub fn get_kernel_version(buf: []u8) ![]const u8 { var name: c.struct_utsname = undefined; if (c.uname(&name) != 0) { @@ -57,12 +55,10 @@ pub fn macos_kernel_version(allocator: std.mem.Allocator) ![]const u8 { const sysname = std.mem.sliceTo(name.sysname[0..], 0); const version = std.mem.sliceTo(name.release[0..], 0); - const buf = try std.fmt.allocPrint(allocator, ": {s} {s}\n", .{ sysname, version }); - - return buf; + return try std.fmt.bufPrint(buf, ": {s} {s}\n", .{ sysname, version }); } -pub fn memory_info(allocator: std.mem.Allocator) ![]const u8 { +pub fn get_mem_info(buf: []u8) ![]const u8 { var memsize: u64 = 0; var memsize_size: usize = @sizeOf(u64); @@ -73,7 +69,7 @@ pub fn memory_info(allocator: std.mem.Allocator) ![]const u8 { const bingb: u64 = (1024 * 1024 * 1024); const memsize_gb: u64 = @divFloor(memsize, bingb); - return try std.fmt.allocPrint(allocator, ": {d} GiB\n", .{memsize_gb}); + return try std.fmt.bufPrint(buf, ": {d} GiB\n", .{memsize_gb}); } // Helper function to create CFString from Zig string @@ -119,7 +115,7 @@ pub fn get_vpn_info() !void { // Convert CFStringRef to C string (null-terminated) } -pub fn get_battery_info(allocator: std.mem.Allocator) ![]const u8 { +pub fn get_battery_info(buf: []u8) ![]const u8 { const power_sources_info: c.CFTypeRef = c.IOPSCopyPowerSourcesInfo(); if (power_sources_info == null) { @@ -169,16 +165,16 @@ pub fn get_battery_info(allocator: std.mem.Allocator) ![]const u8 { if (std.mem.eql(u8, power_source_state, "Battery Power")) { if (time_to_empty_mins < 0) { - return try std.fmt.allocPrint(allocator, ": {d}%, ?m left\n", .{ percent, hours, minutes }); + return try std.fmt.bufPrint(buf, ": {d}%, ?m left\n", .{ percent, hours, minutes }); } else { - return try std.fmt.allocPrint(allocator, ": {d}%, {d}h:{d}m left\n", .{ percent, hours, minutes }); + return try std.fmt.bufPrint(buf, ": {d}%, {d}h:{d}m left\n", .{ percent, hours, minutes }); } } else { - return try std.fmt.allocPrint(allocator, ": {d}%, {s}\n", .{ percent, "charging" }); + return try std.fmt.bufPrint(buf, ": {d}%, {s}\n", .{ percent, "charging" }); } } -pub fn macos_cpu_info(allocator: std.mem.Allocator) ![]const u8 { +pub fn get_cpu_info(buf: []u8) ![]const u8 { var cpu_brand: [128]u8 = undefined; var cpu_brand_size: usize = cpu_brand.len; var cpu_cores: c_int = 0; @@ -193,12 +189,10 @@ pub fn macos_cpu_info(allocator: std.mem.Allocator) ![]const u8 { } // if (c.sysctlbyname("hw.cpufrequency", &)) - const buf = try std.fmt.allocPrint(allocator, ": {s} ({d} cores)\n", .{ cpu_brand[0..cpu_brand_size], cpu_cores }); - - return buf; + return try std.fmt.bufPrint(buf, ": {s} ({d} cores)\n", .{ cpu_brand[0..cpu_brand_size], cpu_cores }); } -pub fn macos_uptime(allocator: std.mem.Allocator) ![]const u8 { +pub fn get_uptime(buf: []u8) ![]const u8 { var mib: [2]c.integer_t = [_]c.integer_t{ c.CTL_KERN, c.KERN_BOOTTIME }; var boottime: c.struct_timeval = undefined; var size: u64 = @sizeOf(c.struct_timeval); @@ -216,9 +210,7 @@ pub fn macos_uptime(allocator: std.mem.Allocator) ![]const u8 { const hours = @divFloor(@rem(uptime_seconds, (24 * 60 * 60)), (60 * 60)); const minutes = @divFloor(@rem(uptime_seconds, (60 * 60)), 60); - const buf = try std.fmt.allocPrint(allocator, ": {d} days, {d} hours, {d} mins\n", .{ days, hours, minutes }); - - return buf; + return try std.fmt.bufPrint(buf, ": {d} days, {d} hours, {d} mins\n", .{ days, hours, minutes }); } fn version_to_name(version: NSOperatingSystemVersion) []const u8 { diff --git a/src/main.zig b/src/main.zig index f32201b..3522151 100644 --- a/src/main.zig +++ b/src/main.zig @@ -7,12 +7,12 @@ const sys = @import("sys.zig"); const log = std.log.scoped(.main); -const apple_logo = @embedFile("assets/apple-white.png"); -const freebsd = @embedFile("assets/freebsd.png"); - -const Event = union(enum) { - key_press: vaxis.Key, - winsize: vaxis.Winsize, +const logo = + switch (builtin.target.os.tag) { + .macos => @embedFile("assets/apple-white.png"), + .freebsd => @embedFile("assets/orby.png"), + .linux => @embedFile("assets/tux.png"), + else => @embedFile("assets/ziggy.png"), }; pub fn main() !void { @@ -24,7 +24,6 @@ pub fn main() !void { } } - // const stdout = std.io.getStdOut().writer(); const allocator = gpa.allocator(); var tty = try vaxis.Tty.init(); @@ -36,56 +35,42 @@ pub fn main() !void { vx.caps.unicode = .unicode; vx.caps.kitty_graphics = true; - const battery = try macos.get_battery_info(allocator); - defer allocator.free(battery); - // _ = try macos.get_vpn_info(); - - // const os = try macos.macos_version(allocator); - const os = try sys.get_os_version(allocator); - defer allocator.free(os.text); - const kernel = try macos.macos_kernel_version(allocator); - defer allocator.free(kernel); - const uptime = try macos.macos_uptime(allocator); - defer allocator.free(uptime); - const cpu = try macos.macos_cpu_info(allocator); - defer allocator.free(cpu); - const current_shell = try sys.get_shell(allocator); - defer allocator.free(current_shell); - const memory = try macos.memory_info(allocator); - defer allocator.free(memory); - var term_buf: [64]u8 = undefined; const current_terminal = try sys.get_terminal(&term_buf); - // try tty.anyWriter().writeAll("\x1bc"); - // try tty.anyWriter().writeAll("\x1b[1;1H"); + var battery_buf: [64]u8 = undefined; + const battery = try sys.get_battery(&battery_buf); + + var os_buf: [64]u8 = undefined; + const os = try sys.get_os_version(&os_buf); + + var kernel_buf: [64]u8 = undefined; + const kernel = try sys.get_kernel_version(&kernel_buf); + + var uptime_buf: [64]u8 = undefined; + const uptime = try sys.get_uptime(&uptime_buf); + + var cpu_buf: [64]u8 = undefined; + const cpu = try sys.get_cpu_info(&cpu_buf); + + const current_shell = try sys.get_shell(allocator); + defer allocator.free(current_shell.text); + + var mem_buf: [64]u8 = undefined; + const memory = try sys.get_mem_info(&mem_buf); + var buf_writer = tty.bufferedWriter(); const writer = buf_writer.writer().any(); - // try writer.writeAll(vaxis.ctlseqs.unicode_set); - // defer vx.queryTerminalSend(writer) catch {}; - // defer writer.writeAll(vaxis.ctlseqs.unicode_reset) catch {}; - // defer tty.deinit(); const winsize: vaxis.Winsize = try vaxis.Tty.getWinsize(tty.fd); try vx.resize(allocator, writer, winsize); const win = vx.window(); win.clear(); - // win.hideCursor(); - var image: vaxis.Image = undefined; - switch (builtin.os.tag) { - .macos => { - image = try vx.loadImage(allocator, tty.anyWriter(), .{ .mem = apple_logo }); - }, - .freebsd => { - image = try vx.loadImage(allocator, writer, .{ .mem = freebsd }); - }, - else => @compileError("unsupported os"), - } + const image = try vx.loadImage(allocator, tty.anyWriter(), .{ .mem = logo }); const dims = try image.cellSize(win); - // const cursor_row = vx.state.cursor.row; const logo_win = win.child(.{ .y_off = 2, .x_off = 0, @@ -102,7 +87,6 @@ pub fn main() !void { var hostname_buf: [std.posix.HOST_NAME_MAX]u8 = undefined; const hostname = try std.posix.gethostname(&hostname_buf); - // const logo_win = win.child(.{ .y_off = 0, .x_off = 0 }); const border_locations = vaxis.Window.BorderOptions.Locations{ .top = true, .bottom = false, @@ -130,22 +114,31 @@ pub fn main() !void { var result: vaxis.Window.PrintResult = .{ .col = 0, .row = 0, .overflow = false }; const whoami_info = [_]vaxis.Cell.Segment{ - .{ .text = user, .style = .{ - .fg = .{ - .index = 7, + .{ + .text = user, + .style = .{ + .fg = .{ + .index = 7, + }, }, - } }, - .{ .text = "@", .style = .{ - .fg = .{ - .index = 15, + }, + .{ + .text = "@", + .style = .{ + .fg = .{ + .index = 15, + }, + .bold = true, }, - .bold = true, - } }, - .{ .text = hostname, .style = .{ - .fg = .{ - .index = 7, + }, + .{ + .text = hostname, + .style = .{ + .fg = .{ + .index = 7, + }, }, - } }, + }, }; const system_info = [_]vaxis.Cell.Segment{ .{ @@ -167,7 +160,7 @@ pub fn main() !void { .bold = true, }, }, - .{ .text = kernel }, + kernel, .{ .text = " Uptime", .style = .{ @@ -177,7 +170,7 @@ pub fn main() !void { .bold = true, }, }, - .{ .text = uptime }, + uptime, .{ .text = " CPU", .style = .{ @@ -187,7 +180,7 @@ pub fn main() !void { .bold = true, }, }, - .{ .text = cpu }, + cpu, .{ .text = " Memory", .style = .{ @@ -197,7 +190,7 @@ pub fn main() !void { .bold = true, }, }, - .{ .text = memory }, + memory, .{ .text = " Shell", .style = .{ @@ -207,7 +200,7 @@ pub fn main() !void { .bold = true, }, }, - .{ .text = current_shell }, + current_shell, .{ .text = " Terminal", .style = .{ @@ -217,7 +210,7 @@ pub fn main() !void { .bold = true, }, }, - .{ .text = current_terminal }, + current_terminal, .{ .text = " Battery", .style = .{ @@ -227,14 +220,7 @@ pub fn main() !void { .bold = true, }, }, - .{ - .text = battery, - // .style = .{ - // .fg = .{ - // .index = 2, - // }, - // }, - }, + battery, .{ .text = " ▂▂▂", .style = .{ @@ -367,80 +353,11 @@ pub fn main() !void { .text = " ", }, }; - // const logo_text = [_]vaxis.Cell.Segment{ - // .{ - // .text = " hello", - // }, - // }; try image.draw(logo_win, .{}); - // _ = try logo_text_win.print(&logo_text, .{}); - // try root.kitty_image_inline_copy(allocator, tty.anyWriter(), "/Users/kc/Sync/Images/apple-dark.png"); - result = try whoami_win.print(&whoami_info, .{ .wrap = .word }); - result = try info_win.print(&system_info, .{ .wrap = .word }); - // printf '\e[%sA\e[9999999D' "${lines:-0}" - // try tty.anyWriter().print("\x1b[{d}A\x1b[9999999D", .{winsize.rows}); - // try tty.anyWriter().writeAll("\x1b[1J"); - - // try logo_win.print(); - // const dimensions = try koko.cellSize(win); - - // const image = try vx.transmitLocalImagePath(allocator, tty.anyWriter(), "/Users/kc/Sync/Images/apple-white.png", dimensions.rows, dimensions.cols, .file, .png); - // defer vx.freeImage(tty.anyWriter(), image.id); - // try root.kitty_image_inline_copy(allocator, tty.anyWriter(), "/Users/kc/Sync/Images/apple-white.png"); - // try image.draw(win, .{}); - - // try vx.render(tty.anyWriter()); try vx.prettyPrint(tty.anyWriter()); try buf_writer.flush(); - - // try vx.queryTerminalSend(tty.anyWriter()); - - // Clear from cursor to beginning of the screen - // Move cursor to the upper left corner of the screen - // try stdout_file.writeAll("\x1b[9B"); - - // try vx.enterAltScreen(tty.anyWriter()); - - // var img2 = try vaxis. - // const koko = try vx.loadImage(allocator, writer, .{ .path = "/Users/kc/Sync/Images/apple-white.png" }); - // const koko = try vx.transmitImage(allocator, writer, &img1, .png); - // const image = [_]vaxis.Image{ - // // try vx.transmitImage(allocator, writer, &img1, .png), - // try vx.loadImage(allocator, writer, .{ .path = "/Users/kc/Sync/Images/apple-white.png" }), - // // vaxis.Image.DrawOptions{ .clip_region = .{ .x = 0, .y = 0 } }, - // }; - - // const dims = try image[0].cellSize(win); - - // try vx.render(writer); - // try stdout.print("\n\n\n\n\n\n\n\n\n", .{}); - - // try writer.writeFile() - // try stdout.writeAll("\x1b[m"); - // win.showCursor(); - // std.time.sleep(10000000); -} - -fn is_dark_mode(allocator: std.mem.Allocator) !bool { - const home_directory = detect_home_directory(); - const dark_mode_file_path = try std.fmt.allocPrint(allocator, "{s}/.dark-mode", .{home_directory}); - defer allocator.free(dark_mode_file_path); - const dark_mode = std.fs.cwd().createFile(dark_mode_file_path, .{ .exclusive = true }) catch |err| - switch (err) { - error.PathAlreadyExists => return true, - else => { - return false; - }, - }; - dark_mode.close(); - - return false; -} - -fn detect_home_directory() []const u8 { - return std.posix.getenv("HOME") orelse "/tmp"; } test "simple test" { diff --git a/src/sys.zig b/src/sys.zig index 0cb48c3..4230b8a 100644 --- a/src/sys.zig +++ b/src/sys.zig @@ -2,6 +2,7 @@ const std = @import("std"); const builtin = @import("builtin"); const vaxis = @import("vaxis"); +const linux = @import("linux.zig"); const macos = @import("macos.zig"); const OSVersion = struct { @@ -16,7 +17,7 @@ const Shell = struct { version: []const u8, }; -pub fn get_shell(allocator: std.mem.Allocator) ![]const u8 { +pub fn get_shell(allocator: std.mem.Allocator) !vaxis.Cell.Segment { const shell_env = std.posix.getenv("SHELL") orelse "Unknown"; var shell_path = std.mem.splitBackwards(u8, shell_env, "/"); @@ -26,11 +27,26 @@ pub fn get_shell(allocator: std.mem.Allocator) ![]const u8 { const zsh_version = try get_zsh_version(allocator, &buf, shell_env); // defer allocator.free(zsh_version); - return try std.fmt.allocPrint(allocator, ": {s} {s}\n", .{ filename, zsh_version }); + return .{ + .text = try std.fmt.allocPrint( + allocator, + ": {s} {s}\n", + .{ + filename, + zsh_version, + }, + ), + }; } else if (std.mem.eql(u8, filename, "bash")) { const bash_version = try get_bash_version(allocator, &buf, shell_env); - return try std.fmt.allocPrint(allocator, ": bash {s}\n", .{bash_version}); + return .{ + .text = try std.fmt.allocPrint( + allocator, + ": bash {s}\n", + .{bash_version}, + ), + }; } else if (std.mem.eql(u8, filename, "bash")) { const version = try std.process.Child.run( .{ @@ -41,31 +57,107 @@ pub fn get_shell(allocator: std.mem.Allocator) ![]const u8 { defer allocator.free(version.stdout); defer allocator.free(version.stderr); - return try std.fmt.allocPrint(allocator, ": {s}\n", .{version.stdout}); + return .{ + .text = try std.fmt.allocPrint( + allocator, + ": {s}\n", + .{version.stdout}, + ), + }; } - return try std.fmt.allocPrint(allocator, ": {s}\n", .{shell_env}); + return .{ + .text = try std.fmt.allocPrint(allocator, ": {s}\n", .{shell_env}), + }; } -pub fn get_os_version(allocator: std.mem.Allocator) !vaxis.Cell.Segment { +pub fn get_kernel_version(buf: []u8) !vaxis.Cell.Segment { switch (builtin.os.tag) { .macos => { return .{ - .text = try macos.macos_version(allocator), + .text = try macos.get_kernel_version(buf), }; }, - else => return .{ .text = "" }, + else => return .{ .text = try std.fmt.bufPrint(buf, "unknown", .{}) }, } } -pub fn get_terminal(buf: []u8) ![]const u8 { +pub fn get_uptime(buf: []u8) !vaxis.Cell.Segment { + switch (builtin.os.tag) { + .macos => { + return .{ + .text = try macos.get_uptime(buf), + }; + }, + else => return .{ .text = try std.fmt.bufPrint(buf, "unknown", .{}) }, + } +} + +pub fn get_cpu_info(buf: []u8) !vaxis.Cell.Segment { + switch (builtin.os.tag) { + .macos => { + return .{ + .text = try macos.get_cpu_info(buf), + }; + }, + else => return .{ .text = try std.fmt.bufPrint(buf, "unknown", .{}) }, + } +} +pub fn get_mem_info(buf: []u8) !vaxis.Cell.Segment { + switch (builtin.os.tag) { + .macos => { + return .{ + .text = try macos.get_mem_info(buf), + }; + }, + else => return .{ .text = try std.fmt.bufPrint(buf, "unknown", .{}) }, + } +} + +pub fn get_battery(buf: []u8) !vaxis.Cell.Segment { + switch (builtin.os.tag) { + .macos => { + return .{ + .text = try macos.get_battery_info(buf), + }; + }, + else => return .{ .text = "unknown" }, + } +} + +pub fn get_os_version(buf: []u8) !vaxis.Cell.Segment { + switch (builtin.os.tag) { + .macos => { + return .{ + .text = try macos.macos_version(buf), + }; + }, + .linux => { + return .{ + .text = try std.fmt.bufPrint(buf, "{s} {s}", .{ try linux.kernel_version(), try linux.distribution() }), + }; + }, + .freebsd => { + return .{ + .text = try std.fmt.bufPrint(buf, "not implemented", .{}), + }; + }, + else => return .{ .text = try std.fmt.bufPrint(buf, "unknown", .{}) }, + } +} + +pub fn get_terminal(buf: []u8) !vaxis.Cell.Segment { const term_program = std.posix.getenv("TERM_PROGRAM") orelse "Unknown"; if (std.mem.eql(u8, term_program, "ghostty")) { - return try std.fmt.bufPrint(buf, ": {s} 󰊠\n", .{term_program}); + return .{ + .text = try std.fmt.bufPrint(buf, ": {s} 󰊠\n", .{term_program}), + }; } - return try std.fmt.bufPrint(buf, ": {s}\n", .{term_program}); + return .{ + .text = try std.fmt.bufPrint(buf, ": {s}\n", .{term_program}), + }; } fn get_zsh_version(allocator: std.mem.Allocator, buf: []u8, zsh_path: []const u8) ![]const u8 {