- Windows: use FILE_FS_FULL_SIZE_INFORMATION_EX on Windows 10 1809+ (Build >= 17763) when calcType != AVAILABLE to get ActualTotalAllocationUnits/ActualAvailableAllocationUnits (ignoring per-user disk quotas). Fall back to legacy FILE_FS_FULL_SIZE_INFORMATION with CallerAvailableAllocationUnits when calcType is AVAILABLE or EX is unavailable.
- Unix-like: respect --disk-calc-type. Use f_bfree for FREE, f_bavail for AVAILABLE (Linux/BSD/SunOS). Haiku currently always uses free_blocks.
- Refactor FFDisk: remove bytesUsed and bytesAvailable; compute used = total - free in disk module.
- Disk module: update custom format (remove `size-available`, add `bytes-used` and `bytes-total`); update JSON output (remove `bytes.available`, `bytes.used`).
- Disk detection: stop computing used in common path; let each platform set bytesFree by chosen semantics.
Fixes#2651
- Host: "Ana Bilgisayar" -> "Cihaz". The module reports the machine
model; "ana bilgisayar" reads as a mainframe in Turkish.
- Login Manager: "Oturum Açma Yöneticisi" -> "Giriş Yöneticisi".
Shorter, and the common Turkish term.
- Top: "En yoğun işlemler" -> "En Yoğun Süreçler". Title case like the
other Turkish names, and "Süreçler" to match the Processes module.
- Bluetooth Radio: "Bluetooth Radyosu" -> "Bluetooth Adaptörü". "Radyo"
reads as an FM radio; "Adaptör" matches Power Adapter ("Güç Adaptörü").
Related to #2526
Use the previously discussed soc_id which have public values in EDK2.
The so far used toplevel devicetree compatible values weren't as precise
and some logic (x1, x2p, x2e) simply was dead code.
Also drops the CPU test due to reading soc_id sysfs file, could be
adapted if still wanted around.
* Vulkan: fixes driver name concatenation on multi-GPU systems
applyDriverName appended to the result buffer without clearing it. When
a later device reported a higher API version, its driver name was
appended to the name of the earlier device instead of replacing it, as
the comment in detectVulkan intends.
* CHANGELOG: moves the #2615 entry to Unreleased
#2616 was opened after 2.69.0 had been released, but its entry was
written under 2.69.0 Bugfixes, so the changelog listed the fix as part
of 2.69.0.
DDC/CI results never set `builtin`, and FF_LIST_ADD does not zero the new
element, so external monitors were reported as built-in or external at
random. Set it to false, as the BSD DDC/CI backend does.
FF_SUPPRESS_IO() was declared inside the `if (ffddca_init)` block, so its
cleanup restored stdout before display detection ran and libddcutil trace
lines could reach the output, ahead of `--format json` too. Declare it at
function scope so it covers the whole detection, including the
FF_DISABLE_DLOPEN build.
Closes#2615
FreeBSD 16.0-CURRENT's <string.h> now provides C23-style
qualifier-preserving wrappers for the string search functions. Besides
the prototype, `memrchr` (like `memchr`, `strchr`, `strstr`, `memmem`,
...) is also defined as a function-like macro built on `_Generic`:
#define memrchr(b, c, n) __qualsel((b), \
(const void *)(memrchr)((b), (c), (n)), (memrchr)((b), (c), (n)))
`common/memrchr.h` redeclares the function unconditionally. When
<string.h> has already been included, that declaration is expanded by
the macro and every translation unit fails with:
src/common/memrchr.h:11:7: error: expected identifier or '('
11 | void* memrchr(const void* s, int c, size_t n);
A libc that defines `memrchr` as a macro has necessarily declared the
function it wraps, so skip our declaration in that case. Nothing
changes on platforms where `memrchr` is not a macro, and the fallback
implementation is still selected by `check_function_exists`.
/proc/cpuinfo on sparc has none of the fields the generic fallback looks
for, so the module printed "Unknown (64)". The name is in "cpu", and the
frequency in "Cpu<n>ClkTck" -- in Hz, hex on sparc64, decimal on sparc32.
FreeBSD (and other systems that build ImageMagick without encoding the
quantum depth into the library name) install libMagickCore-7.so and
libMagickCore-6.so without a .Q16HDRI / .Q16 suffix. dlopen currently
only tries the suffixed names, so image logos always fall back to ASCII
art with "Image Magick library not found" even when ImageMagick is
installed. Append the plain library names as a last resort.
--key-language with an empty value (and "language": null in the config)
asks for the system locale, not for a specific language. When that locale
has no translation, fastfetch aborted with exit 477 instead of printing
anything, so the same config broke on every locale outside the twelve
supported ones, and under LC_ALL=C variants such as POSIX.
Auto-detected locales now fall back to English. An explicitly requested
language still errors out, so typos and zh are still reported.
359cb0a79a renamed the key from `pt_BR` to
`pt` but kept the exact-match guard, so only the literal string `pt`
matched. Every real Portuguese locale (`pt_BR`, `pt_PT` and their charset
and modifier variants) fell through to `goto error` and aborted.
Return the offset unconditionally, matching every other two-letter case.
The Star History chart was removed in 8df0a1c9 (Fixes#2508) because the previous chart was broken due to GitHub stargazer API restrictions. This restores it at the same location using a working data source that requires no API token, so the chart renders correctly again.
The query array gained a third entry in
dd30c82b83 but numQueries stayed at 2, so
`size =` was never queried and every Alacritty user silently got the
hardcoded 11.25 fallback.
Jobs without a permissions block get the repository's default token
scope, and reusable workflow calls pass the caller's grants straight
through. Scopes are now derived from what each workflow actually does
with the token:
- every build workflow declares contents: read; none of them writes
through the GITHUB_TOKEN.
- build-linux-hosts.yml keeps security-events: write for the CodeQL
upload; the other callers had that grant too but never upload
scanning results, so they drop it.
- build-windows-hosts.yml gets actions: read, which the SignPath
action documents needing to read job details and download the
unsigned artifact.
- build-release.yml declares contents: write, matching the grant its
caller already makes for creating the release.
Runs that execute pull request code now hold a token that can do
nothing but read the repository.
Every reusable workflow call used 'secrets: inherit', which hands the
caller's whole secret set to the called workflow, but the only secret
any of them reads is SIGNPATH_API_TOKEN in build-windows-hosts.yml.
Passing that one secret explicitly and dropping inherit everywhere else
means a compromised step in, say, a BSD build VM has no signing token
to steal, and the workflow files now show exactly which secret flows
where.
The secret is declared optional in the reusable workflow so runs
without it (pull requests, forks) behave as before; the signing step
is already guarded to upstream push events.
A version tag like @v1 or a branch like @master is a movable pointer:
whoever controls the action repository can re-point it, and the next
run executes whatever it points at. Several of these actions run in
jobs whose outputs ship to users: build-release.yml creates the GitHub
release with the downloadable binaries, and build-windows-hosts.yml
holds the SignPath signing token, so a re-pointed tag there could ship
a tampered or wrongly signed release. This is exactly how the
tj-actions/changed-files compromise propagated (CVE-2025-30066).
Pinning by full commit SHA makes the reviewed code the code that runs,
the same way docker/setup-qemu-action is already pinned in
build-linux-vms.yml. Refs that pointed at master (cross-platform-actions,
setup-alpine, get-latest-release) are pinned to their latest release
tag. Every pin keeps a version comment, and each SHA was resolved from
the upstream repository and cross-checked against its release tag.
The minimal (core) installation ships the `ubuntustudio-desktop-core`
metapackage instead of `ubuntustudio-desktop`, so the existing check
missed it and the system was reported as Kubuntu.
Fixes#2485
- Add missing ffStrbufDestroy(&options->outputColor) in ffDestroySeparatorOptions
to prevent memory leak when outputColor is set via JSON config
- Replace two exit(1) calls in ffPreparePublicIp with proper error status
propagation, matching the pattern used in the weather module
- Add missing ffStrbufDestroy(&options->outputColor) in ffDestroySeparatorOptions
to prevent memory leak when outputColor is set via JSON config
- Replace two exit(1) calls in ffPreparePublicIp with proper error status
propagation, matching the pattern used in the weather module
The redundant `if (index < strbuf->length)` check inside the static string
branch is always true since `strbuf->length <= index` is already checked
at the top of the function and returns false. Remove this dead code for clarity.
Co-authored-by: tru3 <tru3@tru3.com>
- Add missing ffStrbufDestroy(&options->location) in ffDestroyWeatherOptions
to prevent memory leak when location is set via config
- Replace exit(1) in ffPrepareWeather with setting status to an error string,
allowing the error to be properly propagated through the existing error mechanism
Co-authored-by: tru3 <tru3@tru3.com>
* CI: add loong64 build workflow
Add reusable workflow for building fastfetch on LoongArch 64-bit
architecture using QEMU user-mode emulation + Docker container
(lcr.loongnix.cn/debian:14). Integrate into CI pipeline and
release dependencies.
* CI (loong64): pin docker/setup-qemu-action to full commit SHA
Pin to 06116385d9baf250c9f4dcb4858b16962ea869c3 (v4.1.0) for
immutable action reference as required by Codacy.
ffBase64EncodeRaw unconditionally byte-swapped the input word via
__builtin_bswap32, which only produces the intended big-endian byte
layout on little-endian hosts. On big-endian hosts the word is already
in the correct order, so the swap corrupted the encoded output.
Guard the swap with __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ so the
encoder is correct on both endiannesses.
* add support for proxmox backup server detection
* Update Proxmox identifiers and pretty names
* Simplify Proxmox logo names in p.inc
---------
Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
* Logo: add chimera2, parabola2_small, postmarketos2, qubes_small
* Logo: add types to chimera2, parabola2_small, postmarketos2, qubes_small, remove "parabola-gnulinux"
* Change logo names to use capital letters
---------
Co-authored-by: v_v <circlepuller@inbox.lv>
Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
* added small chimera linux logo
* Add logo type for Chimera_small
---------
Co-authored-by: Weed <weedygmd>
Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
* Create zerene.txt
* Update z.inc
* Fixed z.inc
Changed the problematic line mismatch
* Update z.inc
* Update z.inc
more fixes to z.inc
* Remove duplicate name entry for Zerene logo
---------
Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
Update the large logo for OpenWrt based on the official branding.
Add a small logo version.
Keep the old logo as openwrt_old.txt
Signed-off-by: Valeriy Kosikhin <vkosikhin@gmail.com>
* [fix]: markdown-link to wiki
* [fix]: fix color at 1 spot
* [fix]: fix color at 1 spot, again
* Revert "[fix]: markdown-link to wiki"
This reverts commit 72f4d11c90.
"Remove unrelated changes"
* Improved terminal name detection for nix packages
* Improved terminal name detection for nix packages
* Update terminalshell_linux.c
Move ffStrbufStartsWithC(&result->processName, '.') before string comparation, as it's much cheaper.
* Logo: Add openRuyi
* Update ASCII art in openruyi.txt
* Fix casing of 'openRuyi' in builtin.c
---------
Co-authored-by: Z572 <z572@z572.online>
Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
* Wallpaper (Haiku): Add support
* Refactor wallpaper detection logic and memory handling
---------
Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
* feat(os): enhance Deepin detection with os-version data
Add a Deepin-specific enhancement in Linux OS detection that reads
`/etc/os-version` for `MinorVersion` and `EditionName`.
When available, it now:
- sets `versionID` to `MinorVersion`
- updates `prettyName` to include version and optional edition
This improves Deepin version accuracy and provides a clearer OS name
than relying solely on generic `os-release` fields.feat(os): enhance Deepin detection with os-version data
Add a Deepin-specific enhancement in Linux OS detection that reads
`/etc/os-version` for `MinorVersion` and `EditionName`.
When available, it now:
- sets `versionID` to `MinorVersion`
- updates `prettyName` to include version and optional edition
This improves Deepin version accuracy and provides a clearer OS name
than relying solely on generic `os-release` fields.
* fix(os): use distro name when formatting Deepin prettyName
Update Deepin enhancement formatting to build `prettyName` from
`result->name` instead of hardcoding "Deepin". This keeps output
consistent with the detected distro name while still appending version
and edition details.fix(os): use distro name when formatting Deepin prettyName
Update Deepin enhancement formatting to build `prettyName` from
`result->name` instead of hardcoding "Deepin". This keeps output
consistent with the detected distro name while still appending version
and edition details.
* fix(os/linux): guard Deepin minor version override
Only apply Deepin’s `minor` value to `versionID` when an edition is
present and `prettyName` does not already include parenthesized details.
This avoids incorrectly overriding parsed version info in enhanced names.fix(os/linux): guard Deepin minor version override
Only apply Deepin’s `minor` value to `versionID` when an edition is
present and `prettyName` does not already include parenthesized details.
This avoids incorrectly overriding parsed version info in enhanced names.
Co-authored-by: Copilot <copilot@github.com>
* Refactor Deepin enhancement detection logic
* Refactor detectDeepinEnhancement function
---------
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
* fix(os): detect Ubuntu Studio before KDE-based flavor checks
Add an explicit Ubuntu Studio detection in `getUbuntuFlavour()` by
checking for `/usr/share/doc/ubuntustudio-desktop` and setting
`name`, `id`, and `idLike` accordingly.
This prevents Ubuntu Studio systems from being misidentified as
Kubuntu when KDE/Plasma-related XDG config paths are present.fix(os): detect Ubuntu Studio before KDE-based flavor checks
Add an explicit Ubuntu Studio detection in `getUbuntuFlavour()` by
checking for `/usr/share/doc/ubuntustudio-desktop` and setting
`name`, `id`, and `idLike` accordingly.
This prevents Ubuntu Studio systems from being misidentified as
Kubuntu when KDE/Plasma-related XDG config paths are present.
* refactor(os): detect Ubuntu Studio via package presence
* Add ASCII logo for KibaOS
* Add KibaOS logo to builtin.c
* Update builtin.c
* Update builtin.c
* Add KibaOS logo to builtin logo configurations
Added KibaOS logo configuration to the logo data structure.
* Fix KibaOS Syntax
* Added support for Redrose.
* Remove 'redrose' OS identification logic
* Remove dollar signs from ASCII art in redrose.txt
* Update logo name from 'redrose' to 'Redrose'
---------
Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
* Logo (Builtin): adds LimeOS logo
Adds support for LimeOS, a Debian-based distribution.
- Adds ASCII logo (white color scheme)
- Adds OS detection for `ID=limeos`
Homepage: https://limeos.org
* Logo (Builtin): adds LimeOS logo
Adds support for LimeOS, a Debian-based distribution.
Homepage: https://limeos.org
* Logo (Builtin): adds LimeOS logo
* Update builtin.c
```
kde-output-device-v2-client-protocol.h:257:9: error: implicit declaration of function 'wl_proxy_marshal_flags'; did you mean 'wl_proxy_marshal_array'? [-Werror=implicit-function-declaration]
257 | wl_proxy_marshal_flags((struct wl_proxy *) kde_output_device_registry_v2,
| ^~~~~~~~~~~~~~~~~~~~~~
| wl_proxy_marshal_array
```
* Logo (Builtin): adds Emmabuntüs Logo
* Add Detection for Emmabuntüs
* Update ASCII art in emmabuntus.txt
* Remove duplicate name for Emmabuntus logo
* Update emmabuntus.txt
* Update colors for Emmabuntus logo
---------
Co-authored-by: zamhedonia <zamhedonia@gmx.de>
Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
* fix: colored inside shackle
* Update ASCII art in secureblue.txt
* Fix formatting in secureblue.txt
---------
Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
* Improves accurancy of detection of drive create time
* Improves performance slightly
* Removes remove drive check, `hideFolders` should be used instead
* Fix Oracle Solaris zpool build
* Add memrchr fallback
* Change to include fron extern
* add new line
* remove ; in zpool.c
* Change wrapper to macro
Also change README.md
* Tweaks
---------
Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
* Add files via upload
* Update builtin.c
* Update builtin.c
* Update builtin.c
* PrismLinux logo update + small variant
* Update ASCII art in prismlinux.txt
* Revise ASCII art in prismlinux_small.txt
Updated ASCII art in prismlinux_small.txt
---------
Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
* fix: Codex Linux new logo
reMarkable changed their logo so reflecting that change here too
* Modify ASCII art in codex.txt
---------
Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
* Add OS2 Warp logo
* Update ASCII art in os2warp.txt
* Refactor OS/2 Warp logo names for consistency
---------
Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
* Proper detection of lliurex distribution
* fix newline
* Trim version and not versionID as assigned to lliurex-version output
* Update os_linux.c
---------
Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
* Display: add server vendor string
* Display (X11): fetch server vendor string using XCB/Xlib
* WM: show server vendor string when not empty
* Display (XCB): use proper string helper function
* Display (X11): shorten "The X.Org Foundation" to "Xorg"
Unifies IPv4 and IPv6 default route queries under a shared result structure and per-family functions. Improves clarity and extensibility by centralizing route logic, streamlining detection of preferred interfaces, and updating all consumers to use the new API.
Prepares for more robust multi-protocol network information handling.
* LocalIP: consider preferred source address when retrieving default route
* LocalIP: fix logic error when there is no preferred source address
* LocalIP: use macros rather than manual free/close
* LocalIP(BSD): fix build error
* LocalIP: address Copilot suggestions
Moves module option structs out of global config and removes dynamic allocation, using static buffers and size assertions for safer, simpler management.
Refactors module initialization and destruction to work with isolated option structs, eliminating the need for the previous modules container and related code.
Unifies module option header usage and updates detection logic to leverage statically-sized option buffers, improving encapsulation and maintainability.
Simplifies module function signatures and reduces coupling between modules and config.
Enhances future extensibility and reliability by enforcing max size constraints and removing unnecessary indirections.
Tip: A logo can be displayed by fastfetch without getting into fastfetch's official repo.
For highly customized logo for personal use, it's recommended to keep it locally.
Please refer to https://github.com/fastfetch-cli/fastfetch/wiki/Migrate-Neofetch-Logo-To-Fastfetch
> [!WARNING]
> **NB:** If your logo request does not meet the basic requirements outlined in this template, the issue may be closed at any time without any further explanation.
**Tip:** You can display a logo in fastfetch without adding it to fastfetch's official repo.
For highly customized, personal logos, we recommend keeping them locally.
You can test your logo locally using:
`fastfetch -l /path/to/logo.txt --logo-color-1 white --logo-color-2 red`
Please refer to the [Migration Guide](https://github.com/fastfetch-cli/fastfetch/wiki/Migrate-Neofetch-Logo-To-Fastfetch) for details on color placeholders (`$1`, `$2`, etc.).
- type:textarea
attributes:
label:OS
description:Paste content of `/etc/os-release` and `/etc/lsb-release` here. If none of these files exist, describe a way to identify the distro
description:Paste the contents of `/etc/os-release` (specifically the `ID` and `PRETTY_NAME` fields). If neither file exists, describe how to identify the distro.
placeholder:cat /etc/os-release
validations:
required:true
- type:input
attributes:
label:Public repository URL
description:A public repository is required to verify the request. Please provide a link to the repository where the distro is developed.
placeholder:https://github.com/example/distro
validations:
required:true
- type:input
attributes:
label:Distro Website
description:To help prevent spam and verify the request, a distro website is required, and a downloadable ISO must be available on that site.
placeholder:https://example.com
validations:
required:true
- type:textarea
attributes:
label:ASCII Art
description:An ASCII logo should not take up too much space (smaller than 50x20 characters). Please also include the color codes if not available in `os-release`
placeholder:Paste ASCII art here
description:|
The ASCII logo should not take up too much space (smaller than 50x20 characters, W x H).
**Important:** Fastfetch uses `$1`, `$2`, `$3` etc. for color placeholders. Do NOT use hardcoded ANSI escape codes (like `\033[38;2...m`) or Neofetch's `${c1}` syntax.
Take <https://github.com/fastfetch-cli/fastfetch/tree/dev/src/logo/ascii> as examples.
placeholder:Paste ASCII art with $1, $2 placeholders here
validations:
required:true
- type:input
attributes:
label:Original Image
description:If the ASCII art is based on an image, please provide a link to the original image
placeholder:Image URL or distro website URL
label:Original Image URL
description:If the ASCII art is based on an image, please provide a link to the original image file.
placeholder:Image URL from the distro website mentioned above
- type:checkboxes
attributes:
label:Checklist
options:
- label:The ASCII art is smaller than 50x20 characters (width x height)
- label:My distro has reached a stable state (out of beta, alpha, RC).
required:true
- label:The ASCII art contains color codes, or the color codes are available in `os-release`
- label:The ASCII art is smaller than 50x20 characters (W x H).
required:true
- label:The ASCII art uses `$N` color placeholders (or colors are natively available in `os-release`).
required:true
- label:The ASCII art has no unnecessary trailing spaces at the end of lines.
required:true
- label:I promise that I will send a removal request if the distro is discontinued.
<pclass="intro">Performance history grouped by CPU family. Each chart contains all modules and the total process time for one operating system and architecture. All metric series are shown by default except total process time, module Weather, and module PublicIp — toggle any series from the legend below the chart.</p>
<pclass="links"><ahref="data.js">Download raw benchmark data</a></p>
test -s weak.txt || { echo "::error::none of these entry points is referenced any more -- if the last use is gone on purpose, this check and the -Werror=unguarded-availability pair it guards should go with it"; exit 1; }
if grep -qv '^ *w ' weak.txt; then
echo "::error::expected every one of these to be a weak reference:"
This document is generated by AI and reviewed by humans. It is primarily intended for AI-assisted development, while remaining useful to human developers.
</details>
Thank you for your interest in fastfetch. This document covers building, architecture, how to add a module or a logo, code style, commit conventions, and the pull request workflow.
fastfetch is a system information tool written in C23, supporting Linux, macOS, Windows, the BSDs, Solaris, Haiku and Android. The project places strong emphasis on **startup time** and on keeping **dependencies optional**; many design decisions only make sense under that constraint, and this document returns to it repeatedly.
| Add a platform implementation | `src/detection/<name>/<name>_<platform>.c`, the matching platform block in `CMakeLists.txt` | Build on the target platform or CI |
| Add an ASCII logo | `src/logo/ascii/<letter>/<name>.txt`, matching `<letter>.inc` | `./build/fastfetch --logo <name>` |
| Change shared formatting or containers | `src/common/format.h`, `src/common/color.h`, `src/common/FFstrbuf.h` | Build and run the matching test |
| Run the test suite | `tests/`, `build/` | `cd build && ctest --output-on-failure` |
For a typical code change, the shortest useful iteration is: configure, build the `fastfetch` target, run the affected module, then run the tests. If you add a directory or a generated input, re-run `cmake -B build` so that CMake refreshes its file globs.
---
## Getting started
### Building
The quickest way is `run.sh` in the repository root: it creates `build/`, configures, compiles and runs the binary.
```sh
./run.sh # build and run
./run.sh --format json # arguments are forwarded to fastfetch
```
Manual build:
```sh
cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo
cmake --build build --target fastfetch -j$(nproc)
./build/fastfetch
```
The default build type is `RelWithDebInfo`. LTO is enabled whenever `ENABLE_LTO=ON`**and**`CMAKE_BUILD_TYPE != Debug`, so the default configuration enables it and only `Debug` builds omit it. This is significant because LTO here is not merely an optimization: it is what removes the code of disabled modules. See [Pitfalls](#pitfalls).
### Common build options
| Option | Default | Notes |
|---|---|---|
| `CMAKE_BUILD_TYPE` | `RelWithDebInfo` | LTO is on for anything but `Debug` |
| `BUILD_TESTS` | `OFF` | Builds the unit tests in `tests/` |
| `BUILD_FLASHFETCH` | `ON` | Also builds the stripped-down `flashfetch` |
| `MODULE_DISABLE_<NAME>` | `OFF` | Disable a module, e.g. `MODULE_DISABLE_GPU=ON` |
| `SET_TWEAK` | `ON` | Appends a tweak to the dev version; turned off for releases |
`BINARY_LINK_TYPE=dlopen` (the default) is a deliberate design choice: optional dependencies (Vulkan, Wayland, DBus, ImageMagick, chafa, …) are loaded at runtime, so a missing library never prevents startup. When adding a third-party dependency, use the dlopen helpers in `common/library.h` — do not link it directly.
For a minimal-dependency build, see `.github/workflows/build-no-features-test.yml`:
→ detection/ (one platform implementation each, raw data)
→ common/ (infrastructure)
```
The number of module directories does not match the number of detection directories, which is expected. The following relationships are structural rather than a fixed inventory:
- **13 modules have no detection directory** — they are either pure layout (`break`, `separator`, `colors`, `title`, `logo`) or reuse another module's detection result (`display`, `monitor`, `kernel`, `shell`, `terminal`, `player`, `custom`, `datetime`).
- **4 detection directories serve modules with different names** — `displayserver` (→ `display`, `monitor`), `gtk_qt` (→ `theme`, `icons`, `font`, `cursor`), `terminalshell` (→ `terminal`, `shell`) and `libc`.
Therefore, do not assume that `modules/<x>/` always has a matching `detection/<x>/`.
| `detection/` | cross-platform data retrieval, clean result structs | print anything, read display config |
| `common/` | general-purpose utilities, no business logic | depend on a specific module |
A simple check: **no file under `detection/` should contain `printf` or read `instance.config`.** Symmetrically, no file under `modules/` should contain `#ifdef __linux__`.
---
## Core architecture: modules vs. detection
This is the most important convention in the codebase. Every feature consists of a fixed set of files; using CPU as the example:
The `const char*` return value is an **error string**; `nullptr` means success. This pattern is used throughout `detection/` — please keep it consistent.
Helper functions are only exposed when they are genuinely shared between platform implementations (as in `cpu.h`: `ffCPUAppleCodeToName`, `ffCPUDetectByCpuid`).
**The benefit of this separation:** adding a platform never touches `modules/`; fixing output formatting never touches `detection/`.
---
## Module registration
### The descriptor
Every module exports one `FFModuleBaseInfo` (defined in `common/option.h:46`) — essentially a hand-written vtable:
```c
typedefstructFFModuleBaseInfo{
constchar*name;// lookup key, e.g. "cpu"
constchar*description;// help text
FFModuleDisplayNamedisplayName;// module name in 20 languages
FFModuleFormatArgListformatArgs;// format placeholder table
constuint8_tdefaultOrder;// sort weight
}FFModuleBaseInfo;
```
The source comment acknowledges that this is undefined behavior, since `void*` is not compatible with `FF*Options*`. It is a pragmatic compromise to obtain polymorphism in C; do not attempt to "fix" it.
### The registry: a first-letter hash bucket
`src/modules/modules.c` defines 26 `static FFModuleBaseInfo*` arrays (`A[]` through `Z[]`), each terminated by `nullptr`, collected into `ffModuleInfos[26]`:
Because the registry is small, a single arithmetic bucket lookup followed by a few string comparisons is preferable to a general-purpose hash table. When adding a module, place its descriptor in the bucket matching the first letter of `.name`, and keep the existing `nullptr` terminator at the end.
### The calling convention: zero heap allocation
Every dispatch site (`jsonconfig.c:98`, `commandoption.c:189`) follows the same pattern:
```c
alignas(uint64_t)uint8_toptionBuf[FF_OPTION_MAX_SIZE];// 256 bytes, on the stack
baseInfo->initOptions(optionBuf);
baseInfo->parseJsonObject(optionBuf,jsonVal);// JSONC path only
baseInfo->printModule(optionBuf);// or generateJsonResult
baseInfo->destroyOptions(optionBuf);
```
`FF_OPTION_MAX_SIZE = 1 << 8` (256 bytes). Every module's `option.h` must end with:
```c
static_assert(sizeof(FFCPUOptions)<=FF_OPTION_MAX_SIZE,"FFCPUOptions size exceeds maximum allowed size");
```
**In other words, no module option struct may exceed 256 bytes.** This is a hard constraint, enforced at compile time.
The three dispatch entry points:
| Entry point | Location | Used for |
|---|---|---|
| `parseModuleJsonObject` | `common/impl/jsonconfig.c:90` | the `modules[]` array in a JSONC config |
| `parseStructureCommand` | `common/impl/commandoption.c:181` | the colon-separated structure string |
### Build-time module discovery
`CMakeLists.txt:134` globs `src/modules/*/*.c`, keeps only the entries whose file name matches their directory name, and generates a `MODULE_DISABLE_<UPPER>` option for each:
Because the glob matches sources rather than directories, a directory counts as a module only when `src/modules/<name>/<name>.c` exists. Empty directories — which git does not track, so they are easy to leave behind — and stray files are ignored instead of breaking the configure step with `Cannot find source file`.
### Module sources are discovered automatically
`FF_MODULE_DIRS` also drives the source list (`CMakeLists.txt:516`):
```cmake
foreach(FF_MODULE_DIR${FF_MODULE_DIRS})
list(APPENDLIBFASTFETCH_SRC
src/modules/${FF_MODULE_DIR}/${FF_MODULE_DIR}.c
)
endforeach()
```
Consequences:
-`src/modules/<name>/<name>.c` is compiled as soon as the file exists — **there is no source list to edit for the module layer**.
- The file name must match the directory name. A directory whose `.c` file is named differently, or has none at all, is silently not a module: a typo therefore shows up as a module missing from `fastfetch --list-modules`, not as a build error.
- The glob uses `CONFIGURE_DEPENDS`, so with the Makefile and Ninja generators the build re-evaluates it and re-runs CMake when a module source is added or removed. With other generators, or to be safe, re-run `cmake -B build` explicitly.
Only the module layer is automated. Sources under `src/detection/` and `src/common/impl/` are **not** globbed and must still be listed by hand — see [step 5](#5-add-the-platform-sources-to-cmakeliststxt).
---
## Walkthrough: adding a module
Adding a `Foo` module, step by step.
### 1. Define the option struct
`src/modules/foo/option.h`:
```c
#pragma once
#include"common/option.h"
typedefstructFFFooOptions{
FFModuleArgsmoduleArgs;// must be the first field
boolshowBar;
}FFFooOptions;
static_assert(sizeof(FFFooOptions)<=FF_OPTION_MAX_SIZE,"FFFooOptions size exceeds maximum allowed size");
```
`FFModuleArgs` must come first. It provides `key`, `format`, `outputColor`, `keyColor`, `keyIcon` and `keyWidth`; because it is the first field, `ffJsonConfigParseModuleArgs()` handles these generically, **so no parsing code is required**.
returnnullptr;// success; return an error string on failure
}
```
**Write one file per target platform, plus a `foo_nosupport.c` fallback for the remaining platforms.** The repository currently contains 45 `*_nosupport.c` files serving this purpose.
### 3. Implement the module
`src/modules/foo/foo.c` — implement the six functions, then define the descriptor:
- **`displayName`** is a literal block of all 20 language fields; there is no shortcut macro, so copy the layout from an existing module: **`en`, `ar`, `cs`, `de`, `es`, `fr`, `gl`, `he`, `id`, `it`, `ja`, `ko`, `pl`, `pt`, `ru`, `tr`, `uk`, `vi`, `zh_CN`, `zh_TW`**.
**Fill in all 20.** The struct is read by byte offset (see [Pitfalls](#6-localization-uses-byte-offsets-not-enums)) and there is **no fallback** — a missing field means the key prints empty in that language.
- **`formatArgs`** must be exhaustive. It drives the placeholder list printed by `fastfetch -h foo-format`; **any placeholder omitted here is neither listed nor usable by the user.**
- The `moduleFormat` section in `doc/json_schema.json` is generated by `fastfetch -h format-json`. Its metadata comes from `FFModuleBaseInfo::formatArgs`. To keep the schema and module descriptors consistent, do not edit the `moduleFormat` section in `doc/json_schema.json` by hand; update the module metadata and regenerate it instead.
- **`defaultOrder`**: use the current maximum plus 1. Search the existing descriptors for `.defaultOrder =` before choosing a value; do not copy a hard-coded value from this document. Leaving it out, or setting it to `0`, excludes the module from the interactive `--gen-config` picker. Only `logo`, `command` and `custom` rely on this behavior, because they require user arguments or are invoked directly by the display layer.
### 4. Register it
- Add `#include "modules/foo/foo.h"` to `src/modules/modules.h`
- Insert into the `F[]` array in `src/modules/modules.c`:
```c
#if !FF_MODULE_DISABLE_FOO
&ffFooModuleInfo,
#endif
```
`FF_MODULE_DISABLE_FOO` is generated by CMake — you do not define it yourself.
### 5. Add the platform sources to `CMakeLists.txt`
The module layer is discovered by glob (see [Build-time module discovery](#module-sources-are-discovered-automatically)), **but `src/detection/**` and `src/common/impl/**` are not**. `CMakeLists.txt` lists them explicitly, inside one mutually exclusive chain of platform blocks:
Add the platform implementation to every block whose platform it supports, and `foo_nosupport.c` to every remaining block, so that all ten platforms still link:
```cmake
elseif(FreeBSD)
list(APPEND LIBFASTFETCH_SRC
...
src/detection/foo/foo_bsd.c
)
```
Points to note:
- Exactly one block is compiled per build, so a file omitted from a block does not exist for that platform, and the link fails with an undefined reference to `ffDetectFoo()` — **on that platform only**. A missing entry therefore builds fine locally and fails in CI; this is why every block must be covered.
- A platform may reuse another platform's implementation instead of a stub. `src/common/impl/networking_linux.c`, for example, is listed in nine of the ten blocks (all but `WIN32`). Check where the closest sibling module points before adding a new file.
- `DragonFly` is handled by the inner `if(DragonFly)` sub-block inside the FreeBSD block (`CMakeLists.txt:773`); add the variant there, as `processes`, `top` and `wifi` do.
- New helpers under `src/common/impl/` follow the same rule: they are not globbed, and each block that needs one must list it.
- A few files are appended outside the platform chain because they depend on an option or on a specific feature — for example the proprietary GPU backends (`CMakeLists.txt:1379`) and `src/common/impl/wcwidth.c` (`CMakeLists.txt:1408`). Those are written by hand as well.
### 6. Modules that need warm-up
If your module needs a sampling interval (CPU usage) or a network round-trip (public IP, weather), also implement `ffPrepareFoo()` and register it in the switch inside `ffPrepareCommandOption()` in `common/impl/commandoption.c`, under the matching first-letter `case`. Six modules currently do this: CPUUsage, DiskIO, NetIO, PublicIP, Top and Weather.
./build/fastfetch -h foo-format # list formatArgs placeholders
./build/fastfetch --gen-config # confirm it appears in the picker
```
Note the `-format` suffix on the help flag: `fastfetch -h foo` is not supported; only `fastfetch -h foo-format` works.
If you added detection sources, re-check [step 5](#5-add-the-platform-sources-to-cmakeliststxt) before pushing: a platform block you missed compiles fine locally and fails only when that platform is built.
---
## Walkthrough: adding a logo
A new logo **must** have a corresponding "Logo Request" issue, linked from the PR with `Closes #1234`. Logo PRs without a linked issue are not accepted.
### 1. Add the ASCII file
```
src/logo/ascii/<first-letter>/<distro>.txt
```
For example `src/logo/ascii/d/distro.txt`. Directories are already split by first letter (`a/` … `z/`, plus `_/`).
The file is plain ASCII art with `$1` … `$9` as color placeholders:
```
$3 ,-^-___
$3 /\\\///
$2refined.$1 /\\\\//
```
- `$1` … `$9` map to palette slots 1–9; at most 9 are supported (`FASTFETCH_LOGO_MAX_COLORS = 9`)
- `$$` is a literal `$`
- Characters without a placeholder inherit the current color. Of the 530 existing logos, 239 use no placeholders at all (monochrome) and 291 do; **new logos should use placeholders**, as monochrome is a legacy style
- Tabs are expanded to 4 spaces
- Colors can be overridden with `--logo-color-1` … `--logo-color-9`
### 2. Register it in the `.inc`
CMake turns each `.txt` file into a `FASTFETCH_DATATEXT_LOGO_<UPPERCASE>` macro (`CMakeLists.txt:418`), but **the registry itself is maintained by hand**. Edit `src/logo/ascii/<first-letter>.inc`:
```c
// src/logo/ascii/d.inc
#ifdef FASTFETCH_DATATEXT_LOGO_DISTRO
// Distro
{
.names = { "Distro" }, // ID (preferred) or NAME from /etc/os-release, do NOT add both
.lines = FASTFETCH_DATATEXT_LOGO_DISTRO,
.colors = {
FF_COLOR_FG_PRIMARY, // recommended for using as WHITE replacement, light-theme terminal friendly
FF_COLOR_FG_BLUE, // preferred
FF_COLOR_FG_256 "34",
FF_COLOR_FG_RGB "0;255;0", // not recommended because of bad compatibility with raw TTY
},
},
#endif
```
- `names` is matched case-insensitively. Do not add names that differ only by case, because they can never be distinguished. Every name is also shown by `--list-logos`, so use user-friendly spelling such as an initial capital where appropriate.
- For a new logo, use exactly one name unless there is a specific compatibility reason to add more. That name should first be the `ID` from `/etc/os-release`. If the ID cannot distinguish this logo from another logo for the same OS, use the `NAME` value instead. `logoGetBuiltinDetected` in `src/logo/logo.c` documents the detection order: `ID`, then `NAME`, then tokens from `ID_LIKE`, then the platform name fallback. Manual `logo-source` selection uses the name directly.
- `colors` is positional — entry 0 is `$1`, entry 1 is `$2`, and so on
- `colors[0]` also becomes the title color and `colors[1]` the key color, unless the user overrides them
If the same OS has multiple logo variants, mark the variant explicitly with `.type`:
```c
.type = FF_LOGO_LINE_TYPE_SMALL_BIT,
```
Use `FF_LOGO_LINE_TYPE_ALTER_BIT` for an alternate logo, `FF_LOGO_LINE_TYPE_SMALL_BIT` for a small logo, or combine the flags when both apply. This is also a lookup optimization: a logo marked `FF_LOGO_LINE_TYPE_SMALL_BIT` is considered only for `type = small`, while a logo marked `FF_LOGO_LINE_TYPE_ALTER_BIT` is never selected by automatic detection. Alternate logos are available only when explicitly requested through `-l <source>`.
### 3. Verify
```sh
./build/fastfetch -l distro
./build/fastfetch --list-logos | grep -i distro
```
---
## Platform conventions
The `detection/` layer picks its implementation by **filename suffix**; the choice is made at build time from `CMAKE_SYSTEM_NAME`:
| `_windows.c` / `_windows.cpp` | Windows (`.cpp` for WinRT / WMI) |
| `_bsd.c` | FreeBSD |
| `_nbsd.c` | NetBSD |
| `_obsd.c` | OpenBSD |
| `_sunos.c` | Solaris / illumos |
| `_haiku.c` / `.cpp` | Haiku |
| `_android.c` | Android (Termux) |
| `_gnu.c` | GNU/Hurd |
| `_nosupport.c` | Empty fallback |
Current distribution of platform files in `detection/`:
| Suffix | Files | Suffix | Files |
|---|---|---|---|
| `_linux` | 58 | `_obsd` | 16 |
| `_windows` | 47 | `_haiku` | 13 |
| `_apple` | 46 | `_android` | 12 |
| `_nosupport` | 45 | `_gnu` | 3 |
| `_bsd` | 29 | | |
| `_sunos` | 19 | | |
| `_nbsd` | 17 | | |
(These are repository inventory figures, counting `.c`, `.m`, `.cpp`, and `.h`; they may change as platforms and modules are added.)
**Do not accumulate `#ifdef__linux__` blocks in a single file.** When adding platform support, copy the closest existing implementation and change the suffix.
`common/` follows the same convention: `common/impl/` contains `io_unix.c` / `io_windows.c`, `netif_linux.c` / `netif_apple.c` / `netif_bsd.c` and similar files, with `common/apple/`, `common/windows/` and `common/haiku/` holding platform-specific helpers.
When several platform suffixes could apply, use the most specific implementation supported by the build system (for example, `_nbsd.c` instead of the generic `_bsd.c` on NetBSD). Keep the generic file as the fallback for platforms that share its conventions.
---
## Code style
### Formatting
The project uses clang-format with `BasedOnStyle: LLVM` plus these key overrides:
```yaml
IndentWidth: 4
UseTab: Never
ColumnLimit: 0 # never wrap
InsertBraces: true # braces even on single-statement ifs
PointerAlignment: Left # char* p, not char *p
SortIncludes: Never # include order is managed by hand
AlignAfterOpenBracket: DontAlign
BinPackParameters: false # all params on one line, or one per line
Scope is the module or subsystem name; Platform is optional. Use the third-person singular present tense, capitalize the first letter, no trailing period.
Real examples from recent history:
```
Processes (Haiku): honors `options->countKprocs`
WM (macOS): improves reliability of WM plugin detection
Memory (Windows): prefers `NQSI`
Top (Linux): improves performance of `stat` parsing
Logo (Builtin): adds omarchy
Global: introduces global macro `FF_PATH_PKG_BASE` to replace `_PATH_LOCALBASE`
LM (OpenBSD): adds support
CI: disables fail on alert
Doc: updates README
Presets: moves `top` to the bottom of running modules [ci skip]
Scopes in use: `Top`, `Processes`, `Memory`, `Logo (Builtin)`, `CI`, `Doc`, `Presets`, `Global`, plus individual module names.
Documentation-only changes use a `[ci skip]` suffix.
---
## Changelog
User-visible changes go into `CHANGELOG.md`, under the topmost version heading:
```markdown
# Unreleased
Changes:
* The DE / WM / LM modules now reports the full name ...
Features:
* Added Top module to print processes with the highest CPU, memory or disk I/O usage. (Top)
* Improved Wi-Fi module
* Added Wifi channel width detection, exposed via `{channel-width}` in custom format.
* Improved Wifi channel frequency accuracy on Windows, macOS.
* Added Battery detection support on SunOS. (Battery, SunOS)
Bugfixes:
* Fixed I/O rate calculation precision in DiskIO and NetIO. (DiskIO / NetIO)
```
Rules:
- Three sections: `Changes:` (behavior changes), `Features:`, `Bugfixes:`
- Past tense: `Added` / `Fixed` / `Improved`
- End each entry with its scope: `(Module, Platform)` or `(ModuleA / ModuleB)`
- Sub-bullets are indented 4 spaces
---
## Tests
Tests are standalone executables in `tests/` using a `VERIFY` macro that exits non-zero on failure:
```c
#define VERIFY(expression) \
if (!(expression)) testFailed(&strbuf, #expression, __LINE__)
```
Current tests: `strbuf.c`, `list.c`, `format.c`, `color.c`, `duration.c`, `strutil.c`.
```sh
cmake -B build -DBUILD_TESTS=On
cmake --build build
cd build && ctest --output-on-failure
```
Coverage focuses on the core data structures and the formatting engine in `common/`. The `detection/` layer has no automated tests, because it depends on the state of a running system; it is instead covered by the CI matrix — 20 workflows under `.github/workflows/` spanning Linux (including musl, loong64, armv7l, i686), Android, macOS, Windows, FreeBSD, NetBSD, OpenBSD, DragonFly, Solaris, OmniOS and Haiku, plus a benchmark job. The Android job is the one that does not run what it builds: it cross-compiles for arm64-v8a, armeabi-v7a and x86_64 with the NDK at API 24 and inspects the result instead, because CI has no device or emulator. Its dynamic-symbol checks are what keep the weak references the platform branch depends on from turning into load failures on older devices.
**If you modify `common/FFstrbuf.h`, `common/format.h` or `common/color.h`, extend the corresponding test.**
---
## Pull requests
1. **Open an issue first** (feature request / bug report / logo request) to confirm that the change is wanted before investing effort. Templates are in `.github/ISSUE_TEMPLATE/`.
2. Branch off `dev` — **`dev` is the main development branch**, not `master`.
3. Follow the [commit message convention](#commit-messages).
4. Update `CHANGELOG.md` for user-visible changes.
5. Open the PR against `dev` and fill in `.github/pull_request_template.md`:
- Summary
- Related issue (**required for new logos**; otherwise the PR is not accepted)
./build/fastfetch --format json # verify JSON output is well-formed
./build/fastfetch -c presets/all.jsonc --stat false # smoke-test every module
```
---
## Pitfalls
The following points are easy to misinterpret when reading this codebase. Most of them follow from the startup-time objective described above.
### 1. Option structs must not exceed 256 bytes
`FF_OPTION_MAX_SIZE = 1 << 8`. Exceeding it is caught at compile time by `static_assert`. Do not attempt to increase the value: it determines the stack cost of every module invocation.
### 2. `FF_MODULE_DISABLE_*` controls registration, not compilation
```c
// verbatim from the top of modules/modules.c:
// FF_MODULE_DISABLE_<module> only controls if the module is registered,
// the module code itself is still compiled.
// We rely `LTO` to remove the unused code (only enabled in Release mode)
```
**Disabling modules in a Debug build does not shrink the binary.** LTO is enabled whenever `CMAKE_BUILD_TYPE != Debug`, and the default `RelWithDebInfo` already satisfies that — so measure size with `RelWithDebInfo` or `Release`, never with `Debug`. (The "Release mode" wording in the comment above is imprecise.)
### 3. Only two things are discovered by glob
The module sources (`CMakeLists.txt:134`) and the logo `.txt` files (`CMakeLists.txt:429`). Both use `CONFIGURE_DEPENDS`, so with the Makefile and Ninja generators the build re-checks the glob and re-runs CMake when the result changes; other generators (Visual Studio and Xcode in particular) do not track it as reliably. Re-run `cmake -B build` after adding a module source or a logo file rather than relying on that behavior.
Everything else — `src/detection/**` and `src/common/impl/**`, and any source outside the platform chain — must be listed in `CMakeLists.txt` by hand; see [step 5](#5-add-the-platform-sources-to-cmakeliststxt).
### 4. CLI module options are removed
Per-module command-line flags such as `--cpu-temp` are **no longer supported**. The only job of `ffParseModuleOptions` now is to translate the flag into a JSON key, then `exit(477)` with a pointer to the config file:
```
Error: Unsupported module option: --cpu-temp
Support of module options has been removed. Please add the flag to the JSON config instead.
**JSONC is the first-class configuration interface; the command line is not.** When adding module options, implement `parseJsonObject` only — do not add a CLI branch.
### 5. `defaultOrder = 0` hides a module from `--gen-config`
`collectModuleInfos` (`genconfig.c:186`) skips any module whose `defaultOrder` is `0`. C zero-initializes the field, so **omitting it is the same as setting it to 0**. Only `logo`, `command` and `custom` rely on this intentionally.
`defaultOrder` affects only the ordering in the interactive `--gen-config` picker; it has no effect on the runtime output order.
### 6. Localization uses byte offsets, not enums
`instance.config.display.keyLanguage` does not hold a language enum — it holds a **byte offset** such as `offsetof(FFModuleDisplayName, zh_CN)`. The macro `FF_MODULE_GET_DISPLAY_NAME` (`common/option.h:123`) does plain pointer arithmetic with it:
Consequence: **the field order of `FFModuleDisplayName` must never change** — reordering the fields silently corrupts the output for every language.
### 7. The `multithreading` option has limited effect
The global `multithreading` option currently takes effect in exactly one place: `common/impl/networking_linux.c:339`. Modules are still printed sequentially. Modules that need concurrency go through the `ffPrepare*` warm-up hooks instead, which start sampling or fire off requests before the print loop begins.
This may change in the future. The main blocking issue is that there are dependencies between different modules.
### 8. Do not print or read configuration inside `detection/`
The `detection/` layer must stay pure: read system state, fill a struct, return an error string. Any `printf` or any read of `instance.config` there is a design error.
Use `FF_DEBUG` (`src/common/debug.h`) for logging.
### 9. `src/logo/builtin.c` and `3rdparty/` are formatting-exempt
The former is a large generated and hand-maintained data table; the latter is upstream code. Both are excluded via `.clang-format-ignore`; do not reformat either.
[](https://github.com/fastfetch-cli/fastfetch/actions)
Fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for fetching system information and displaying it in a visually appealing way. It is written mainly in C, with a focus on performance and customizability. Currently, it supports Linux, macOS, Windows 7+, Android, FreeBSD, OpenBSD, NetBSD, DragonFly, Haiku, and SunOS.
Fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for fetching system information and displaying it in a visually appealing way. It is written mainly in C, with a focus on performance and customizability. Currently, it supports Linux, macOS, Windows 8.1+, Android, FreeBSD, OpenBSD, NetBSD, DragonFly, Haiku and SunOS (illumos, Solaris).
> Note: Fastfetch is only actively tested on x86-64 and aarch64 platforms. It may work on other platforms but is not guaranteed to do so.
* Ubuntu: [`ppa:zhangsongcui3371/fastfetch`](https://launchpad.net/~zhangsongcui3371/+archive/ubuntu/fastfetch) (for Ubuntu 22.04 or newer)
* Debian: `apt install fastfetch` (for Debian 13 or newer)
* Ubuntu: [`ppa:zhangsongcui3371/fastfetch`](https://launchpad.net/~zhangsongcui3371/+archive/ubuntu/fastfetch) (Ubuntu 22.04 or newer; latest version)
* Debian / Ubuntu: `apt install fastfetch` (Debian 13 or newer; Ubuntu 25.04 or newer)
* Debian / Ubuntu: Download `fastfetch-linux-<proper architecture>.deb` from [Github release page](https://github.com/fastfetch-cli/fastfetch/releases/latest) and double-click it (for Ubuntu 20.04 or newer and Debian 11 or newer).
* Arch Linux: `pacman -S fastfetch`
* Fedora: `dnf install fastfetch`
@@ -58,7 +62,7 @@ If fastfetch is not packaged for your distribution or an outdated version is pac
* [MacPorts](https://ports.macports.org/port/fastfetch/): `sudo port install fastfetch`
### Windows
@@ -95,7 +99,8 @@ See the Wiki: https://github.com/fastfetch-cli/fastfetch/wiki/Building
* Run with [all supported modules](https://github.com/fastfetch-cli/fastfetch/wiki/Support+Status#available-modules) to find what interests you: `fastfetch -c all.jsonc`
* View all data that fastfetch detects: `fastfetch -s <module1>[:<module2>][:<module3>] --format json`
* Display help messages: `fastfetch --help`
* Generate a config file based on command line arguments: `fastfetch --arg1 --arg2 --gen-config`
* Use [The online configuration generator](https://fastfetch-cli.github.io/fastfetch-config/) to generate a full config file with all optional options
## Customization
@@ -103,6 +108,10 @@ Fastfetch uses JSONC (JSON with comments) for configuration. [See the Wiki for d
Logos can also be heavily customized; see the [logo documentation](https://github.com/fastfetch-cli/fastfetch/wiki/Logo-options) for more information.
### WARNING
Fastfetch supports a `Command` module that can run arbitrary shell commands. If you copy-paste a config file from an untrusted source, it may contain malicious commands that can harm your system or compromise your privacy. Please always review the config file before using it.
## FAQ
### Q: Neofetch is good enough. Why do I need fastfetch?
@@ -191,7 +200,8 @@ See [#1096](https://github.com/fastfetch-cli/fastfetch/issues/1096).
### Q: Fastfetch shows fewer dpkg packages than neofetch. Is it a bug?
Neofetch incorrectly counts `rc` packages (packages that have been removed but still have configuration files remaining). See bug: https://github.com/dylanaraps/neofetch/issues/2278
1.Neofetch incorrectly counts `rc` packages for apt (packages that have been removed but still have configuration files remaining). See bug: https://github.com/dylanaraps/neofetch/issues/2278
2. Neofetch incorrectly counts `gpg-pubkey` as packages for rpm. You may check the results of `dnf list --installed | wc -l` and `rpm -qa | wc -l` to see the difference.
### Q: I use Debian / Ubuntu / Debian-derived distro. My GPU is detected as `XXXX Device XXXX (VGA compatible)`. Is this a bug?
@@ -238,7 +248,20 @@ Set the key to a white space.
### Q: How can I display images on Windows?
As of April 2025:
#### Windows Terminal
Windows Terminal supports the sixel image protocol only.
```jsonc
{
"logo":{
"type":"sixel",// DO NOT USE "auto"
"source":"C:/path/to/image.png",// ~ can be used to refer to the Windows user home directory
"width":<image-width-in-chars>,// Optional
"height":<image-height-in-chars>// Optional
}
}
```
#### mintty and Wezterm
@@ -250,38 +273,7 @@ In `config.jsonc`:
"logo":{
"type":"iterm",
"source":"C:/path/to/image.png",
"width":<num-in-chars>
}
}
```
#### Windows Terminal
Windows Terminal supports the sixel image protocol only.
"source":"C:/path/to/image.png",// Do NOT use `~` as fastfetch is a native Windows program and doesn't apply cygwin path conversion
"width":<image-width-in-chars>,// Optional
"height":<image-height-in-chars>// Optional
}
}
```
* If you installed fastfetch via scoop or downloaded the binary directly from the GitHub Releases page:
1. Convert your image manually to sixel format using [any online image conversion service](https://www.google.com/search?q=convert+image+to+sixel)
2. In `config.jsonc`:
```jsonc
{
"logo":{
"type":"raw",// DO NOT USE "auto"
"source":"C:/path/to/image.sixel",
"width":<image-width-in-chars>,// Required
"height":<image-height-in-chars>// Required
"width":<image-width-in-chars>
}
}
```
@@ -317,14 +309,19 @@ If you find Fastfetch useful, please consider donating.
* Current maintainer: [@CarterLi](https://paypal.me/zhangsongcui)
* Original author: [@LinusDierheimer](https://github.com/sponsors/LinusDierheimer)
## Code signing
* Free code signing provided by [SignPath.io](https://about.signpath.io/), certificate by [SignPath Foundation](https://signpath.org/)
* This program will not transfer any information to other networked systems unless specifically requested by the user or the person installing or operating it
ADL_THREADING_UNLOCKED=0,/*!< Default behavior. ADL will not enforce serialization of ADL API executions by multiple threads. Multiple threads will be allowed to enter to ADL at the same time. Note that ADL library is not guaranteed to be thread-safe. Client that calls ADL_Main_Control_Create have to provide its own mechanism for ADL calls serialization. */
ADL_THREADING_LOCKED/*!< ADL will enforce serialization of ADL API when called by multiple threads. Only single thread will be allowed to enter ADL API at the time. This option makes ADL calls thread-safe. You shouldn't use this option if ADL calls will be executed on Linux on x-server rendering thread. It can cause the application to hung. */
ADL_THREADING_LOCKED/*!< ADL will enforce serialization of ADL API when called by multiple threads. Only single thread will be allowed to enter ADL API at the time. This option makes ADL calls thread-safe. */
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.