Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8132b0fc04 | ||
|
|
d5bb5b19c5 | ||
|
|
1d7a175d29 | ||
|
|
61ceb027a6 | ||
|
|
3e55f6a973 | ||
|
|
a5f4a60d46 | ||
|
|
36ff1857b7 | ||
|
|
48ab100e13 | ||
|
|
1363bad02d | ||
|
|
12435bae0e | ||
|
|
d26be667a1 | ||
|
|
b3ca5ae9eb | ||
|
|
e30c6ccc73 | ||
|
|
8599fe92cf | ||
|
|
19facc09ef | ||
|
|
0aec3d8e5b | ||
|
|
dd2f50c79c | ||
|
|
16bb74c47b | ||
|
|
62df4a52dc | ||
|
|
20f9c6e1d5 | ||
|
|
b09443db4d | ||
|
|
dd3b79b32d | ||
|
|
22376139f2 | ||
|
|
d6978cd4b2 | ||
|
|
2f847fbef3 | ||
|
|
cec2b8068a | ||
|
|
6564d85845 | ||
|
|
a835074ee6 | ||
|
|
3d16102f37 | ||
|
|
24a5e98089 | ||
|
|
f03f7e163c | ||
|
|
69d02a4bb7 | ||
|
|
6a86a81fcc | ||
|
|
a125053c70 | ||
|
|
d9ec3a7de7 | ||
|
|
5f6460f46e | ||
|
|
aab5212e6e | ||
|
|
abff59b7d6 |
8
.github/workflows/build.yml
vendored
8
.github/workflows/build.yml
vendored
@@ -65,17 +65,11 @@ jobs:
|
||||
ls -la zig-out/bin/
|
||||
file zig-out/bin/zigfetch-${{ matrix.target }}
|
||||
|
||||
- name: Create archive
|
||||
run: |
|
||||
tar -czf zigfetch-${{ matrix.target }}.tar.gz -C zig-out/bin zigfetch-${{ matrix.target }}
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: zigfetch-${{ matrix.target }}
|
||||
path: |
|
||||
# zig-out/bin/zigfetch-${{ matrix.target }}
|
||||
zigfetch-${{ matrix.target }}.tar.gz
|
||||
path: zig-out/bin/zigfetch-${{ matrix.target }}
|
||||
retention-days: 3
|
||||
|
||||
test:
|
||||
|
||||
84
README.md
84
README.md
@@ -2,10 +2,15 @@
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
| Default config | Custom config |
|
||||
| :-----------------------------------------------------: | :---------------------------------------------------: |
|
||||
|  |  |
|
||||
|
||||
---
|
||||
|
||||
- [Description](#description)
|
||||
@@ -74,6 +79,85 @@ $ touch config.json
|
||||
$ cp /path/to/zigfetch/config.json ~/.config/zigfetch/config.json
|
||||
```
|
||||
|
||||
#### Modules
|
||||
|
||||
Available modules:
|
||||
|
||||
- Os
|
||||
- Kernel
|
||||
- Uptime
|
||||
- Packages
|
||||
- Shell
|
||||
- Cpu
|
||||
- Gpu
|
||||
- Ram
|
||||
- Swap
|
||||
- Disk
|
||||
- Net
|
||||
- WM (Window Manager)
|
||||
- Terminal
|
||||
- Locale
|
||||
- Custom
|
||||
|
||||
| Module type | Linux | macOS | Windows |
|
||||
| :---------: | :-------------: | :----------------------: | :-----: |
|
||||
| os | Yes | Yes | WIP |
|
||||
| kernel | Yes | Yes | WIP |
|
||||
| uptime | Yes | Yes | WIP |
|
||||
| packages | WIP | Yes (Homebrew, Macports) | WIP |
|
||||
| shell | Yes (bash, zsh) | Yes (bash, zsh) | WIP |
|
||||
| cpu | Yes | Yes | WIP |
|
||||
| gpu | Yes | Yes (Apple Silicon only) | WIP |
|
||||
| ram | Yes | Yes | WIP |
|
||||
| swap | Yes | Yes | WIP |
|
||||
| disk | Yes | Yes | WIP |
|
||||
| net | Yes | Yes | WIP |
|
||||
| wm | Yes | Yes | WIP |
|
||||
| terminal | Yes | Yes | WIP |
|
||||
| locale | Yes | Yes | WIP |
|
||||
|
||||
```json
|
||||
"modules": [
|
||||
{
|
||||
"type": "os",
|
||||
"key": "OS",
|
||||
"key_color": "#5E81AC"
|
||||
},
|
||||
...
|
||||
]
|
||||
```
|
||||
|
||||
#### Custom module
|
||||
|
||||
```json
|
||||
"modules": [
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "-----------",
|
||||
"key_color": "#5E81AC"
|
||||
},
|
||||
...
|
||||
]
|
||||
```
|
||||
|
||||
#### Custom ASCII art
|
||||
|
||||
To use an ASCII art of your choice:
|
||||
|
||||
```json
|
||||
"ascii_abs_path": "absolute_path/to/your/ascii_art.txt"
|
||||
```
|
||||
|
||||
Don't use the `~` character.
|
||||
|
||||
#### Username and Hostname color
|
||||
|
||||
To change the Username and Hostname color (HEX colors only):
|
||||
|
||||
```json
|
||||
"username_hostname_color": "#5E81AC"
|
||||
```
|
||||
|
||||
## Roadtrip
|
||||
|
||||
- [ ] Add ASCII art for each operating system and Linux distro
|
||||
|
||||
BIN
assets/screenshot-custom-config.png
Normal file
BIN
assets/screenshot-custom-config.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 209 KiB |
BIN
assets/screenshot-default-config.png
Normal file
BIN
assets/screenshot-default-config.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 200 KiB |
@@ -10,7 +10,7 @@
|
||||
|
||||
// This is a [Semantic Version](https://semver.org/).
|
||||
// In a future version of Zig it will be used for package deduplication.
|
||||
.version = "0.21.1",
|
||||
.version = "0.24.0",
|
||||
|
||||
// Together with name, this represents a globally unique package
|
||||
// identifier. This field is generated by the Zig toolchain when the
|
||||
|
||||
@@ -72,9 +72,10 @@ pub fn printAsciiAndModules(allocator: std.mem.Allocator, ascii_art_path: ?[]u8,
|
||||
|
||||
var ascii_art_data: []const u8 = undefined;
|
||||
if (ascii_art_path) |ascii| {
|
||||
var ascii_file = try std.fs.cwd().openFile(ascii, .{});
|
||||
const ascii_file = try std.fs.cwd().openFile(ascii, .{ .mode = .read_only });
|
||||
defer ascii_file.close();
|
||||
ascii_art_data = try ascii_file.readToEndAlloc(allocator, std.math.maxInt(usize));
|
||||
const file_size = (try ascii_file.stat()).size;
|
||||
ascii_art_data = try utils.readFile(allocator, ascii_file, file_size);
|
||||
} else {
|
||||
ascii_art_data = @embedFile("./assets/ascii/guy_fawks.txt");
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const ascii = @import("ascii.zig");
|
||||
const utils = @import("utils.zig");
|
||||
|
||||
pub const Module = struct {
|
||||
type: []u8,
|
||||
@@ -10,6 +10,7 @@ pub const Module = struct {
|
||||
|
||||
pub const Config = struct {
|
||||
ascii_abs_path: ?[]u8 = null,
|
||||
username_hostname_color: ?[]u8 = null,
|
||||
modules: []Module,
|
||||
};
|
||||
|
||||
@@ -25,13 +26,22 @@ pub const ModuleType = enum {
|
||||
swap,
|
||||
disk,
|
||||
net,
|
||||
wm,
|
||||
terminal,
|
||||
locale,
|
||||
custom,
|
||||
};
|
||||
|
||||
pub fn getAsciiPath(config: ?std.json.Parsed(Config)) ?[]u8 {
|
||||
return config.?.value.ascii_abs_path;
|
||||
if (config) |c| {
|
||||
return c.value.ascii_abs_path;
|
||||
} else return null;
|
||||
}
|
||||
|
||||
pub fn getUsernameHostnameColor(config: ?std.json.Parsed(Config)) ?[]u8 {
|
||||
if (config) |c| {
|
||||
return c.value.username_hostname_color;
|
||||
} else return null;
|
||||
}
|
||||
|
||||
pub fn getModulesTypes(allocator: std.mem.Allocator, config: ?std.json.Parsed(Config)) !std.array_list.Managed(ModuleType) {
|
||||
@@ -43,6 +53,7 @@ pub fn getModulesTypes(allocator: std.mem.Allocator, config: ?std.json.Parsed(Co
|
||||
if (module_enum) |m| {
|
||||
try modules_list.append(m);
|
||||
} else {
|
||||
modules_list.deinit();
|
||||
return error.InvalidModule;
|
||||
}
|
||||
}
|
||||
@@ -58,14 +69,16 @@ pub fn readConfigFile(allocator: std.mem.Allocator) !?std.json.Parsed(Config) {
|
||||
const config_abs_path = try std.mem.concat(allocator, u8, &.{ home, "/.config/zigfetch/config.json" });
|
||||
defer allocator.free(config_abs_path);
|
||||
|
||||
const file = std.fs.openFileAbsolute(config_abs_path, .{ .mode = .read_only }) catch |err| switch (err) {
|
||||
const config_file = std.fs.openFileAbsolute(config_abs_path, .{ .mode = .read_only }) catch |err| switch (err) {
|
||||
error.FileNotFound => return null,
|
||||
else => return err,
|
||||
};
|
||||
defer file.close();
|
||||
defer config_file.close();
|
||||
|
||||
const data = try file.readToEndAlloc(allocator, std.math.maxInt(usize));
|
||||
defer allocator.free(data);
|
||||
const file_size = (try config_file.stat()).size;
|
||||
|
||||
return try std.json.parseFromSlice(Config, allocator, data, .{ .allocate = .alloc_always });
|
||||
const config_data = try utils.readFile(allocator, config_file, file_size);
|
||||
defer allocator.free(config_data);
|
||||
|
||||
return try std.json.parseFromSlice(Config, allocator, config_data, .{ .allocate = .alloc_always });
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ pub const formatters = [_]*const fn (allocator: std.mem.Allocator, key: []const
|
||||
&getFormattedSwapInfo,
|
||||
&getFormattedDiskInfo,
|
||||
&getFormattedNetInfo,
|
||||
&getFormattedWindowManagerInfo,
|
||||
&getFormattedTerminalNameInfo,
|
||||
&getFormattedLocaleInfo,
|
||||
&getFormattedCustom,
|
||||
@@ -37,10 +38,22 @@ pub const default_formatters = [_]*const fn (allocator: std.mem.Allocator) anyer
|
||||
&getDefaultFormattedSwapInfo,
|
||||
&getDefaultFormattedDiskInfo,
|
||||
&getDefaultFormattedNetInfo,
|
||||
&getDefaultFormattedWindowManagerInfo,
|
||||
&getDefaultFormattedTerminalNameInfo,
|
||||
&getDefaultFormattedLocaleInfo,
|
||||
};
|
||||
|
||||
pub fn getFormattedUsernameHostname(allocator: std.mem.Allocator, color: []const u8, username: []const u8, hostname: []const u8) ![]u8 {
|
||||
return try std.fmt.allocPrint(allocator, "{s}{s}{s}@{s}{s}{s}", .{
|
||||
color,
|
||||
username,
|
||||
ascii.Reset,
|
||||
color,
|
||||
hostname,
|
||||
ascii.Reset,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn getDefaultFormattedKernelInfo(allocator: std.mem.Allocator) !Result {
|
||||
return try getFormattedKernelInfo(allocator, "Kernel", ascii.Yellow);
|
||||
}
|
||||
@@ -181,6 +194,16 @@ pub fn getFormattedDiskInfo(allocator: std.mem.Allocator, key: []const u8, key_c
|
||||
return Result{ .string = try std.fmt.allocPrint(allocator, "{s}{s} ({s}):{s} {d:.2} / {d:.2} GB ({}%)", .{ key_color, key, disk_info.disk_path, ascii.Reset, disk_info.disk_usage, disk_info.disk_size, disk_info.disk_usage_percentage }) };
|
||||
}
|
||||
|
||||
pub fn getDefaultFormattedWindowManagerInfo(allocator: std.mem.Allocator) !Result {
|
||||
return try getFormattedWindowManagerInfo(allocator, "WM", ascii.Yellow);
|
||||
}
|
||||
|
||||
pub fn getFormattedWindowManagerInfo(allocator: std.mem.Allocator, key: []const u8, key_color: []const u8) !Result {
|
||||
const wm = try detection.system.getWindowManagerInfo(allocator);
|
||||
defer allocator.free(wm);
|
||||
return Result{ .string = try std.fmt.allocPrint(allocator, "{s}{s}:{s} {s}", .{ key_color, key, ascii.Reset, wm }) };
|
||||
}
|
||||
|
||||
pub fn getDefaultFormattedTerminalNameInfo(allocator: std.mem.Allocator) !Result {
|
||||
return try getFormattedTerminalNameInfo(allocator, "Terminal", ascii.Yellow);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const std = @import("std");
|
||||
const utils = @import("../utils.zig");
|
||||
const c_unistd = @cImport(@cInclude("unistd.h"));
|
||||
const c_statvfs = @cImport(@cInclude("sys/statvfs.h"));
|
||||
const c_libpci = @cImport(@cInclude("pci/pci.h"));
|
||||
@@ -44,9 +45,16 @@ pub fn getCpuInfo(allocator: std.mem.Allocator) !CpuInfo {
|
||||
|
||||
// Reads /proc/cpuinfo
|
||||
const cpuinfo_path = "/proc/cpuinfo";
|
||||
var file = try std.fs.cwd().openFile(cpuinfo_path, .{});
|
||||
defer file.close();
|
||||
const cpuinfo_data = try file.readToEndAlloc(allocator, std.math.maxInt(usize));
|
||||
const cpuinfo_file = try std.fs.cwd().openFile(cpuinfo_path, .{ .mode = .read_only });
|
||||
defer cpuinfo_file.close();
|
||||
|
||||
// NOTE: procfs is a pseudo-filesystem, so it is not possible to determine the size of a file
|
||||
// https://docs.kernel.org/filesystems/proc.html
|
||||
// https://en.wikipedia.org/wiki/Procfs
|
||||
//
|
||||
// Only the first section (core 0) will be parsed
|
||||
// 512 is more than enough
|
||||
const cpuinfo_data = try utils.readFile(allocator, cpuinfo_file, 512);
|
||||
defer allocator.free(cpuinfo_data);
|
||||
|
||||
// Parsing /proc/cpuinfo
|
||||
@@ -77,6 +85,7 @@ pub fn getCpuInfo(allocator: std.mem.Allocator) !CpuInfo {
|
||||
|
||||
var cpu_max_freq: f32 = 0.0;
|
||||
|
||||
// NOTE: this is the preferred approach beacause it is the most accurate
|
||||
const cpuinfo_max_freq_path = "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq";
|
||||
var cmf_exists: bool = true;
|
||||
|
||||
@@ -89,14 +98,13 @@ pub fn getCpuInfo(allocator: std.mem.Allocator) !CpuInfo {
|
||||
|
||||
if (cmf_exists) {
|
||||
// Reads /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq
|
||||
var file2 = try std.fs.cwd().openFile(cpuinfo_max_freq_path, .{});
|
||||
|
||||
defer file2.close();
|
||||
const cpuinfo_max_freq_data = try file2.readToEndAlloc(allocator, std.math.maxInt(usize));
|
||||
defer allocator.free(cpuinfo_max_freq_data);
|
||||
const maxfreq_file = try std.fs.cwd().openFile(cpuinfo_max_freq_path, .{ .mode = .read_only });
|
||||
defer maxfreq_file.close();
|
||||
const maxfreq_data = try utils.readFile(allocator, maxfreq_file, 32);
|
||||
defer allocator.free(maxfreq_data);
|
||||
|
||||
// Parsing /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq
|
||||
const trimmed = std.mem.trim(u8, cpuinfo_max_freq_data, " \n\r");
|
||||
const trimmed = std.mem.trim(u8, maxfreq_data, " \n\r");
|
||||
const cpu_max_freq_khz: f32 = try std.fmt.parseFloat(f32, trimmed);
|
||||
cpu_max_freq = cpu_max_freq_khz / 1_000_000;
|
||||
} else {
|
||||
@@ -203,9 +211,16 @@ fn parseGpuName(allocator: std.mem.Allocator, name: []u8) !?[]u8 {
|
||||
pub fn getRamInfo(allocator: std.mem.Allocator) !RamInfo {
|
||||
// Reads /proc/meminfo
|
||||
const meminfo_path = "/proc/meminfo";
|
||||
const file = try std.fs.cwd().openFile(meminfo_path, .{});
|
||||
defer file.close();
|
||||
const meminfo_data = try file.readToEndAlloc(allocator, std.math.maxInt(usize));
|
||||
const meminfo_file = try std.fs.cwd().openFile(meminfo_path, .{ .mode = .read_only });
|
||||
defer meminfo_file.close();
|
||||
|
||||
// NOTE: procfs is a pseudo-filesystem, so it is not possible to determine the size of a file
|
||||
// https://docs.kernel.org/filesystems/proc.html
|
||||
// https://en.wikipedia.org/wiki/Procfs
|
||||
//
|
||||
// We only need to read the first few lines
|
||||
// 512 is more than enough
|
||||
const meminfo_data = try utils.readFile(allocator, meminfo_file, 512);
|
||||
defer allocator.free(meminfo_data);
|
||||
|
||||
// Parsing /proc/meminfo
|
||||
@@ -265,9 +280,16 @@ pub fn getRamInfo(allocator: std.mem.Allocator) !RamInfo {
|
||||
pub fn getSwapInfo(allocator: std.mem.Allocator) !?SwapInfo {
|
||||
// Reads /proc/meminfo
|
||||
const meminfo_path = "/proc/meminfo";
|
||||
const file = try std.fs.cwd().openFile(meminfo_path, .{});
|
||||
defer file.close();
|
||||
const meminfo_data = try file.readToEndAlloc(allocator, std.math.maxInt(usize));
|
||||
const meminfo_file = try std.fs.cwd().openFile(meminfo_path, .{ .mode = .read_only });
|
||||
defer meminfo_file.close();
|
||||
|
||||
// NOTE: procfs is a pseudo-filesystem, so it is not possible to determine the size of a file
|
||||
// https://docs.kernel.org/filesystems/proc.html
|
||||
// https://en.wikipedia.org/wiki/Procfs
|
||||
//
|
||||
// We only need to read the first few lines
|
||||
// 512 is ok
|
||||
const meminfo_data = try utils.readFile(allocator, meminfo_file, 512);
|
||||
defer allocator.free(meminfo_data);
|
||||
|
||||
// Parsing /proc/meminfo
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const std = @import("std");
|
||||
const utils = @import("../utils.zig");
|
||||
const c_sysinfo = @cImport(@cInclude("sys/sysinfo.h"));
|
||||
const c_utsname = @cImport(@cInclude("sys/utsname.h"));
|
||||
|
||||
@@ -77,9 +78,10 @@ pub fn getKernelInfo(allocator: std.mem.Allocator) !KernelInfo {
|
||||
|
||||
pub fn getOsInfo(allocator: std.mem.Allocator) ![]u8 {
|
||||
const os_release_path = "/etc/os-release";
|
||||
const file = try std.fs.cwd().openFile(os_release_path, .{});
|
||||
defer file.close();
|
||||
const os_release_data = try file.readToEndAlloc(allocator, std.math.maxInt(usize));
|
||||
const os_release_file = try std.fs.cwd().openFile(os_release_path, .{ .mode = .read_only });
|
||||
defer os_release_file.close();
|
||||
const size = (try os_release_file.stat()).size;
|
||||
const os_release_data = try utils.readFile(allocator, os_release_file, size);
|
||||
defer allocator.free(os_release_data);
|
||||
|
||||
var pretty_name: ?[]const u8 = null;
|
||||
@@ -98,3 +100,58 @@ pub fn getOsInfo(allocator: std.mem.Allocator) ![]u8 {
|
||||
|
||||
return try allocator.dupe(u8, pretty_name orelse "Unknown");
|
||||
}
|
||||
|
||||
pub fn getWindowManagerInfo(allocator: std.mem.Allocator) ![]const u8 {
|
||||
var dir = try std.fs.cwd().openDir("/proc/", .{ .iterate = true });
|
||||
defer dir.close();
|
||||
|
||||
var wm_name: ?[]const u8 = null;
|
||||
|
||||
var iter = dir.iterate();
|
||||
wm_name = outer: {
|
||||
while (try iter.next()) |entry| {
|
||||
if (entry.kind != .directory) continue;
|
||||
|
||||
// Check if the entry name is numeric
|
||||
_ = std.fmt.parseInt(i32, entry.name, 10) catch continue;
|
||||
|
||||
var buf: [1024]u8 = undefined;
|
||||
const file_name = try std.fmt.bufPrint(&buf, "/proc/{s}/comm", .{entry.name});
|
||||
const file = try std.fs.cwd().openFile(file_name, .{ .mode = .read_only });
|
||||
defer file.close();
|
||||
|
||||
// NOTE: https://stackoverflow.com/questions/23534263/what-is-the-maximum-allowed-limit-on-the-length-of-a-process-name
|
||||
var file_buf: [16]u8 = undefined;
|
||||
var reader = std.fs.File.Reader.init(file, &file_buf);
|
||||
const read = try reader.read(&file_buf);
|
||||
const proc_name = file_buf[0..read];
|
||||
|
||||
const proc_name_trimmed = std.mem.trim(u8, proc_name, "\n");
|
||||
|
||||
const supported_wms: [9][]const u8 = .{
|
||||
"i3", // https://i3wm.org/
|
||||
// "i3gaps", // TODO: find a way to recognize i3gaps
|
||||
"sway", // https://swaywm.org/
|
||||
// "swayfx", // TODO: find a way to recognize swayfx
|
||||
"niri", // https://github.com/YaLTeR/niri
|
||||
"dwm", // https://dwm.suckless.org/
|
||||
// "qtile", // TODO: find a way to recognize qtile
|
||||
"awesome", // https://awesomewm.org/
|
||||
"river", // https://codeberg.org/river/river
|
||||
"hyprland", // https://hypr.land/
|
||||
"bspwm", // https://github.com/baskerville/bspwm
|
||||
"openbox", // https://openbox.org/
|
||||
};
|
||||
|
||||
inline for (supported_wms) |wm| {
|
||||
if (std.ascii.eqlIgnoreCase(wm, proc_name_trimmed)) {
|
||||
break :outer try allocator.dupe(u8, proc_name_trimmed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break :outer null;
|
||||
};
|
||||
|
||||
return wm_name orelse allocator.dupe(u8, "Unknown");
|
||||
}
|
||||
|
||||
@@ -128,3 +128,68 @@ pub fn getOsInfo(allocator: std.mem.Allocator) ![]u8 {
|
||||
|
||||
return os_info;
|
||||
}
|
||||
|
||||
pub fn getWindowManagerInfo(allocator: std.mem.Allocator) ![]const u8 {
|
||||
var name = [_]c_int{ c_sysctl.CTL_KERN, c_sysctl.KERN_PROC, c_sysctl.KERN_PROC_ALL };
|
||||
var size: usize = 0;
|
||||
|
||||
// First call to get the dimension
|
||||
if (c_sysctl.sysctl(&name, name.len, null, &size, null, 0) != 0) {
|
||||
return error.SysctlFailed;
|
||||
}
|
||||
|
||||
const buffer: []u8 = try allocator.alloc(u8, size);
|
||||
defer allocator.free(buffer);
|
||||
|
||||
// Second call to retrieve process data
|
||||
if (c_sysctl.sysctl(&name, name.len, buffer.ptr, &size, null, 0) != 0) {
|
||||
return error.SysctlFailed;
|
||||
}
|
||||
|
||||
// Ensure the buffer size is valid
|
||||
if (size % @sizeOf(c_sysctl.struct_kinfo_proc) != 0) {
|
||||
return error.InvalidBufferSize;
|
||||
}
|
||||
|
||||
const kinfo_list = std.mem.bytesAsSlice(c_sysctl.struct_kinfo_proc, buffer);
|
||||
|
||||
var wm_name: ?[]const u8 = null;
|
||||
|
||||
const supported_wms: [6][]const u8 = .{
|
||||
"aerospace",
|
||||
"amethyst",
|
||||
"chunkwm",
|
||||
"rectangle",
|
||||
"spectacle",
|
||||
"yabai",
|
||||
};
|
||||
|
||||
wm_name = outer: {
|
||||
for (kinfo_list) |kinfo| {
|
||||
const pid = kinfo.kp_proc.p_pid;
|
||||
if (pid <= 0) continue;
|
||||
|
||||
// Gets the process pathname
|
||||
var pathbuf: [c_libproc.PROC_PIDPATHINFO_MAXSIZE]u8 = undefined;
|
||||
// c_libproc.proc_pidpath saves the process name in `pathbuf` and returns the len
|
||||
const path_len = @as(usize, @intCast(c_libproc.proc_pidpath(pid, &pathbuf, pathbuf.len)));
|
||||
const proc_pathname = if (path_len > 0) try allocator.dupe(u8, pathbuf[0..@intCast(path_len)]) else try allocator.dupe(u8, "unknown");
|
||||
defer allocator.free(proc_pathname);
|
||||
|
||||
inline for (supported_wms) |wm| {
|
||||
if (std.ascii.endsWithIgnoreCase(proc_pathname, wm)) {
|
||||
const basename = if (std.mem.lastIndexOfScalar(u8, proc_pathname, '/')) |index|
|
||||
proc_pathname[index + 1 ..]
|
||||
else
|
||||
proc_pathname;
|
||||
|
||||
break :outer try allocator.dupe(u8, basename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break :outer null;
|
||||
};
|
||||
|
||||
return wm_name orelse allocator.dupe(u8, "Quartz Compositor");
|
||||
}
|
||||
|
||||
17
src/main.zig
17
src/main.zig
@@ -27,14 +27,15 @@ pub fn main() !void {
|
||||
|
||||
const username = try detection.user.getUsername(allocator);
|
||||
const hostname = try detection.system.getHostname(allocator);
|
||||
try modules_list.append(try std.fmt.allocPrint(allocator, "{s}{s}{s}@{s}{s}{s}", .{
|
||||
ascii.Yellow,
|
||||
username,
|
||||
ascii.Reset,
|
||||
ascii.Yellow,
|
||||
hostname,
|
||||
ascii.Reset,
|
||||
}));
|
||||
|
||||
const username_hostname_color = if (config.getUsernameHostnameColor(conf)) |color| blk: {
|
||||
var buf: [32]u8 = undefined;
|
||||
const rgb = try ascii.hexColorToRgb(color);
|
||||
const formatted_color = try std.fmt.bufPrint(&buf, "\x1b[38;2;{d};{d};{d}m", .{ rgb.r, rgb.g, rgb.b });
|
||||
break :blk formatted_color;
|
||||
} else ascii.Yellow;
|
||||
|
||||
try modules_list.append(try formatters.getFormattedUsernameHostname(allocator, username_hostname_color, username, hostname));
|
||||
allocator.free(hostname);
|
||||
allocator.free(username);
|
||||
|
||||
|
||||
@@ -114,3 +114,15 @@ test "getLongestAsciiArtRowLen" {
|
||||
|
||||
try std.testing.expectEqual(40, try getLongestAsciiArtRowLen(rows[0..]));
|
||||
}
|
||||
|
||||
pub fn readFile(allocator: std.mem.Allocator, file: std.fs.File, size: usize) ![]const u8 {
|
||||
var file_buf = try allocator.alloc(u8, size);
|
||||
defer allocator.free(file_buf);
|
||||
|
||||
var reader = std.fs.File.Reader.init(file, file_buf);
|
||||
const read = try reader.read(file_buf);
|
||||
|
||||
const data = file_buf[0..read];
|
||||
|
||||
return allocator.dupe(u8, data);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user