diff --git a/src/main.zig b/src/main.zig index 6a4b5f5..0211c27 100644 --- a/src/main.zig +++ b/src/main.zig @@ -17,9 +17,24 @@ const bg_left_color = Color{ .r = 0, .g = 0, .b = 0 }; const bg_right_color = Color{ .r = 0.2, .g = 0.2, .b = 0.2 }; pub fn main() !void { - var arena = heap.ArenaAllocator.init(heap.page_allocator); + var gpa = heap.GeneralPurposeAllocator(.{}){}; + defer _ = gpa.deinit(); + var arena = heap.ArenaAllocator.init(gpa.allocator()); defer arena.deinit(); + var backlight_count: usize = 0; + var powersupply_count: usize = 0; + + var backlight_dir = try std.fs.openDirAbsolute("/sys/class/backlight", .{ .iterate = true }); + defer backlight_dir.close(); + var backlight_it = backlight_dir.iterate(); + while (try backlight_it.next()) |_| backlight_count += 1; + + var powersupply_dir = try std.fs.openDirAbsolute("/sys/class/power_supply", .{ .iterate = true }); + defer powersupply_dir.close(); + var powersupply_it = powersupply_dir.iterate(); + while (try powersupply_it.next()) |_| powersupply_count += 1; + const stdout_file = std.io.getStdOut().writer(); var bw = std.io.bufferedWriter(stdout_file); const stdout = bw.writer(); @@ -27,15 +42,25 @@ pub fn main() !void { try stdout.print("{{\"version\":1}}\n[\n", .{}); try bw.flush(); - const modules = [_]Module{ - uptime.init(arena.allocator()).module, - loadavg.init(arena.allocator()).module, - memory.init(arena.allocator()).module, - volume.init(arena.allocator()).module, - display.init(arena.allocator()).module, - battery.init(arena.allocator()).module, - calendar.init(arena.allocator()).module, - }; + var _uptime = try uptime.init(gpa.allocator()); + var _loadavg = try loadavg.init(gpa.allocator()); + var _memory = try memory.init(gpa.allocator()); + var _volume = try volume.init(gpa.allocator()); + var _display = try display.init(gpa.allocator()); + var _battery = try battery.init(gpa.allocator()); + var _calendar = try calendar.init(gpa.allocator()); + + var module_arr = std.ArrayList(*Module).init(gpa.allocator()); + defer module_arr.deinit(); + try module_arr.append(&_uptime.module); + try module_arr.append(&_loadavg.module); + try module_arr.append(&_memory.module); + try module_arr.append(&_volume.module); + if (backlight_count > 0) try module_arr.append(&_display.module); + if (powersupply_count > 0) try module_arr.append(&_battery.module); + try module_arr.append(&_calendar.module); + const modules = try module_arr.toOwnedSlice(); + const modules_len = 1 / @as(f32, @floatFromInt(modules.len)); var act = posix.Sigaction{ .handler = .{ .handler = sigHandler }, @@ -45,19 +70,18 @@ pub fn main() !void { try posix.sigaction(posix.SIG.USR1, &act, null); while (true) { - // const start_time = std.time.milliTimestamp(); + const start_time = std.time.milliTimestamp(); try stdout.print("[", .{}); - const modules_len = 1 / @as(f32, @floatFromInt(modules.len)); var bg = Color{ .r = 0.0, .g = 0.0, .b = 0.0 }; for (modules, 0..) |module, idx| { - // const module_start_time = std.time.nanoTimestamp(); + const module_start_time = std.time.nanoTimestamp(); - var output = module.getJson() catch { + const output = module.getBlock(arena.allocator()) catch { const output = Module.JSON{ .full_text = " [error] ", .background = try bg.getString(arena.allocator()), - .color = try bg.add(Color{ .r = 1, .g = 0.3, .b = 0.3 }).getString(arena.allocator()), + .color = try bg.add(Color{ .r = 1, .g = 0.1, .b = 0.1 }).getString(arena.allocator()), .separator = false, .separator_block_width = 0, }; @@ -67,30 +91,36 @@ pub fn main() !void { bg = bg_left_color.mix(bg_right_color, progress); continue; }; - output.full_text = try std.fmt.allocPrint(arena.allocator(), " {s} ", .{output.full_text}); - output.background = try bg.getString(arena.allocator()); - var color = bg.add(Color{ .r = 0.6, .g = 0.6, .b = 0.6 }); - if (output.color == null) output.color = try color.getString(arena.allocator()); - output.separator = false; - output.separator_block_width = 0; - try json.stringify(output, .{ .emit_null_optional_fields = false }, stdout); + std.debug.print("output: {any}\n", .{output}); + + const bg_color = bg.mix(Color{ .r = 0.25, .g = 0.1, .b = 0.1 }, @max(0.0, output.severity - 1.0)); + const fg_color = bg_color.add(Color{ .r = 0.6, .g = 0.6, .b = 0.6 }) + .mix(Color{ .r = 1, .g = 0.1, .b = 0.1 }, output.severity) + .mix(Color{ .r = 1, .g = 0.3, .b = 0.54 }, @max(0.0, output.severity - 1.0)); + const jsonBlock = Module.JSON{ + .full_text = try std.fmt.allocPrint(arena.allocator(), " {s} ", .{output.full_text}), + .background = try bg_color.getString(arena.allocator()), + .color = try fg_color.getString(arena.allocator()), + .separator = false, + .separator_block_width = 0, + }; + try json.stringify(jsonBlock, .{ .emit_null_optional_fields = false }, stdout); try stdout.print(",", .{}); const progress = @as(f32, @floatFromInt(idx + 1)) * modules_len; - // std.debug.print("\n{d}\n", .{progress}); bg = bg_left_color.mix(bg_right_color, progress); - // const module_end_time = std.time.nanoTimestamp(); - // std.debug.print("\nmodule {d}: finished in {d}ns", .{ idx, module_end_time - module_start_time }); + const module_end_time = std.time.nanoTimestamp(); + std.debug.print("module {d} finished in {d}ns\n", .{ idx, module_end_time - module_start_time }); } try stdout.print("],\n", .{}); - // std.debug.print("\n", .{}); + std.debug.print("\n", .{}); try bw.flush(); _ = arena.reset(.retain_capacity); - // const end_time = std.time.milliTimestamp(); - // std.debug.print("\nFinished in {d}ms", .{end_time - start_time}); + const end_time = std.time.milliTimestamp(); + std.debug.print("\nFinished in {d}ms\n\n", .{end_time - start_time}); var i: usize = 0; while (!refresh and i < 100) : (i += 1) std.time.sleep(10_000_000); refresh = false; @@ -108,6 +138,7 @@ pub const Color = struct { g: f32, b: f32, + // creates a color from an html hexcode string pub fn init(string: []const u8) !Color { const r = try std.fmt.parseInt(u8, string[1..2], 16); const g = try std.fmt.parseInt(u8, string[3..4], 16); @@ -119,6 +150,7 @@ pub const Color = struct { }; } + // returns the color as an html hexcode string pub fn getString(self: *const Color, allocator: std.mem.Allocator) ![]const u8 { const v = self.getVector(); const x = @max(VecRGB{ 0.0, 0.0, 0.0 }, @min(v, VecRGB{ 1.0, 1.0, 1.0 })); @@ -133,12 +165,14 @@ pub const Color = struct { }); } + // returns the result of `a` plus `b` pub fn add(a: *const Color, b: Color) Color { const va = a.getVector(); const vb = b.getVector(); return Color.fromVector(va + vb); } + // returns the result of the linear interpolation between `a` and `b` by amount `t` pub fn mix(a: *const Color, b: Color, t: f32) Color { const va = a.getVector(); const vb = b.getVector(); @@ -146,6 +180,15 @@ pub const Color = struct { return Color.fromVector(@mulAdd(VecRGB, vb - va, vt, va)); } + // returns the color with its rgb values clamped to those in `min` and `max` + pub fn clamp(self: *const Color, min: Color, max: Color) Color { + return .{ + .r = @max(max.r, @min(min.r, self.r)), + .g = @max(max.g, @min(min.g, self.g)), + .b = @max(max.b, @min(min.b, self.b)), + }; + } + fn getVector(self: *const Color) VecRGB { return VecRGB{ self.r, @@ -162,9 +205,14 @@ pub const Color = struct { }; } + // why did i use vectors?? this was probably a bad idea, + // but now i am too lazy to go back. + // it could have worked if i had made them chainable somehow, + // so it doesn't get converted to and from a vector constantly. pub const VecRGB = @Vector(3, f32); }; +// the hell were these for?? pub fn getBgColor(idx: usize, override: ?[]const u8) []const u8 { if (override) |o| return o; return switch (idx % 2) { diff --git a/src/module.zig b/src/module.zig index 45e9c0b..0e08bfe 100644 --- a/src/module.zig +++ b/src/module.zig @@ -22,18 +22,16 @@ pub const JSON = struct { const Self = @This(); -allocator: std.mem.Allocator, -getJsonFn: *const fn (*const Self) anyerror!JSON, +getBlockFn: *const fn (*Self, std.mem.Allocator) anyerror!Block, -pub fn getJson(self: *const Self) anyerror!JSON { - return self.getJsonFn(self); +pub fn getBlock(self: *Self, allocator: std.mem.Allocator) anyerror!Block { + return self.getBlockFn(self, allocator); } pub const Block = struct { full_text: []const u8, - short_text: ?[]const u8, + short_text: ?[]const u8 = null, /// from 0.0 to 1.0, affects foreground color /// from 1.0 to 2.0, affects background and foreground colors - urgency: f32, + severity: f32 = 0.0, }; - diff --git a/src/modules/battery.zig b/src/modules/battery.zig index 7aff63f..db23bde 100644 --- a/src/modules/battery.zig +++ b/src/modules/battery.zig @@ -4,17 +4,16 @@ const Self = @This(); module: Module, -pub fn init(allocator: std.mem.Allocator) Self { +pub fn init(allocator: std.mem.Allocator) !Self { + _ = allocator; return .{ - .module = .{ - .allocator = allocator, - .getJsonFn = getJson, - }, + .module = .{ .getBlockFn = getBlock }, }; } -pub fn getJson(module: *const Module) !Module.JSON { - const self: *const Self = @fieldParentPtr("module", module); +pub fn getBlock(module: *Module, allocator: std.mem.Allocator) !Module.Block { + _ = module; + // const self: *const Self = @fieldParentPtr("module", module); var energy_full_file = try std.fs.openFileAbsolute("/sys/class/power_supply/BAT0/energy_full", .{}); defer energy_full_file.close(); @@ -23,9 +22,9 @@ pub fn getJson(module: *const Module) !Module.JSON { var status_file = try std.fs.openFileAbsolute("/sys/class/power_supply/BAT0/status", .{}); defer status_file.close(); - const energy_full_string = try energy_full_file.reader().readAllAlloc(self.module.allocator, 32); - const energy_now_string = try energy_now_file.reader().readAllAlloc(self.module.allocator, 32); - const status_string = try status_file.reader().readAllAlloc(self.module.allocator, 32); + const energy_full_string = try energy_full_file.reader().readAllAlloc(allocator, 32); + const energy_now_string = try energy_now_file.reader().readAllAlloc(allocator, 32); + const status_string = try status_file.reader().readAllAlloc(allocator, 32); const energy_full = try std.fmt.parseInt(u32, energy_full_string[0 .. energy_full_string.len - 1], 10); const energy_now = try std.fmt.parseInt(u32, energy_now_string[0 .. energy_now_string.len - 1], 10); @@ -40,6 +39,6 @@ pub fn getJson(module: *const Module) !Module.JSON { const percent_left = @as(f32, @floatFromInt(energy_now)) / @as(f32, @floatFromInt(energy_full)) * 100; return .{ - .full_text = try std.fmt.allocPrint(self.module.allocator, "{s} {d:.2}%", .{ status, percent_left }), + .full_text = try std.fmt.allocPrint(allocator, "{s} {d:.2}%", .{ status, percent_left }), }; } diff --git a/src/modules/calendar.zig b/src/modules/calendar.zig index 19bbd62..89b73bc 100644 --- a/src/modules/calendar.zig +++ b/src/modules/calendar.zig @@ -4,22 +4,21 @@ const Self = @This(); module: Module, -pub fn init(allocator: std.mem.Allocator) Self { +pub fn init(allocator: std.mem.Allocator) !Self { + _ = allocator; return .{ - .module = .{ - .allocator = allocator, - .getJsonFn = getJson, - }, + .module = .{ .getBlockFn = getBlock }, }; } -pub fn getJson(module: *const Module) !Module.JSON { - const self: *const Self = @fieldParentPtr("module", module); +pub fn getBlock(module: *Module, allocator: std.mem.Allocator) !Module.Block { + _ = module; + // const self: *const Self = @fieldParentPtr("module", module); + var tz_file = try std.fs.openFileAbsolute("/etc/localtime", .{}); defer tz_file.close(); - var tz = try std.tz.Tz.parse(self.module.allocator, tz_file.reader()); + var tz = try std.tz.Tz.parse(allocator, tz_file.reader()); defer tz.deinit(); - // std.debug.print("{any}\n", .{tz.timetypes}); const timestamp = std.time.timestamp() + tz.timetypes[tz.timetypes.len - 1].offset + std.time.s_per_day; @@ -30,7 +29,7 @@ pub fn getJson(module: *const Module) !Module.JSON { const month_day = year_day.calculateMonthDay(); return .{ - .full_text = try std.fmt.allocPrint(self.module.allocator, "{d}-{d:0>2}-{d:0>2} {d:0>2}:{d:0>2}:{d:0>2}", .{ + .full_text = try std.fmt.allocPrint(allocator, "{d}-{d:0>2}-{d:0>2} {d:0>2}:{d:0>2}:{d:0>2}", .{ year_day.year, @intFromEnum(month_day.month), month_day.day_index, diff --git a/src/modules/display.zig b/src/modules/display.zig index 8663c66..6941b6c 100644 --- a/src/modules/display.zig +++ b/src/modules/display.zig @@ -4,31 +4,30 @@ const Self = @This(); module: Module, -pub fn init(allocator: std.mem.Allocator) Self { +pub fn init(allocator: std.mem.Allocator) !Self { + _ = allocator; return .{ - .module = .{ - .allocator = allocator, - .getJsonFn = getJson, - }, + .module = .{ .getBlockFn = getBlock }, }; } -pub fn getJson(module: *const Module) !Module.JSON { - const self: *const Self = @fieldParentPtr("module", module); +pub fn getBlock(module: *Module, allocator: std.mem.Allocator) !Module.Block { + _ = module; + // const self: *const Self = @fieldParentPtr("module", module); var brightness_full_file = try std.fs.openFileAbsolute("/sys/class/backlight/acpi_video0/max_brightness", .{}); defer brightness_full_file.close(); var brightness_now_file = try std.fs.openFileAbsolute("/sys/class/backlight/acpi_video0/actual_brightness", .{}); defer brightness_now_file.close(); - const brightness_full_string = try brightness_full_file.reader().readAllAlloc(self.module.allocator, 32); - const brightness_now_string = try brightness_now_file.reader().readAllAlloc(self.module.allocator, 32); + const brightness_full_string = try brightness_full_file.reader().readAllAlloc(allocator, 32); + const brightness_now_string = try brightness_now_file.reader().readAllAlloc(allocator, 32); const brightness_full = try std.fmt.parseInt(u32, brightness_full_string[0 .. brightness_full_string.len - 1], 10); const brightness_now = try std.fmt.parseInt(u32, brightness_now_string[0 .. brightness_now_string.len - 1], 10); const percent = @as(f32, @floatFromInt(brightness_now)) / @as(f32, @floatFromInt(brightness_full)) * 100; return .{ - .full_text = try std.fmt.allocPrint(self.module.allocator, "{d:.2}%", .{percent}), + .full_text = try std.fmt.allocPrint(allocator, "{d:.2}%", .{percent}), }; } diff --git a/src/modules/loadavg.zig b/src/modules/loadavg.zig index 888b3b4..293f6dc 100644 --- a/src/modules/loadavg.zig +++ b/src/modules/loadavg.zig @@ -1,30 +1,37 @@ const std = @import("std"); +const mem = std.mem; +const fs = std.fs; const Module = @import("../module.zig"); const Self = @This(); +cores: usize, module: Module, -pub fn init(allocator: std.mem.Allocator) Self { +pub fn init(allocator: std.mem.Allocator) !Self { + var cpuinfo_file = try fs.openFileAbsolute("/proc/cpuinfo", .{}); + defer cpuinfo_file.close(); + const cpuinfo = try cpuinfo_file.reader().readAllAlloc(allocator, 1024 * 128); + defer allocator.free(cpuinfo); + const cores = mem.count(u8, cpuinfo, "\n\n"); + return .{ - .module = .{ - .allocator = allocator, - .getJsonFn = getJson, - }, + .cores = cores, + .module = .{ .getBlockFn = getBlock }, }; } -pub fn getJson(module: *const Module) !Module.JSON { +pub fn getBlock(module: *Module, allocator: std.mem.Allocator) !Module.Block { const self: *const Self = @fieldParentPtr("module", module); - var loadavg_file = try std.fs.openFileAbsolute("/proc/loadavg", .{}); + var loadavg_file = try fs.openFileAbsolute("/proc/loadavg", .{}); defer loadavg_file.close(); - const loadavg_string = try loadavg_file.reader().readAllAlloc(self.module.allocator, 64); + const loadavg_string = try loadavg_file.reader().readAllAlloc(allocator, 64); var loadavg_split = std.mem.splitScalar(u8, loadavg_string[0 .. loadavg_string.len - 1], ' '); const loadavg = try std.fmt.parseFloat(f32, loadavg_split.first()); return .{ - .full_text = try std.fmt.allocPrint(self.module.allocator, "{d:0>1.2}", .{loadavg}), - .color = if (loadavg > 1.95) "#ff0000" else null, + .full_text = try std.fmt.allocPrint(allocator, "{d:0>1.2}", .{loadavg}), + .severity = @max(0.0, loadavg - @as(f32, @floatFromInt(self.cores))), }; } diff --git a/src/modules/memory.zig b/src/modules/memory.zig index 73cbe46..af0d3cd 100644 --- a/src/modules/memory.zig +++ b/src/modules/memory.zig @@ -4,22 +4,21 @@ const Self = @This(); module: Module, -pub fn init(allocator: std.mem.Allocator) Self { +pub fn init(allocator: std.mem.Allocator) !Self { + _ = allocator; return .{ - .module = .{ - .allocator = allocator, - .getJsonFn = getJson, - }, + .module = .{ .getBlockFn = getBlock }, }; } -pub fn getJson(module: *const Module) !Module.JSON { - const self: *const Self = @fieldParentPtr("module", module); +pub fn getBlock(module: *Module, allocator: std.mem.Allocator) !Module.Block { + _ = module; + // const self: *const Self = @fieldParentPtr("module", module); var meminfo_file = try std.fs.openFileAbsolute("/proc/meminfo", .{}); defer meminfo_file.close(); - const meminfo_string = try meminfo_file.reader().readAllAlloc(self.module.allocator, 4096); + const meminfo_string = try meminfo_file.reader().readAllAlloc(allocator, 4096); const mem_total_idx = std.mem.indexOf(u8, meminfo_string, "MemTotal:"); const mem_available_idx = std.mem.indexOf(u8, meminfo_string, "MemAvailable:"); const mem_total_newline = std.mem.indexOfScalarPos(u8, meminfo_string, mem_total_idx.?, '\n'); @@ -34,6 +33,6 @@ pub fn getJson(module: *const Module) !Module.JSON { const mem = mem_total - mem_available; return .{ - .full_text = try std.fmt.allocPrint(self.module.allocator, "{d:.3}/{d:.0} GB", .{ mem / 1000 / 1000, mem_total / 1000 / 1000 }), + .full_text = try std.fmt.allocPrint(allocator, "{d:.3}/{d:.0} GB", .{ mem / 1000 / 1000, mem_total / 1000 / 1000 }), }; } diff --git a/src/modules/uptime.zig b/src/modules/uptime.zig index 769c79e..cd6766b 100644 --- a/src/modules/uptime.zig +++ b/src/modules/uptime.zig @@ -4,22 +4,21 @@ const Self = @This(); module: Module, -pub fn init(allocator: std.mem.Allocator) Self { +pub fn init(allocator: std.mem.Allocator) !Self { + _ = allocator; return .{ - .module = .{ - .allocator = allocator, - .getJsonFn = getJson, - }, + .module = .{ .getBlockFn = getBlock }, }; } -pub fn getJson(module: *const Module) !Module.JSON { - const self: *const Self = @fieldParentPtr("module", module); +pub fn getBlock(module: *Module, allocator: std.mem.Allocator) !Module.Block { + _ = module; + // const self: *const Self = @fieldParentPtr("module", module); var uptime_file = try std.fs.openFileAbsolute("/proc/uptime", .{}); defer uptime_file.close(); - const uptime_string = try uptime_file.reader().readAllAlloc(self.module.allocator, 256); + const uptime_string = try uptime_file.reader().readAllAlloc(allocator, 256); var uptime_split = std.mem.splitScalar(u8, uptime_string[0 .. uptime_string.len - 1], ' '); var uptime = try std.fmt.parseFloat(f32, uptime_split.first()); @@ -30,6 +29,6 @@ pub fn getJson(module: *const Module) !Module.JSON { uptime /= 24; return .{ - .full_text = try std.fmt.allocPrint(self.module.allocator, "{d:0>1.0}d {d:0>1.0}h {d:.0}m", .{ uptime, hours, mins }), + .full_text = try std.fmt.allocPrint(allocator, "{d:0>1.0}d {d:0>1.0}h {d:.0}m", .{ uptime, hours, mins }), }; } diff --git a/src/modules/volume.zig b/src/modules/volume.zig index 783f66c..5110856 100644 --- a/src/modules/volume.zig +++ b/src/modules/volume.zig @@ -4,28 +4,27 @@ const Self = @This(); module: Module, -pub fn init(allocator: std.mem.Allocator) Self { +pub fn init(allocator: std.mem.Allocator) !Self { + _ = allocator; return .{ - .module = .{ - .allocator = allocator, - .getJsonFn = getJson, - }, + .module = .{ .getBlockFn = getBlock }, }; } -pub fn getJson(module: *const Module) !Module.JSON { - const self: *const Self = @fieldParentPtr("module", module); +pub fn getBlock(module: *Module, allocator: std.mem.Allocator) !Module.Block { + _ = module; + // const self: *const Self = @fieldParentPtr("module", module); const child = try std.ChildProcess.run(.{ .argv = &[_][]const u8{ "amixer", "sget", "Master" }, - .allocator = self.module.allocator, + .allocator = allocator, }); if (std.mem.indexOfScalar(u8, child.stdout, '[')) |volume_idx| { if (std.mem.indexOfScalarPos(u8, child.stdout, volume_idx, '%')) |percent_idx| { const volume = try std.fmt.parseInt(u8, child.stdout[volume_idx + 1 .. percent_idx], 10); return .{ - .full_text = try std.fmt.allocPrint(self.module.allocator, "{d: >2}%", .{volume}), + .full_text = try std.fmt.allocPrint(allocator, "{d: >2}%", .{volume}), }; } else return .{ .full_text = "?" }; } else return .{ .full_text = "?" };