Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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.23.0",
|
||||
|
||||
// Together with name, this represents a globally unique package
|
||||
// identifier. This field is generated by the Zig toolchain when the
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const ascii = @import("ascii.zig");
|
||||
|
||||
pub const Module = struct {
|
||||
@@ -10,6 +9,7 @@ pub const Module = struct {
|
||||
|
||||
pub const Config = struct {
|
||||
ascii_abs_path: ?[]u8 = null,
|
||||
username_hostname_color: ?[]u8 = null,
|
||||
modules: []Module,
|
||||
};
|
||||
|
||||
@@ -25,13 +25,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 +52,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -98,3 +98,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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user