-
-
Notifications
You must be signed in to change notification settings - Fork 898
Format String Guide
This document describes the format string syntax used by the format property of a module, and by the key property when it is used as a format string.
A format string contains placeholders for dynamic values. Each placeholder starts with {, contains a value name or index, and ends with }.
For example:
See the module-specific help for available named arguments:
$ fastfetch -h title-formatA placeholder that cannot be resolved, such as a misspelled argument name or an out-of-range index, is printed verbatim rather than being dropped, which makes it easy to spot. fastfetch --show-errors does not report them.
DEPRECATED: Always prefer named arguments over numeric placeholders. Numeric placeholder positions can change between releases (for example if arguments are reordered), which introduces breaking changes for any configuration relying on them. Named arguments such as {user-name} remain stable regardless of argument ordering.
{1}@{2} or {}@{} (indices are implicitly increased, starts from 1)
Because of historical reasons,
{0}is the same as{}
You can specify a truncation length using the {arg:length} syntax:
"{user-name:5}" → truncates the username to 5 characters
If the length is negative, an ellipsis (…) is appended to the truncated string.
Note: the length is measured in raw bytes, not in characters or display columns, so a multi-byte character counts as several and can be cut in half. A color escape sequence at the start of the value, and the reset at the end of it, are not counted; one in the middle of the value is.
Use <, >, or | instead of : to apply left, right, or center padding:
"{user-name<20}" → left-aligned with spaces: "username "
"{user-name>20}" → right-aligned with spaces: " username"
"{user-name|20}" → center-aligned with spaces: " username " // Added in v2.64.0Note: String length is measured in raw bytes, as above.
Use {variable~startIndex,endIndex} to slice a string:
"{user-name~0,3}" → characters 0 to 2: "car"
"{user-name~1}" → from character 1 to the end: "arter"
"{user-name~2,4}" → characters 2 to 3: "rt"
"{user-name~-3,-1}" → characters 3 to 4: "te"
Negative indices count backward from the end of the string. The start index is inclusive and the end index is exclusive, an omitted start index defaults to 0, and an end index past the end of the string is clamped to it.
Note: String length is measured in raw bytes, as above.
Note: an omitted end index does not mean "up to the end of the string". "{user-name~2,}" and "{user-name~-5,}" both evaluate to an empty string, because the missing end index is read as 0 and 0 is never greater than the start index. Give the end index explicitly, or drop the comma to slice to the end of the string ("{user-name~2}").
You can reference constants and environment variables using the $ prefix:
"{$1}" → the first entry of `display.constants`
"{$-1}" → the last entry of `display.constants`
"{$ENV_VAR}" → an environment variable
- Constants are numbered from
1, and a negative index counts backward from the end. -
{$0}and any index outside the list are printed verbatim.
A double open curly brace ({{) is printed as a single open curly brace ({) and is not treated as a placeholder. There is no escape for a closing brace; a } that does not close a placeholder is printed as is.
To conditionally print content only when a variable is set (not empty):
"{?user-name}Username: {user-name}{?}" → Prints only if `{user-name}` is set
To conditionally print content only when a variable is NOT set (empty):
"{/user-name}Username not available{/}" → Prints only if `{user-name}` is NOT set
Example combining both:
"{?user-name}{user-name}{?}{/user-name}Username fallback{/}"
Whether a variable counts as "set" depends on its type, and for every numeric type the test is strictly greater than zero:
| Variable type | Counted as set when |
|---|---|
| Number (integer, unsigned or floating point) | the value is greater than 0
|
| String | it is neither empty nor NULL
|
| Boolean | it is true
|
| List | it holds at least one entry |
A numeric 0 is therefore "not set", and so is every negative number. That is what makes the
conditional form the right way to print a value that the platform may not report: modules whose
detection layer marks "no data" with a negative sentinel hand that sentinel to the format engine, so
a bare {lmp-version} in Modules/BluetoothRadio prints -2147483648
when the field is absent, while {?lmp-version}…{?} correctly treats it as unset and prints nothing.
The raw variable and the condition disagree on purpose; use the conditional form for anything that
can be absent. The test is formatArgSet() in src/common/impl/format.c.
Note: {/x} is the exact negation of {?x}, so it fires for 0 and for negative numbers too.
To terminate formatting at any point, use {-}. Everything after it in the format string is discarded.
To apply color to text, start a placeholder with # followed by terminal color codes:
"{#4;35}Colored Text{#}" → underlined magenta (pink) text
The ANSI escape sequence \e[ at the start and m at the end are automatically appended.
{#} resets all formatting to default, as does {#0}.
Named color formats are also supported:
"{#underline_magenta}Colored Text{#}"
See Color Format Specification for the supported color codes.
Setting key to exactly one space hides the key of a module, so that only its value is printed:
{
"type": "host",
"key": " " // Hides the key for the host module
}- The value must be exactly one space. Any other value is printed as the key, including two spaces (
" "). - An empty key (
"") is treated as "unset", so the module's built-in key is used instead. - The same applies to
format: an empty format string ("") is treated as "unset", so the module's built-in format is used instead. - A format string that evaluates to nothing still prints the key and the separator, followed by an empty value. It does not remove the line.
For advanced custom formatting and cross-module data manipulation, Fastfetch supports embedding Lua or QuickJS (JavaScript) scripts directly within format strings. This feature requires Fastfetch v2.64.0 or later.
Prefix your format string with lua: to execute Lua code.
-
Return Values: A
returnstatement is required to pass the final string result back to the Fastfetch module. Ifnilis returned (or implicitly omitted), the entire module's output is skipped. -
Parameters: Module-specific variables are passed via variable arguments (
...). You can assign them to local variables for better readability. - State Sharing: The Lua interpreter instance is shared across all modules, allowing you to store data in one module and access it in another.
-
Debugging: A
json_encode(table, is_pretty)helper function is injected into the Lua environment to easily dump and inspect available variables. -
Requirements: Supports Lua 5.3 through 5.5 (Lua 5.1 and LuaJIT are not supported). The Lua version is auto-detected at build time and can be verified using
fastfetch --list-features.
Basic Usage:
{
"type": "title",
"format": "lua:local args = ...; return string.format('Hello %s@%s', args.userName, args.hostName)" // Prints `Hello user@host`
}Cross-Module Data Sharing:
[
// 1. Store the shell object globally (no "return", so this module's output is skipped)
{ "type": "shell", "format": "lua:shell = ..." },
// 2. Access the stored object in a subsequent module
{ "type": "terminal", "format": "lua:return shell.prettyName .. ' in ' .. (...).prettyName" } // Prints `Zsh in Alacritty`
]Debugging Available Variables:
{
"type": "cpu",
"format": "lua:return json_encode(..., true)"
}You can use JSON5's line-continuation syntax (backslashes) to break up long script lines. Example
As an alternative to Lua, you can execute JavaScript by prefixing your format string with qjs:.
-
Return Values: No explicit
returnstatement is needed; the final result is simply the evaluated value of the script's last expression. -
Parameters: Module-specific variables are passed via the
thiscontext object. Usage is conceptually similar to Lua but utilizes JavaScript syntax. - Requirements: Requires the Fastfetch binary to be built with quickjs-ng v0.15.0 or newer.
Basic Usage:
{
"type": "title",
"format": "qjs:`Hello ${this.userName}@${this.hostName}`"
}You can access the global object via globalThis and debug available variables using JSON.stringify(this).
{ "type": "title", "format": "{user-name}@{host-name}" // Evaluates to "user@my-host" given the values "user" and "my-host" }