Thank you for contributing to KKFetch. This guide covers local development, testing, adding new system modules, and contributing distribution logos.
KKFetch is maintained by Kushagra Kumar (kk376).
- Rust Edition 2024 / Rust 1.85.0 or later (standard toolchain via
rustup) - Standard C library headers (
libc) - Optional packaging utilities:
cargo-deb,cargo-generate-rpm,zstd
git clone https://github.com/kk376/kkfetch.git
cd kkfetch
cargo buildRun KKFetch locally:
cargo run -- --logo ferrisAll pull requests must pass formatting, linter, and test checks without warnings.
-
Check formatting:
cargo fmt --check
Apply automatic formatting with
cargo fmt. -
Run Clippy linter:
cargo clippy --all-targets --all-features -- -D warnings
-
Run the test suite:
cargo test --all-targets --all-features
Modules collect and format a specific piece of system information.
Create src/modules/<module_name>.rs and implement the Collector trait:
use crate::context::FetchContext;
use crate::modules::{Collector, ModuleId, ModuleOutput};
pub struct MyModuleCollector;
impl Collector for MyModuleCollector {
fn id(&self) -> ModuleId {
ModuleId::MyModule
}
fn collect(&self, _ctx: &FetchContext) -> Option<ModuleOutput> {
let value = detect_my_metric()?;
Some(ModuleOutput {
id: self.id(),
label: "My Metric".to_string(),
value,
custom_rendered: None,
})
}
}
pub fn detect_my_metric() -> Option<String> {
// Read from /proc or /sys directly without spawning child processes.
// Return None if the data is unavailable or unreadable.
std::fs::read_to_string("/sys/class/power_supply/BAT0/capacity")
.ok()
.map(|s| format!("{}%", s.trim()))
}- Add
pub mod <module_name>; - Add the variant to
ModuleIdenum. - Update
ModuleId::all(),ModuleId::as_str(), andFromStrimplementations. - Register the collector instance inside
ModuleRegistry::new().
Include unit tests in src/modules/<module_name>.rs to test edge cases, missing files, or corrupted string parsing. Add mock fixtures in tests/parser_tests.rs if testing against synthetic procfs/sysfs data.
KKFetch contains compact ASCII art logos for Linux distributions.
- Dimensions: Keep logos compact (typically 4 to 8 lines high, under 25 columns wide) so they fit comfortably next to module text on 80-column terminals.
- Escape sequences: Use raw strings without embedded ANSI codes in
raw_lines. Colors are applied dynamically viaprimary_color.
Append the new Logo definition to ALL_LOGOS:
Logo {
name: "mydistro",
raw_lines: &[
" /\\___/\\",
" ( o o )",
" ( =^= )",
" (---)",
],
primary_color: "\x1b[38;5;39m",
},Map distro IDs and aliases (matching /etc/os-release ID and ID_LIKE values):
"mydistro" | "mydistro-linux" => logos.iter().find(|l| l.name == "mydistro"),Add test coverage in src/output/logo.rs verifying that match_logo resolves your new identifier.
- Zero shell subprocesses: Always query metrics via
/proc,/sys, environment variables, or standardlibcinterfaces. Spawning subprocesses (sh,bash, or external CLI binaries) slows down execution and introduces unnecessary runtime dependencies. - No panics: System metrics must never cause a crash. Use
Option,Result, and defensive parsing. If a file does not exist or has an unexpected format, returnNoneor an empty string so the module can be omitted gracefully. - Minimal allocations: Avoid redundant string clones and intermediate buffers in tight parsing loops.
- ANSI width awareness: If modifying layouts, calculate visible terminal widths by stripping ANSI sequences rather than using raw byte lengths.
- Fork the repository and create a descriptive branch:
git checkout -b feature/battery-moduleorgit checkout -b fix/arch-logo-alignment. - Ensure
cargo fmt --check,cargo clippy --all-targets --all-features -- -D warnings, andcargo testpass cleanly. - Submit a pull request filling in the pull request template with a brief description of the change and how it was verified.