Compare commits
31 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 |
8
.github/workflows/build.yml
vendored
8
.github/workflows/build.yml
vendored
@@ -65,17 +65,11 @@ jobs:
|
|||||||
ls -la zig-out/bin/
|
ls -la zig-out/bin/
|
||||||
file zig-out/bin/zigfetch-${{ matrix.target }}
|
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
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: zigfetch-${{ matrix.target }}
|
name: zigfetch-${{ matrix.target }}
|
||||||
path: |
|
path: zig-out/bin/zigfetch-${{ matrix.target }}
|
||||||
# zig-out/bin/zigfetch-${{ matrix.target }}
|
|
||||||
zigfetch-${{ matrix.target }}.tar.gz
|
|
||||||
retention-days: 3
|
retention-days: 3
|
||||||
|
|
||||||
test:
|
test:
|
||||||
|
|||||||
84
README.md
84
README.md
@@ -2,10 +2,15 @@
|
|||||||
|
|
||||||

|

|
||||||

|

|
||||||
|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
|
| Default config | Custom config |
|
||||||
|
| :-----------------------------------------------------: | :---------------------------------------------------: |
|
||||||
|
|  |  |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
- [Description](#description)
|
- [Description](#description)
|
||||||
@@ -74,6 +79,85 @@ $ touch config.json
|
|||||||
$ cp /path/to/zigfetch/config.json ~/.config/zigfetch/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
|
## Roadtrip
|
||||||
|
|
||||||
- [ ] Add ASCII art for each operating system and Linux distro
|
- [ ] 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/).
|
// This is a [Semantic Version](https://semver.org/).
|
||||||
// In a future version of Zig it will be used for package deduplication.
|
// In a future version of Zig it will be used for package deduplication.
|
||||||
.version = "0.22.0",
|
.version = "0.24.0",
|
||||||
|
|
||||||
// Together with name, this represents a globally unique package
|
// Together with name, this represents a globally unique package
|
||||||
// identifier. This field is generated by the Zig toolchain when the
|
// 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;
|
var ascii_art_data: []const u8 = undefined;
|
||||||
if (ascii_art_path) |ascii| {
|
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();
|
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 {
|
} else {
|
||||||
ascii_art_data = @embedFile("./assets/ascii/guy_fawks.txt");
|
ascii_art_data = @embedFile("./assets/ascii/guy_fawks.txt");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const ascii = @import("ascii.zig");
|
const ascii = @import("ascii.zig");
|
||||||
|
const utils = @import("utils.zig");
|
||||||
|
|
||||||
pub const Module = struct {
|
pub const Module = struct {
|
||||||
type: []u8,
|
type: []u8,
|
||||||
@@ -25,6 +26,7 @@ pub const ModuleType = enum {
|
|||||||
swap,
|
swap,
|
||||||
disk,
|
disk,
|
||||||
net,
|
net,
|
||||||
|
wm,
|
||||||
terminal,
|
terminal,
|
||||||
locale,
|
locale,
|
||||||
custom,
|
custom,
|
||||||
@@ -51,6 +53,7 @@ pub fn getModulesTypes(allocator: std.mem.Allocator, config: ?std.json.Parsed(Co
|
|||||||
if (module_enum) |m| {
|
if (module_enum) |m| {
|
||||||
try modules_list.append(m);
|
try modules_list.append(m);
|
||||||
} else {
|
} else {
|
||||||
|
modules_list.deinit();
|
||||||
return error.InvalidModule;
|
return error.InvalidModule;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,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" });
|
const config_abs_path = try std.mem.concat(allocator, u8, &.{ home, "/.config/zigfetch/config.json" });
|
||||||
defer allocator.free(config_abs_path);
|
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,
|
error.FileNotFound => return null,
|
||||||
else => return err,
|
else => return err,
|
||||||
};
|
};
|
||||||
defer file.close();
|
defer config_file.close();
|
||||||
|
|
||||||
const data = try file.readToEndAlloc(allocator, std.math.maxInt(usize));
|
const file_size = (try config_file.stat()).size;
|
||||||
defer allocator.free(data);
|
|
||||||
|
|
||||||
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,
|
&getFormattedSwapInfo,
|
||||||
&getFormattedDiskInfo,
|
&getFormattedDiskInfo,
|
||||||
&getFormattedNetInfo,
|
&getFormattedNetInfo,
|
||||||
|
&getFormattedWindowManagerInfo,
|
||||||
&getFormattedTerminalNameInfo,
|
&getFormattedTerminalNameInfo,
|
||||||
&getFormattedLocaleInfo,
|
&getFormattedLocaleInfo,
|
||||||
&getFormattedCustom,
|
&getFormattedCustom,
|
||||||
@@ -37,6 +38,7 @@ pub const default_formatters = [_]*const fn (allocator: std.mem.Allocator) anyer
|
|||||||
&getDefaultFormattedSwapInfo,
|
&getDefaultFormattedSwapInfo,
|
||||||
&getDefaultFormattedDiskInfo,
|
&getDefaultFormattedDiskInfo,
|
||||||
&getDefaultFormattedNetInfo,
|
&getDefaultFormattedNetInfo,
|
||||||
|
&getDefaultFormattedWindowManagerInfo,
|
||||||
&getDefaultFormattedTerminalNameInfo,
|
&getDefaultFormattedTerminalNameInfo,
|
||||||
&getDefaultFormattedLocaleInfo,
|
&getDefaultFormattedLocaleInfo,
|
||||||
};
|
};
|
||||||
@@ -192,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 }) };
|
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 {
|
pub fn getDefaultFormattedTerminalNameInfo(allocator: std.mem.Allocator) !Result {
|
||||||
return try getFormattedTerminalNameInfo(allocator, "Terminal", ascii.Yellow);
|
return try getFormattedTerminalNameInfo(allocator, "Terminal", ascii.Yellow);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const utils = @import("../utils.zig");
|
||||||
const c_unistd = @cImport(@cInclude("unistd.h"));
|
const c_unistd = @cImport(@cInclude("unistd.h"));
|
||||||
const c_statvfs = @cImport(@cInclude("sys/statvfs.h"));
|
const c_statvfs = @cImport(@cInclude("sys/statvfs.h"));
|
||||||
const c_libpci = @cImport(@cInclude("pci/pci.h"));
|
const c_libpci = @cImport(@cInclude("pci/pci.h"));
|
||||||
@@ -44,9 +45,16 @@ pub fn getCpuInfo(allocator: std.mem.Allocator) !CpuInfo {
|
|||||||
|
|
||||||
// Reads /proc/cpuinfo
|
// Reads /proc/cpuinfo
|
||||||
const cpuinfo_path = "/proc/cpuinfo";
|
const cpuinfo_path = "/proc/cpuinfo";
|
||||||
var file = try std.fs.cwd().openFile(cpuinfo_path, .{});
|
const cpuinfo_file = try std.fs.cwd().openFile(cpuinfo_path, .{ .mode = .read_only });
|
||||||
defer file.close();
|
defer cpuinfo_file.close();
|
||||||
const cpuinfo_data = try file.readToEndAlloc(allocator, std.math.maxInt(usize));
|
|
||||||
|
// 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);
|
defer allocator.free(cpuinfo_data);
|
||||||
|
|
||||||
// Parsing /proc/cpuinfo
|
// Parsing /proc/cpuinfo
|
||||||
@@ -77,6 +85,7 @@ pub fn getCpuInfo(allocator: std.mem.Allocator) !CpuInfo {
|
|||||||
|
|
||||||
var cpu_max_freq: f32 = 0.0;
|
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";
|
const cpuinfo_max_freq_path = "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq";
|
||||||
var cmf_exists: bool = true;
|
var cmf_exists: bool = true;
|
||||||
|
|
||||||
@@ -89,14 +98,13 @@ pub fn getCpuInfo(allocator: std.mem.Allocator) !CpuInfo {
|
|||||||
|
|
||||||
if (cmf_exists) {
|
if (cmf_exists) {
|
||||||
// Reads /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq
|
// Reads /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq
|
||||||
var file2 = try std.fs.cwd().openFile(cpuinfo_max_freq_path, .{});
|
const maxfreq_file = try std.fs.cwd().openFile(cpuinfo_max_freq_path, .{ .mode = .read_only });
|
||||||
|
defer maxfreq_file.close();
|
||||||
defer file2.close();
|
const maxfreq_data = try utils.readFile(allocator, maxfreq_file, 32);
|
||||||
const cpuinfo_max_freq_data = try file2.readToEndAlloc(allocator, std.math.maxInt(usize));
|
defer allocator.free(maxfreq_data);
|
||||||
defer allocator.free(cpuinfo_max_freq_data);
|
|
||||||
|
|
||||||
// Parsing /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq
|
// 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);
|
const cpu_max_freq_khz: f32 = try std.fmt.parseFloat(f32, trimmed);
|
||||||
cpu_max_freq = cpu_max_freq_khz / 1_000_000;
|
cpu_max_freq = cpu_max_freq_khz / 1_000_000;
|
||||||
} else {
|
} else {
|
||||||
@@ -203,9 +211,16 @@ fn parseGpuName(allocator: std.mem.Allocator, name: []u8) !?[]u8 {
|
|||||||
pub fn getRamInfo(allocator: std.mem.Allocator) !RamInfo {
|
pub fn getRamInfo(allocator: std.mem.Allocator) !RamInfo {
|
||||||
// Reads /proc/meminfo
|
// Reads /proc/meminfo
|
||||||
const meminfo_path = "/proc/meminfo";
|
const meminfo_path = "/proc/meminfo";
|
||||||
const file = try std.fs.cwd().openFile(meminfo_path, .{});
|
const meminfo_file = try std.fs.cwd().openFile(meminfo_path, .{ .mode = .read_only });
|
||||||
defer file.close();
|
defer meminfo_file.close();
|
||||||
const meminfo_data = try file.readToEndAlloc(allocator, std.math.maxInt(usize));
|
|
||||||
|
// 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);
|
defer allocator.free(meminfo_data);
|
||||||
|
|
||||||
// Parsing /proc/meminfo
|
// Parsing /proc/meminfo
|
||||||
@@ -265,9 +280,16 @@ pub fn getRamInfo(allocator: std.mem.Allocator) !RamInfo {
|
|||||||
pub fn getSwapInfo(allocator: std.mem.Allocator) !?SwapInfo {
|
pub fn getSwapInfo(allocator: std.mem.Allocator) !?SwapInfo {
|
||||||
// Reads /proc/meminfo
|
// Reads /proc/meminfo
|
||||||
const meminfo_path = "/proc/meminfo";
|
const meminfo_path = "/proc/meminfo";
|
||||||
const file = try std.fs.cwd().openFile(meminfo_path, .{});
|
const meminfo_file = try std.fs.cwd().openFile(meminfo_path, .{ .mode = .read_only });
|
||||||
defer file.close();
|
defer meminfo_file.close();
|
||||||
const meminfo_data = try file.readToEndAlloc(allocator, std.math.maxInt(usize));
|
|
||||||
|
// 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);
|
defer allocator.free(meminfo_data);
|
||||||
|
|
||||||
// Parsing /proc/meminfo
|
// Parsing /proc/meminfo
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const utils = @import("../utils.zig");
|
||||||
const c_sysinfo = @cImport(@cInclude("sys/sysinfo.h"));
|
const c_sysinfo = @cImport(@cInclude("sys/sysinfo.h"));
|
||||||
const c_utsname = @cImport(@cInclude("sys/utsname.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 {
|
pub fn getOsInfo(allocator: std.mem.Allocator) ![]u8 {
|
||||||
const os_release_path = "/etc/os-release";
|
const os_release_path = "/etc/os-release";
|
||||||
const file = try std.fs.cwd().openFile(os_release_path, .{});
|
const os_release_file = try std.fs.cwd().openFile(os_release_path, .{ .mode = .read_only });
|
||||||
defer file.close();
|
defer os_release_file.close();
|
||||||
const os_release_data = try file.readToEndAlloc(allocator, std.math.maxInt(usize));
|
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);
|
defer allocator.free(os_release_data);
|
||||||
|
|
||||||
var pretty_name: ?[]const u8 = null;
|
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");
|
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;
|
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");
|
||||||
|
}
|
||||||
|
|||||||
@@ -114,3 +114,15 @@ test "getLongestAsciiArtRowLen" {
|
|||||||
|
|
||||||
try std.testing.expectEqual(40, try getLongestAsciiArtRowLen(rows[0..]));
|
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