# Handling Display Options in FastFetch: Architecture and Implementation

> Explore the architecture for handling display options in FastFetch. Learn how FFOptionsDisplay ensures consistent terminal formatting through defaults, command-line args, and JSON config.

- Repository: [fastfetch-cli/fastfetch](https://github.com/fastfetch-cli/fastfetch)
- Tags: architecture
- Published: 2026-03-30

---

**FastFetch centralizes all output customization in a global `FFOptionsDisplay` structure that is initialized with defaults, populated from command-line arguments or JSON configuration, and consumed as read-only state by every module to ensure consistent terminal formatting.**

FastFetch implements a centralized architecture for handling display options in fastfetch, storing all formatting preferences in a single configuration object that serves as the single source of truth for colors, separators, and numeric formatting. The design separates parsing logic from rendering logic, allowing modules to query display settings without duplicating validation code.

## Core Data Structure

The foundation of FastFetch's display handling is the `FFOptionsDisplay` struct defined in [`src/options/display.h`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/options/display.h). This structure aggregates every user-facing output customization into a single, flat configuration object.

```c
typedef struct FFOptionsDisplay {
    /* colour handling */
    FFstrbuf colorKeys;          // “--color‑keys”
    FFstrbuf colorTitle;         // “--color‑title”
    FFstrbuf colorOutput;        // “--color‑output”
    FFstrbuf colorSeparator;     // “--color‑separator”
    bool brightColor;            // auto‑bright for dark terminals

    /* key/value layout */
    FFstrbuf keyValueSeparator; // “--separator”
    FFModuleKeyType keyType;     // “--key‑type”
    uint16_t keyWidth;           // “--key‑width”
    uint16_t keyPaddingLeft;     // “--key‑padding‑left”

    /* numeric formatting */
    int32_t stat;                // “--stat”
    bool pipe;                   // “--pipe”
    bool hideCursor;             // “--hide‑cursor”
    bool disableLinewrap;        // “--disable‑linewrap”
    bool durationAbbreviation;   // “--duration‑abbreviation”
    FFSpaceBeforeUnitType durationSpaceBeforeUnit;
    FFSizeBinaryPrefixType sizeBinaryPrefix;
    uint8_t sizeNdigits;
    uint8_t sizeMaxPrefix;
    FFSpaceBeforeUnitType sizeSpaceBeforeUnit;
    FFTemperatureUnit tempUnit;
    uint8_t tempNdigits;
    FFSpaceBeforeUnitType tempSpaceBeforeUnit;
    uint8_t barWidth;
    FFPercentageTypeFlags percentType;
    uint8_t percentNdigits;
    FFSpaceBeforeUnitType percentSpaceBeforeUnit;
    uint8_t percentWidth;
    int8_t freqNdigits;
    FFSpaceBeforeUnitType freqSpaceBeforeUnit;
    int8_t fractionNdigits;
    FFFractionTrailingZerosType fractionTrailingZeros;
    bool noBuffer;
    FFlist constants;            // user defined constants
} FFOptionsDisplay;

```

This struct lives inside the global configuration object `FFconfig` (declared in [`src/fastfetch.h`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/fastfetch.h)), ensuring all display parameters are accessible throughout the codebase.

## Global Instance Management

FastFetch uses a single global instance to host the display configuration. The `FFinstance` struct defined in [`src/fastfetch.h`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/fastfetch.h) contains both configuration and runtime state:

```c
typedef struct FFinstance {
    FFconfig config;
    FFstate state;
} FFinstance;

extern FFinstance instance;   // defined in `src/common/init.c`

```

All modules read `instance.config.display` directly, which guarantees a single source of truth for output style. This global pattern eliminates the need to pass configuration pointers through every function call while maintaining thread-safe read-only access during execution.

## Configuration Initialization

During startup, FastFetch calls `ffOptionsInitDisplay(&instance.config.display)` to establish sane defaults. This function, implemented in [`src/options/display.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/options/display.c), allocates internal buffers and sets default values such as `sizeBinaryPrefix = FF_SIZE_BINARY_PREFIX_TYPE_IEC`, `percentType = 9`, and default color strings.

The initialization sequence ensures that every field contains a valid value before any user input is processed, preventing undefined behavior when modules query display settings.

## Parsing User Input

FastFetch supports two input vectors for display options: command-line arguments and JSON configuration files. Both populate the same `FFOptionsDisplay` struct using dedicated parser functions.

### Command-Line Parsing

The `ffOptionsParseDisplayCommandLine` function receives each `--<option>` flag and updates the matching field in the display struct. It is invoked from the generic option parser in [`src/fastfetch.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/fastfetch.c):

```c
if (ffOptionsParseDisplayCommandLine(&instance.config.display, key, value)) …

```

This parser uses helper functions like `ffOptionParseColor`, `ffOptionParseEnum`, and `ffOptionParseBoolean` to translate raw strings into internal representations. For example, when processing `--color-keys`, the parser validates the color string and stores it in `options->colorKeys`.

### JSON Configuration Parsing

When a config file is supplied, FastFetch reads it with `yyjson` and calls:

```c
ffOptionsParseDisplayJsonConfig(&instance.config.display, root);

```

The JSON parser walks each property inside the top-level `"display"` object, validates types, and copies values directly into the struct. This allows complex nested configurations like custom color schemes and unit preferences to be persisted across sessions.

### Configuration Generation

When `--gen-config` is used, FastFetch serializes the current configuration back to JSON via `ffOptionsGenerateDisplayJsonConfig(data, &instance.config.display)`. This ensures the generated file mirrors in-memory defaults and any runtime overrides, creating a perfect round-trip between CLI flags and configuration files.

## Runtime Consumption Patterns

All modules that output data query the global `instance.config.display` in a read-only pattern. This design ensures consistent formatting across every system information module.

### Color Handling

Modules wrap output with ANSI sequences only when `!instance.config.display.pipe`. For example, in [`src/modules/title/title.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/modules/title/title.c):

```c
if (!instance.config.display.pipe) {
    ffPrintColor(&instance.config.display.colorTitle);
}

```

The `pipe` flag acts as a master switch for all terminal control codes, ensuring that piped output never contains escape sequences that could corrupt downstream processing.

### Percentage and Size Formatting

Modules respect global formatting defaults while allowing local overrides. In [`src/modules/cpuusage/cpuusage.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/modules/cpuusage/cpuusage.c), the code falls back to global settings when module-specific options are unset:

```c
FFPercentageTypeFlags pct = options->percent.type == 0
                            ? instance.config.display.percentType
                            : options->percent.type;

```

Helper functions in [`src/common/impl/size.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/common/impl/size.c) and [`src/common/impl/printing.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/common/impl/printing.c) read display fields like `sizeNdigits`, `freqSpaceBeforeUnit`, and `keyWidth` to determine number formatting, spacing, and alignment.

### Key-Value Rendering

The generic printer in [`src/common/impl/printing.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/common/impl/printing.c) consults `keyWidth`, `keyPaddingLeft`, and `keyValueSeparator` to construct formatted output lines. This centralizes the logic for aligning keys and values across all modules, ensuring that `--key-width 15` affects every module uniformly.

## Configuration Lifecycle

The display options follow a strict lifecycle that maintains data integrity from startup to shutdown:

1. **Startup**: `ffOptionsInitDisplay` allocates buffers and sets defaults
2. **CLI Parsing**: `ffOptionsParseDisplayCommandLine` overwrites defaults per `--<option>` flag
3. **Config File**: `ffOptionsParseDisplayJsonConfig` merges JSON values (overwriting CLI if processed later)
4. **Runtime**: Modules and printers read `instance.config.display` (read-only access)
5. **Shutdown**: `ffOptionsDestroyDisplay` frees allocated buffers and lists

This lifecycle ensures that display configuration is immutable during the actual information gathering and printing phases, preventing race conditions or inconsistent formatting.

## Summary

- **Centralized Structure**: All display options reside in `FFOptionsDisplay` (defined in [`src/options/display.h`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/options/display.h)), accessed globally via `instance.config.display`.
- **Dual Input Support**: The architecture handles both command-line arguments via `ffOptionsParseDisplayCommandLine` and JSON configuration via `ffOptionsParseDisplayJsonConfig`.
- **Read-Only Consumption**: Modules query display settings at runtime but never modify them, ensuring consistent output formatting.
- **Pipe Safety**: The `pipe` boolean acts as a global gate for ANSI escape sequences, automatically disabling colors and cursor manipulation when output is redirected.
- **Round-Trip Configuration**: `ffOptionsGenerateDisplayJsonConfig` enables perfect serialization of runtime state back to JSON for configuration management.

## Frequently Asked Questions

### Where are the display option defaults defined in FastFetch?

The default values for all display options are established in `ffOptionsInitDisplay` within [`src/options/display.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/options/display.c). This function sets initial values such as IEC binary prefixes for sizes, specific percentage formatting flags, and default color buffers before any user configuration is loaded.

### How does FastFetch handle the `--pipe` flag internally?

The `pipe` field in `FFOptionsDisplay` serves as a master switch for ANSI escape sequences. Every module checks `instance.config.display.pipe` before emitting color codes or cursor control sequences. When pipe mode is enabled, FastFetch outputs plain text suitable for redirection to files or other programs without terminal control characters.

### Can display options be specified in both CLI arguments and JSON config simultaneously?

Yes. FastFetch processes display options from both sources, with later inputs overwriting earlier ones. Typically, CLI arguments are processed first, then JSON configuration is loaded. If the same option appears in both, the JSON value takes precedence unless the CLI flag was processed after the config file load. The `ffOptionsGenerateDisplayJsonConfig` function can export the final merged state to create a new config file reflecting all active settings.

### Which modules consume the display configuration options?

All output modules consume the global display configuration. Key consumers include the **title** module ([`src/modules/title/title.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/modules/title/title.c)) for colors, the **CPU usage** module ([`src/modules/cpuusage/cpuusage.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/modules/cpuusage/cpuusage.c)) for percentage formatting, and the generic printing helpers in [`src/common/impl/printing.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/common/impl/printing.c) and [`src/common/impl/size.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/common/impl/size.c) that handle key alignment, unit prefixes, and numeric precision across the entire codebase.