2023-10-26 10:26:15 +08:00
#include "fastfetch.h"
2026-01-06 09:48:38 +08:00
#include "common/color.h"
#include "common/jsonconfig.h"
#include "common/percent.h"
#include "common/stringUtils.h"
2023-10-26 10:26:15 +08:00
#include "options/display.h"
#include <unistd.h>
const char * ffOptionsParseDisplayJsonConfig ( FFOptionsDisplay * options , yyjson_val * root )
{
yyjson_val * object = yyjson_obj_get ( root , "display" );
if ( ! object ) return NULL ;
if ( ! yyjson_is_obj ( object )) return "Property 'display' must be an object" ;
2025-08-05 13:37:53 +08:00
yyjson_val * key , * val ;
2023-10-26 10:26:15 +08:00
size_t idx , max ;
2025-08-05 13:37:53 +08:00
yyjson_obj_foreach ( object , idx , max , key , val )
2023-10-26 10:26:15 +08:00
{
2025-08-05 13:37:53 +08:00
if ( unsafe_yyjson_equals_str ( key , "stat" ))
2023-10-26 10:26:15 +08:00
{
2024-08-12 16:16:47 +08:00
if ( yyjson_is_bool ( val ))
{
if ( yyjson_get_bool ( val ))
{
options -> stat = 0 ;
options -> showErrors = true ;
}
else
options -> stat = - 1 ;
}
else if ( yyjson_is_uint ( val ))
{
options -> stat = ( int ) yyjson_get_uint ( val );
2023-10-26 10:26:15 +08:00
options -> showErrors = true ;
2024-08-12 16:16:47 +08:00
}
else
return "display.stat must be a boolean or a positive integer" ;
2023-10-26 10:26:15 +08:00
}
2025-08-05 13:37:53 +08:00
else if ( unsafe_yyjson_equals_str ( key , "pipe" ))
2023-10-26 10:26:15 +08:00
options -> pipe = yyjson_get_bool ( val );
2025-08-05 13:37:53 +08:00
else if ( unsafe_yyjson_equals_str ( key , "showErrors" ))
2023-10-26 10:26:15 +08:00
options -> showErrors = yyjson_get_bool ( val );
2025-08-05 13:37:53 +08:00
else if ( unsafe_yyjson_equals_str ( key , "disableLinewrap" ))
2023-10-26 10:26:15 +08:00
options -> disableLinewrap = yyjson_get_bool ( val );
2025-08-05 13:37:53 +08:00
else if ( unsafe_yyjson_equals_str ( key , "hideCursor" ))
2023-10-26 10:26:15 +08:00
options -> hideCursor = yyjson_get_bool ( val );
2025-08-05 13:37:53 +08:00
else if ( unsafe_yyjson_equals_str ( key , "separator" ))
2025-08-02 17:41:19 +08:00
ffStrbufSetJsonVal ( & options -> keyValueSeparator , val );
2025-08-05 13:37:53 +08:00
else if ( unsafe_yyjson_equals_str ( key , "color" ))
2023-10-26 10:26:15 +08:00
{
if ( yyjson_is_str ( val ))
{
2025-08-05 13:37:53 +08:00
ffOptionParseColor ( unsafe_yyjson_get_str ( val ), & options -> colorKeys );
2023-10-26 10:26:15 +08:00
ffStrbufSet ( & options -> colorTitle , & options -> colorKeys );
}
else if ( yyjson_is_obj ( val ))
{
2025-08-02 17:41:19 +08:00
yyjson_val * colorKeys = yyjson_obj_get ( val , "keys" );
2023-10-26 10:26:15 +08:00
if ( colorKeys )
2025-08-02 17:41:19 +08:00
ffOptionParseColor ( yyjson_get_str ( colorKeys ), & options -> colorKeys );
yyjson_val * colorTitle = yyjson_obj_get ( val , "title" );
2023-10-26 10:26:15 +08:00
if ( colorTitle )
2025-08-02 17:41:19 +08:00
ffOptionParseColor ( yyjson_get_str ( colorTitle ), & options -> colorTitle );
yyjson_val * colorOutput = yyjson_obj_get ( val , "output" );
2024-05-08 15:01:57 +08:00
if ( colorOutput )
2025-08-02 17:41:19 +08:00
ffOptionParseColor ( yyjson_get_str ( colorOutput ), & options -> colorOutput );
yyjson_val * colorSeparator = yyjson_obj_get ( val , "separator" );
2024-05-28 16:13:06 +08:00
if ( colorSeparator )
2025-08-02 17:41:19 +08:00
ffOptionParseColor ( yyjson_get_str ( colorSeparator ), & options -> colorSeparator );
2023-10-26 10:26:15 +08:00
}
else
return "display.color must be either a string or an object" ;
}
2025-08-05 13:37:53 +08:00
else if ( unsafe_yyjson_equals_str ( key , "brightColor" ))
2023-10-26 10:26:15 +08:00
options -> brightColor = yyjson_get_bool ( val );
2025-08-05 13:37:53 +08:00
else if ( unsafe_yyjson_equals_str ( key , "duration" ))
2025-07-30 14:30:36 +08:00
{
if ( ! yyjson_is_obj ( val ))
return "display.duration must be an object" ;
yyjson_val * abbreviation = yyjson_obj_get ( val , "abbreviation" );
if ( abbreviation ) options -> durationAbbreviation = yyjson_get_bool ( abbreviation );
yyjson_val * spaceBeforeUnit = yyjson_obj_get ( val , "spaceBeforeUnit" );
if ( spaceBeforeUnit )
{
int value ;
const char * error = ffJsonConfigParseEnum ( spaceBeforeUnit , & value , ( FFKeyValuePair []) {
{ "default" , FF_SPACE_BEFORE_UNIT_DEFAULT },
{ "always" , FF_SPACE_BEFORE_UNIT_ALWAYS },
{ "never" , FF_SPACE_BEFORE_UNIT_NEVER },
{},
});
if ( error ) return error ;
options -> durationSpaceBeforeUnit = ( FFSpaceBeforeUnitType ) value ;
}
}
2025-08-05 13:37:53 +08:00
else if ( unsafe_yyjson_equals_str ( key , "size" ))
2023-10-26 10:26:15 +08:00
{
2023-10-29 00:17:24 +08:00
if ( ! yyjson_is_obj ( val ))
return "display.size must be an object" ;
yyjson_val * maxPrefix = yyjson_obj_get ( val , "maxPrefix" );
if ( maxPrefix )
{
int value ;
const char * error = ffJsonConfigParseEnum ( maxPrefix , & value , ( FFKeyValuePair []) {
{ "B" , 0 },
{ "kB" , 1 },
{ "MB" , 2 },
{ "GB" , 3 },
{ "TB" , 4 },
{ "PB" , 5 },
{ "EB" , 6 },
{ "ZB" , 7 },
{ "YB" , 8 },
{}
});
if ( error ) return error ;
options -> sizeMaxPrefix = ( uint8_t ) value ;
}
2024-07-22 10:51:27 +08:00
yyjson_val * binaryPrefix = yyjson_obj_get ( val , "binaryPrefix" );
if ( binaryPrefix )
{
int value ;
const char * error = ffJsonConfigParseEnum ( binaryPrefix , & value , ( FFKeyValuePair []) {
2024-07-22 10:59:23 +08:00
{ "iec" , FF_SIZE_BINARY_PREFIX_TYPE_IEC },
{ "si" , FF_SIZE_BINARY_PREFIX_TYPE_SI },
{ "jedec" , FF_SIZE_BINARY_PREFIX_TYPE_JEDEC },
2024-07-22 10:51:27 +08:00
{},
});
if ( error ) return error ;
2024-07-22 10:59:23 +08:00
options -> sizeBinaryPrefix = ( FFSizeBinaryPrefixType ) value ;
2024-07-22 10:51:27 +08:00
}
2023-10-29 00:17:24 +08:00
yyjson_val * ndigits = yyjson_obj_get ( val , "ndigits" );
2025-09-03 14:23:59 +08:00
if ( ndigits )
{
if ( ! yyjson_is_uint ( ndigits ))
return "display.size.ndigits must be an unsigned integer" ;
uint64_t val = yyjson_get_uint ( ndigits );
if ( val > 9 )
return "display.size.ndigits must be between 0 and 9" ;
options -> sizeNdigits = ( uint8_t ) val ;
}
2025-07-30 14:30:36 +08:00
yyjson_val * spaceBeforeUnit = yyjson_obj_get ( val , "spaceBeforeUnit" );
if ( spaceBeforeUnit )
{
int value ;
const char * error = ffJsonConfigParseEnum ( spaceBeforeUnit , & value , ( FFKeyValuePair []) {
{ "default" , FF_SPACE_BEFORE_UNIT_DEFAULT },
{ "always" , FF_SPACE_BEFORE_UNIT_ALWAYS },
{ "never" , FF_SPACE_BEFORE_UNIT_NEVER },
{},
});
if ( error ) return error ;
options -> sizeSpaceBeforeUnit = ( FFSpaceBeforeUnitType ) value ;
}
2023-10-26 10:26:15 +08:00
}
2025-08-05 13:37:53 +08:00
else if ( unsafe_yyjson_equals_str ( key , "temp" ))
2023-10-26 10:26:15 +08:00
{
2024-02-26 10:46:13 +08:00
if ( ! yyjson_is_obj ( val ))
2024-02-27 13:11:39 +08:00
return "display.temp must be an object" ;
2024-02-26 10:46:13 +08:00
yyjson_val * unit = yyjson_obj_get ( val , "unit" );
if ( unit )
{
int value ;
const char * error = ffJsonConfigParseEnum ( unit , & value , ( FFKeyValuePair []) {
2025-02-14 10:31:13 +08:00
{ "DEFAULT" , FF_TEMPERATURE_UNIT_DEFAULT },
{ "D" , FF_TEMPERATURE_UNIT_DEFAULT },
2024-02-26 10:46:13 +08:00
{ "CELSIUS" , FF_TEMPERATURE_UNIT_CELSIUS },
{ "C" , FF_TEMPERATURE_UNIT_CELSIUS },
{ "FAHRENHEIT" , FF_TEMPERATURE_UNIT_FAHRENHEIT },
{ "F" , FF_TEMPERATURE_UNIT_FAHRENHEIT },
{ "KELVIN" , FF_TEMPERATURE_UNIT_KELVIN },
{ "K" , FF_TEMPERATURE_UNIT_KELVIN },
{},
});
if ( error ) return error ;
2024-05-09 08:46:52 +08:00
options -> tempUnit = ( FFTemperatureUnit ) value ;
2024-02-26 10:46:13 +08:00
}
yyjson_val * ndigits = yyjson_obj_get ( val , "ndigits" );
2025-09-03 14:23:59 +08:00
if ( ndigits )
{
if ( ! yyjson_is_uint ( ndigits ))
return "display.temperature.ndigits must be an unsigned integer" ;
uint64_t val = yyjson_get_uint ( ndigits );
if ( val > 9 )
return "display.temperature.ndigits must be between 0 and 9" ;
options -> tempNdigits = ( uint8_t ) val ;
}
2024-02-26 10:46:13 +08:00
yyjson_val * color = yyjson_obj_get ( val , "color" );
if ( color )
{
if ( ! yyjson_is_obj ( color ))
return "display.temperature.color must be an object" ;
yyjson_val * green = yyjson_obj_get ( color , "green" );
2024-02-27 13:11:39 +08:00
if ( green ) ffOptionParseColor ( yyjson_get_str ( green ), & options -> tempColorGreen );
2024-02-26 10:46:13 +08:00
yyjson_val * yellow = yyjson_obj_get ( color , "yellow" );
2024-02-27 13:11:39 +08:00
if ( yellow ) ffOptionParseColor ( yyjson_get_str ( yellow ), & options -> tempColorYellow );
2024-02-26 10:46:13 +08:00
yyjson_val * red = yyjson_obj_get ( color , "red" );
2024-02-27 13:11:39 +08:00
if ( red ) ffOptionParseColor ( yyjson_get_str ( red ), & options -> tempColorRed );
2024-02-26 10:46:13 +08:00
}
2025-07-30 14:30:36 +08:00
yyjson_val * spaceBeforeUnit = yyjson_obj_get ( val , "spaceBeforeUnit" );
if ( spaceBeforeUnit )
{
int value ;
const char * error = ffJsonConfigParseEnum ( spaceBeforeUnit , & value , ( FFKeyValuePair []) {
{ "default" , FF_SPACE_BEFORE_UNIT_DEFAULT },
{ "always" , FF_SPACE_BEFORE_UNIT_ALWAYS },
{ "never" , FF_SPACE_BEFORE_UNIT_NEVER },
{},
});
if ( error ) return error ;
options -> tempSpaceBeforeUnit = ( FFSpaceBeforeUnitType ) value ;
}
2023-10-26 10:26:15 +08:00
}
2025-08-05 13:37:53 +08:00
else if ( unsafe_yyjson_equals_str ( key , "percent" ))
2023-10-29 00:17:24 +08:00
{
if ( ! yyjson_is_obj ( val ))
return "display.percent must be an object" ;
yyjson_val * type = yyjson_obj_get ( val , "type" );
2024-11-14 14:21:55 +08:00
if ( type )
{
const char * error = ffPercentParseTypeJsonConfig ( type , & options -> percentType );
if ( error ) return error ;
}
2023-10-29 00:17:24 +08:00
yyjson_val * ndigits = yyjson_obj_get ( val , "ndigits" );
2025-09-03 14:23:59 +08:00
if ( ndigits )
{
if ( ! yyjson_is_uint ( ndigits ))
return "display.percent.ndigits must be an unsigned integer" ;
uint64_t val = yyjson_get_uint ( ndigits );
if ( val > 9 )
return "display.percent.ndigits must be between 0 and 9" ;
options -> percentNdigits = ( uint8_t ) val ;
}
2024-01-20 19:59:13 +08:00
yyjson_val * color = yyjson_obj_get ( val , "color" );
if ( color )
{
if ( ! yyjson_is_obj ( color ))
return "display.percent.color must be an object" ;
yyjson_val * green = yyjson_obj_get ( color , "green" );
if ( green ) ffOptionParseColor ( yyjson_get_str ( green ), & options -> percentColorGreen );
yyjson_val * yellow = yyjson_obj_get ( color , "yellow" );
if ( yellow ) ffOptionParseColor ( yyjson_get_str ( yellow ), & options -> percentColorYellow );
yyjson_val * red = yyjson_obj_get ( color , "red" );
if ( red ) ffOptionParseColor ( yyjson_get_str ( red ), & options -> percentColorRed );
}
2025-07-30 14:30:36 +08:00
yyjson_val * spaceBeforeUnit = yyjson_obj_get ( val , "spaceBeforeUnit" );
if ( spaceBeforeUnit )
{
int value ;
const char * error = ffJsonConfigParseEnum ( spaceBeforeUnit , & value , ( FFKeyValuePair []) {
{ "default" , FF_SPACE_BEFORE_UNIT_DEFAULT },
{ "always" , FF_SPACE_BEFORE_UNIT_ALWAYS },
{ "never" , FF_SPACE_BEFORE_UNIT_NEVER },
{},
});
if ( error ) return error ;
options -> percentSpaceBeforeUnit = ( FFSpaceBeforeUnitType ) value ;
}
2025-07-30 15:06:16 +08:00
yyjson_val * width = yyjson_obj_get ( val , "width" );
if ( width ) options -> percentWidth = ( uint8_t ) yyjson_get_uint ( width );
2023-10-29 00:17:24 +08:00
}
2025-08-05 13:37:53 +08:00
else if ( unsafe_yyjson_equals_str ( key , "bar" ))
2023-10-26 10:26:15 +08:00
{
if ( yyjson_is_obj ( val ))
{
2025-08-01 15:12:30 +08:00
yyjson_val * char_ = yyjson_obj_get ( val , "char" );
if ( char_ )
{
if ( ! yyjson_is_obj ( char_ )) return "display.bar.char must be an object" ;
2024-06-06 16:36:57 +08:00
2025-08-02 17:41:19 +08:00
yyjson_val * charElapsed = yyjson_obj_get ( char_ , "elapsed" );
2025-08-01 15:12:30 +08:00
if ( charElapsed )
2025-08-02 17:41:19 +08:00
ffStrbufSetJsonVal ( & options -> barCharElapsed , charElapsed );
2023-10-26 10:26:15 +08:00
2025-08-02 17:41:19 +08:00
yyjson_val * charTotal = yyjson_obj_get ( char_ , "total" );
2025-08-01 15:12:30 +08:00
if ( charTotal )
2025-08-02 17:41:19 +08:00
ffStrbufSetJsonVal ( & options -> barCharTotal , charTotal );
2025-08-01 15:12:30 +08:00
}
else
{
2025-08-02 17:41:19 +08:00
yyjson_val * charElapsed = yyjson_obj_get ( val , "charElapsed" );
2025-08-01 15:12:30 +08:00
if ( charElapsed )
return "display.bar.charElapsed has been renamed to display.bar.char.elapsed." ;
2025-08-01 10:51:26 +08:00
2025-08-02 17:41:19 +08:00
yyjson_val * charTotal = yyjson_obj_get ( val , "charTotal" );
2025-08-01 15:12:30 +08:00
if ( charTotal )
return "display.bar.charTotal has been renamed to display.bar.char.total." ;
}
2025-08-01 10:51:26 +08:00
2025-08-01 15:12:30 +08:00
yyjson_val * border = yyjson_obj_get ( val , "border" );
if ( border )
{
if ( yyjson_is_null ( border ))
{
ffStrbufClear ( & options -> barBorderLeft );
ffStrbufClear ( & options -> barBorderRight );
ffStrbufClear ( & options -> barBorderLeftElapsed );
ffStrbufClear ( & options -> barBorderRightElapsed );
}
else
{
if ( ! yyjson_is_obj ( border )) return "display.bar.border must be an object" ;
yyjson_val * borderLeft = yyjson_obj_get ( border , "left" );
if ( borderLeft )
2025-08-02 17:41:19 +08:00
ffStrbufSetJsonVal ( & options -> barBorderLeft , borderLeft );
2025-08-01 15:12:30 +08:00
yyjson_val * borderRight = yyjson_obj_get ( border , "right" );
if ( borderRight )
2025-08-02 17:41:19 +08:00
ffStrbufSetJsonVal ( & options -> barBorderRight , borderRight );
2025-08-01 15:12:30 +08:00
yyjson_val * borderLeftElapsed = yyjson_obj_get ( border , "leftElapsed" );
if ( borderLeftElapsed )
2025-08-02 17:41:19 +08:00
ffStrbufSetJsonVal ( & options -> barBorderLeftElapsed , borderLeftElapsed );
2025-08-01 15:12:30 +08:00
yyjson_val * borderRightElapsed = yyjson_obj_get ( border , "rightElapsed" );
if ( borderRightElapsed )
2025-08-02 17:41:19 +08:00
ffStrbufSetJsonVal ( & options -> barBorderRightElapsed , borderRightElapsed );
2025-08-01 15:12:30 +08:00
}
}
else
{
yyjson_val * borderLeft = yyjson_obj_get ( val , "borderLeft" );
if ( borderLeft )
return "display.bar.borderLeft has been renamed to display.bar.border.left." ;
2025-08-01 13:50:02 +08:00
2025-08-01 15:12:30 +08:00
yyjson_val * borderRight = yyjson_obj_get ( val , "borderRight" );
if ( borderRight )
return "display.bar.borderRight has been renamed to display.bar.border.right." ;
}
2025-08-01 13:50:02 +08:00
2025-08-01 15:12:30 +08:00
yyjson_val * color = yyjson_obj_get ( val , "color" );
if ( color )
{
if ( yyjson_is_null ( color ))
{
ffStrbufClear ( & options -> barColorElapsed );
ffStrbufClear ( & options -> barColorTotal );
ffStrbufClear ( & options -> barColorBorder );
}
else
{
if ( ! yyjson_is_obj ( color )) return "display.bar.color must be an object" ;
yyjson_val * colorElapsed = yyjson_obj_get ( color , "elapsed" );
2025-08-04 16:46:28 +08:00
if ( colorElapsed )
{
const char * value = yyjson_get_str ( colorElapsed );
if ( ! value )
ffStrbufClear ( & options -> barColorElapsed );
else if ( ffStrEqualsIgnCase ( value , "auto" ))
ffStrbufSetStatic ( & options -> barColorElapsed , "auto" );
else
ffOptionParseColor ( value , & options -> barColorElapsed );
}
2025-08-01 15:12:30 +08:00
yyjson_val * colorTotal = yyjson_obj_get ( color , "total" );
if ( colorTotal ) ffOptionParseColor ( yyjson_get_str ( colorTotal ), & options -> barColorTotal );
yyjson_val * colorBorder = yyjson_obj_get ( color , "border" );
if ( colorBorder ) ffOptionParseColor ( yyjson_get_str ( colorBorder ), & options -> barColorBorder );
}
}
2025-08-01 13:50:02 +08:00
2023-10-26 10:26:15 +08:00
yyjson_val * width = yyjson_obj_get ( val , "width" );
if ( width )
options -> barWidth = ( uint8_t ) yyjson_get_uint ( width );
}
else
return "display.bar must be an object" ;
}
2025-08-05 13:37:53 +08:00
else if ( unsafe_yyjson_equals_str ( key , "fraction" ))
2025-07-16 10:30:45 +08:00
{
if ( yyjson_is_obj ( val ))
{
yyjson_val * ndigits = yyjson_obj_get ( val , "ndigits" );
if ( ndigits )
{
if ( yyjson_is_null ( ndigits ))
options -> fractionNdigits = - 1 ;
2025-09-02 14:44:15 +08:00
else
{
if ( ! yyjson_is_int ( ndigits ))
return "display.fraction.ndigits must be an integer" ;
2025-09-03 14:23:59 +08:00
int64_t val = yyjson_get_int ( ndigits );
if ( val < - 1 || val > 9 )
return "display.fraction.ndigits must be between -1 and 9" ;
options -> fractionNdigits = ( int8_t ) val ;
2025-09-02 14:44:15 +08:00
}
2025-07-16 10:30:45 +08:00
}
2025-09-02 14:12:58 +08:00
yyjson_val * trailingZeros = yyjson_obj_get ( val , "trailingZeros" );
if ( trailingZeros )
{
if ( yyjson_is_null ( trailingZeros ))
options -> fractionTrailingZeros = FF_FRACTION_TRAILING_ZEROS_TYPE_DEFAULT ;
else
{
int value ;
const char * error = ffJsonConfigParseEnum ( trailingZeros , & value , ( FFKeyValuePair []) {
{ "default" , FF_FRACTION_TRAILING_ZEROS_TYPE_DEFAULT },
2025-09-05 12:27:03 +08:00
{ "always" , FF_FRACTION_TRAILING_ZEROS_TYPE_ALWAYS },
{ "never" , FF_FRACTION_TRAILING_ZEROS_TYPE_NEVER },
2025-09-02 14:12:58 +08:00
{},
});
if ( error ) return error ;
options -> fractionTrailingZeros = ( FFFractionTrailingZerosType ) value ;
}
}
2025-07-16 10:30:45 +08:00
}
else
return "display.fraction must be an object" ;
}
2025-08-05 13:37:53 +08:00
else if ( unsafe_yyjson_equals_str ( key , "noBuffer" ))
2023-10-26 10:26:15 +08:00
options -> noBuffer = yyjson_get_bool ( val );
2025-08-05 13:37:53 +08:00
else if ( unsafe_yyjson_equals_str ( key , "key" ))
2024-07-24 11:13:37 +08:00
{
2024-07-24 15:12:25 +08:00
if ( yyjson_is_obj ( val ))
{
yyjson_val * width = yyjson_obj_get ( val , "width" );
if ( width )
options -> keyWidth = ( uint16_t ) yyjson_get_uint ( width );
yyjson_val * type = yyjson_obj_get ( val , "type" );
if ( type )
{
int value ;
const char * error = ffJsonConfigParseEnum ( type , & value , ( FFKeyValuePair []) {
{ "none" , FF_MODULE_KEY_TYPE_NONE },
{ "string" , FF_MODULE_KEY_TYPE_STRING },
{ "icon" , FF_MODULE_KEY_TYPE_ICON },
{ "both" , FF_MODULE_KEY_TYPE_BOTH },
2025-10-13 09:54:34 +08:00
{ "both-0" , FF_MODULE_KEY_TYPE_BOTH_0 },
{ "both-1" , FF_MODULE_KEY_TYPE_BOTH_1 },
{ "both-2" , FF_MODULE_KEY_TYPE_BOTH_2 },
{ "both-3" , FF_MODULE_KEY_TYPE_BOTH_3 },
{ "both-4" , FF_MODULE_KEY_TYPE_BOTH_4 },
2024-07-24 15:12:25 +08:00
{}
});
if ( error ) return error ;
options -> keyType = ( uint8_t ) value ;
}
yyjson_val * paddingLeft = yyjson_obj_get ( val , "paddingLeft" );
if ( paddingLeft )
options -> keyPaddingLeft = ( uint16_t ) yyjson_get_uint ( paddingLeft );
}
else
return "display.key must be an object" ;
2024-07-24 11:13:37 +08:00
}
2025-08-05 13:37:53 +08:00
else if ( unsafe_yyjson_equals_str ( key , "constants" ))
2024-07-15 11:00:15 +08:00
{
if ( ! yyjson_is_arr ( val ))
return "display.constants must be an array" ;
yyjson_val * item ;
size_t idx , max ;
yyjson_arr_foreach ( val , idx , max , item )
2025-08-02 17:41:19 +08:00
ffStrbufInitJsonVal ( ffListAdd ( & options -> constants ), item );
2024-07-15 11:00:15 +08:00
}
2025-08-05 13:37:53 +08:00
else if ( unsafe_yyjson_equals_str ( key , "freq" ))
2024-07-17 14:42:09 +08:00
{
if ( ! yyjson_is_obj ( val ))
return "display.freq must be an object" ;
yyjson_val * ndigits = yyjson_obj_get ( val , "ndigits" );
2025-09-03 14:23:59 +08:00
if ( ndigits )
{
if ( yyjson_is_null ( ndigits ))
options -> freqNdigits = - 1 ;
else
{
if ( ! yyjson_is_int ( ndigits ))
return "display.freq.ndigits must be an integer" ;
int64_t val = yyjson_get_int ( ndigits );
if ( val < - 1 || val > 9 )
return "display.freq.ndigits must be between -1 and 9" ;
options -> freqNdigits = ( int8_t ) val ;
}
}
2025-07-30 14:30:36 +08:00
yyjson_val * spaceBeforeUnit = yyjson_obj_get ( val , "spaceBeforeUnit" );
if ( spaceBeforeUnit )
{
int value ;
const char * error = ffJsonConfigParseEnum ( spaceBeforeUnit , & value , ( FFKeyValuePair []) {
{ "default" , FF_SPACE_BEFORE_UNIT_DEFAULT },
{ "always" , FF_SPACE_BEFORE_UNIT_ALWAYS },
{ "never" , FF_SPACE_BEFORE_UNIT_NEVER },
{},
});
if ( error ) return error ;
options -> freqSpaceBeforeUnit = ( FFSpaceBeforeUnitType ) value ;
}
2024-07-17 14:42:09 +08:00
}
2023-10-26 10:26:15 +08:00
else
return "Unknown display property" ;
}
return NULL ;
}
static inline void optionCheckString ( const char * key , const char * value , FFstrbuf * buffer )
{
if ( value == NULL )
{
fprintf ( stderr , "Error: usage: %s <str> \n " , key );
exit ( 477 );
}
ffStrbufEnsureFree ( buffer , 63 ); //This is not needed, as ffStrbufSetS will resize capacity if needed, but giving a higher start should improve performance
}
bool ffOptionsParseDisplayCommandLine ( FFOptionsDisplay * options , const char * key , const char * value )
{
if ( ffStrEqualsIgnCase ( key , "--stat" ))
{
2024-08-12 16:16:47 +08:00
if ( ffOptionParseBoolean ( value ))
{
options -> stat = 0 ;
2023-10-26 10:26:15 +08:00
options -> showErrors = true ;
2024-08-12 16:16:47 +08:00
}
else if ( value )
{
char * end ;
uint32_t num = ( uint32_t ) strtoul ( value , & end , 10 );
if ( * end == '\0' )
{
options -> stat = ( int32_t ) num ;
options -> showErrors = true ;
}
else
options -> stat = - 1 ;
}
else
options -> stat = - 1 ;
2023-10-26 10:26:15 +08:00
}
else if ( ffStrEqualsIgnCase ( key , "--pipe" ))
options -> pipe = ffOptionParseBoolean ( value );
else if ( ffStrEqualsIgnCase ( key , "--show-errors" ))
options -> showErrors = ffOptionParseBoolean ( value );
2025-03-15 19:49:51 +08:00
else if ( ffStrEqualsIgnCase ( key , "--debug" ))
2025-08-28 09:32:01 +08:00
#ifndef NDEBUG
2025-03-15 19:49:51 +08:00
options -> debugMode = ffOptionParseBoolean ( value );
2025-08-28 09:32:01 +08:00
#else
{
fprintf ( stderr , "--debug is only available in debug builds \n " );
exit ( 477 );
}
2025-03-15 19:49:51 +08:00
#endif
2023-10-26 10:26:15 +08:00
else if ( ffStrEqualsIgnCase ( key , "--disable-linewrap" ))
options -> disableLinewrap = ffOptionParseBoolean ( value );
else if ( ffStrEqualsIgnCase ( key , "--hide-cursor" ))
options -> hideCursor = ffOptionParseBoolean ( value );
else if ( ffStrEqualsIgnCase ( key , "--separator" ))
ffOptionParseString ( key , value , & options -> keyValueSeparator );
else if ( ffStrEqualsIgnCase ( key , "--color" ))
{
optionCheckString ( key , value , & options -> colorKeys );
ffOptionParseColor ( value , & options -> colorKeys );
ffStrbufSet ( & options -> colorTitle , & options -> colorKeys );
}
else if ( ffStrStartsWithIgnCase ( key , "--color-" ))
{
const char * subkey = key + strlen ( "--color-" );
if ( ffStrEqualsIgnCase ( subkey , "keys" ))
{
optionCheckString ( key , value , & options -> colorKeys );
ffOptionParseColor ( value , & options -> colorKeys );
}
else if ( ffStrEqualsIgnCase ( subkey , "title" ))
{
optionCheckString ( key , value , & options -> colorTitle );
ffOptionParseColor ( value , & options -> colorTitle );
}
2024-05-08 15:01:57 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "output" ))
{
optionCheckString ( key , value , & options -> colorOutput );
ffOptionParseColor ( value , & options -> colorOutput );
}
2024-05-28 16:13:06 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "separator" ))
{
optionCheckString ( key , value , & options -> colorSeparator );
ffOptionParseColor ( value , & options -> colorSeparator );
}
2023-10-26 10:26:15 +08:00
else
return false ;
}
2024-07-24 15:12:25 +08:00
else if ( ffStrStartsWithIgnCase ( key , "--key-" ))
2024-07-24 11:13:37 +08:00
{
2024-07-24 15:12:25 +08:00
const char * subkey = key + strlen ( "--key-" );
if ( ffStrEqualsIgnCase ( subkey , "width" ))
options -> keyWidth = ( uint16_t ) ffOptionParseUInt32 ( key , value );
else if ( ffStrEqualsIgnCase ( subkey , "type" ))
{
options -> keyType = ( FFModuleKeyType ) ffOptionParseEnum ( key , value , ( FFKeyValuePair []) {
{ "none" , FF_MODULE_KEY_TYPE_NONE },
{ "string" , FF_MODULE_KEY_TYPE_STRING },
{ "icon" , FF_MODULE_KEY_TYPE_ICON },
{ "both" , FF_MODULE_KEY_TYPE_BOTH },
2025-10-13 09:54:34 +08:00
{ "both-0" , FF_MODULE_KEY_TYPE_BOTH_0 },
{ "both-1" , FF_MODULE_KEY_TYPE_BOTH_1 },
{ "both-2" , FF_MODULE_KEY_TYPE_BOTH_2 },
{ "both-3" , FF_MODULE_KEY_TYPE_BOTH_3 },
{ "both-4" , FF_MODULE_KEY_TYPE_BOTH_4 },
2024-07-24 15:12:25 +08:00
{}
});
}
else if ( ffStrEqualsIgnCase ( subkey , "padding-left" ))
options -> keyPaddingLeft = ( uint16_t ) ffOptionParseUInt32 ( key , value );
else
return false ;
2024-07-24 11:13:37 +08:00
}
2023-10-26 10:26:15 +08:00
else if ( ffStrEqualsIgnCase ( key , "--bright-color" ))
options -> brightColor = ffOptionParseBoolean ( value );
else if ( ffStrEqualsIgnCase ( key , "--binary-prefix" ))
{
2024-07-22 10:51:27 +08:00
fprintf ( stderr , "--binary-prefix has been renamed to --size-binary-prefix \n " );
exit ( 477 );
2023-10-26 10:26:15 +08:00
}
2025-07-30 14:30:36 +08:00
else if ( ffStrStartsWithIgnCase ( key , "--duration-" ))
{
const char * subkey = key + strlen ( "--duration-" );
if ( ffStrEqualsIgnCase ( subkey , "abbreviation" ))
options -> durationAbbreviation = ffOptionParseBoolean ( value );
else if ( ffStrEqualsIgnCase ( subkey , "space-before-unit" ))
{
options -> durationSpaceBeforeUnit = ( FFSpaceBeforeUnitType ) ffOptionParseEnum ( key , value , ( FFKeyValuePair []) {
{ "default" , FF_SPACE_BEFORE_UNIT_DEFAULT },
{ "always" , FF_SPACE_BEFORE_UNIT_ALWAYS },
{ "never" , FF_SPACE_BEFORE_UNIT_NEVER },
{},
});
}
else
return false ;
}
2024-07-22 10:51:27 +08:00
else if ( ffStrStartsWithIgnCase ( key , "--size-" ))
2023-10-26 10:26:15 +08:00
{
2024-07-22 10:51:27 +08:00
const char * subkey = key + strlen ( "--size-" );
if ( ffStrEqualsIgnCase ( subkey , "binary-prefix" ))
{
2024-07-22 10:59:23 +08:00
options -> sizeBinaryPrefix = ( FFSizeBinaryPrefixType ) ffOptionParseEnum ( key , value , ( FFKeyValuePair []) {
{ "iec" , FF_SIZE_BINARY_PREFIX_TYPE_IEC },
{ "si" , FF_SIZE_BINARY_PREFIX_TYPE_SI },
{ "jedec" , FF_SIZE_BINARY_PREFIX_TYPE_JEDEC },
2024-07-22 10:51:27 +08:00
{}
});
}
else if ( ffStrEqualsIgnCase ( subkey , "ndigits" ))
options -> sizeNdigits = ( uint8_t ) ffOptionParseUInt32 ( key , value );
else if ( ffStrEqualsIgnCase ( subkey , "max-prefix" ))
{
options -> sizeMaxPrefix = ( uint8_t ) ffOptionParseEnum ( key , value , ( FFKeyValuePair []) {
{ "B" , 0 },
{ "kB" , 1 },
{ "MB" , 2 },
{ "GB" , 3 },
{ "TB" , 4 },
{ "PB" , 5 },
{ "EB" , 6 },
{ "ZB" , 7 },
{ "YB" , 8 },
{}
});
}
2025-07-30 14:30:36 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "space-before-unit" ))
{
options -> sizeSpaceBeforeUnit = ( FFSpaceBeforeUnitType ) ffOptionParseEnum ( key , value , ( FFKeyValuePair []) {
{ "default" , FF_SPACE_BEFORE_UNIT_DEFAULT },
{ "always" , FF_SPACE_BEFORE_UNIT_ALWAYS },
{ "never" , FF_SPACE_BEFORE_UNIT_NEVER },
{},
});
}
2024-07-22 10:51:27 +08:00
else
return false ;
2023-10-26 10:26:15 +08:00
}
2024-05-09 08:46:52 +08:00
else if ( ffStrStartsWithIgnCase ( key , "--temp-" ))
2023-10-26 10:26:15 +08:00
{
2024-05-09 08:46:52 +08:00
const char * subkey = key + strlen ( "--temp-" );
2024-02-26 10:46:13 +08:00
if ( ffStrEqualsIgnCase ( subkey , "unit" ))
{
2024-05-09 08:46:52 +08:00
options -> tempUnit = ( FFTemperatureUnit ) ffOptionParseEnum ( key , value , ( FFKeyValuePair []) {
2025-02-14 10:31:13 +08:00
{ "DEFAULT" , FF_TEMPERATURE_UNIT_DEFAULT },
{ "D" , FF_TEMPERATURE_UNIT_DEFAULT },
2024-02-26 10:46:13 +08:00
{ "CELSIUS" , FF_TEMPERATURE_UNIT_CELSIUS },
{ "C" , FF_TEMPERATURE_UNIT_CELSIUS },
{ "FAHRENHEIT" , FF_TEMPERATURE_UNIT_FAHRENHEIT },
{ "F" , FF_TEMPERATURE_UNIT_FAHRENHEIT },
{ "KELVIN" , FF_TEMPERATURE_UNIT_KELVIN },
{ "K" , FF_TEMPERATURE_UNIT_KELVIN },
{},
});
}
else if ( ffStrEqualsIgnCase ( subkey , "ndigits" ))
2024-02-27 13:11:39 +08:00
options -> tempNdigits = ( uint8_t ) ffOptionParseUInt32 ( key , value );
2024-02-26 10:46:13 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "color-green" ))
2024-02-27 13:11:39 +08:00
ffOptionParseColor ( value , & options -> tempColorGreen );
2024-02-26 10:46:13 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "color-yellow" ))
2024-02-27 13:11:39 +08:00
ffOptionParseColor ( value , & options -> tempColorYellow );
2024-02-26 10:46:13 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "color-red" ))
2024-02-27 13:11:39 +08:00
ffOptionParseColor ( value , & options -> tempColorRed );
2025-07-30 14:30:36 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "space-before-unit" ))
{
options -> tempSpaceBeforeUnit = ( FFSpaceBeforeUnitType ) ffOptionParseEnum ( key , value , ( FFKeyValuePair []) {
{ "default" , FF_SPACE_BEFORE_UNIT_DEFAULT },
{ "always" , FF_SPACE_BEFORE_UNIT_ALWAYS },
{ "never" , FF_SPACE_BEFORE_UNIT_NEVER },
{},
});
}
2024-02-26 10:46:13 +08:00
else
return false ;
2023-10-26 10:26:15 +08:00
}
2024-01-20 19:59:13 +08:00
else if ( ffStrStartsWithIgnCase ( key , "--percent-" ))
{
const char * subkey = key + strlen ( "--percent-" );
if ( ffStrEqualsIgnCase ( subkey , "type" ))
options -> percentType = ( uint8_t ) ffOptionParseUInt32 ( key , value );
else if ( ffStrEqualsIgnCase ( subkey , "ndigits" ))
options -> percentNdigits = ( uint8_t ) ffOptionParseUInt32 ( key , value );
else if ( ffStrEqualsIgnCase ( subkey , "color-green" ))
ffOptionParseColor ( value , & options -> percentColorGreen );
else if ( ffStrEqualsIgnCase ( subkey , "color-yellow" ))
ffOptionParseColor ( value , & options -> percentColorYellow );
else if ( ffStrEqualsIgnCase ( subkey , "color-red" ))
ffOptionParseColor ( value , & options -> percentColorRed );
2025-07-30 14:30:36 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "space-before-unit" ))
{
options -> percentSpaceBeforeUnit = ( FFSpaceBeforeUnitType ) ffOptionParseEnum ( key , value , ( FFKeyValuePair []) {
{ "default" , FF_SPACE_BEFORE_UNIT_DEFAULT },
{ "always" , FF_SPACE_BEFORE_UNIT_ALWAYS },
{ "never" , FF_SPACE_BEFORE_UNIT_NEVER },
{},
});
}
2025-07-30 15:06:16 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "width" ))
options -> percentWidth = ( uint8_t ) ffOptionParseUInt32 ( key , value );
2024-01-20 19:59:13 +08:00
else
return false ;
}
2025-07-16 10:30:45 +08:00
else if ( ffStrEqualsIgnCase ( key , "--fraction-ndigits" ))
options -> fractionNdigits = ( int8_t ) ffOptionParseInt32 ( key , value );
2025-09-03 14:20:23 +08:00
else if ( ffStrEqualsIgnCase ( key , "--fraction-trailing-zeros" ))
{
options -> fractionTrailingZeros = ( FFFractionTrailingZerosType ) ffOptionParseEnum ( key , value , ( FFKeyValuePair []) {
{ "default" , FF_FRACTION_TRAILING_ZEROS_TYPE_DEFAULT },
2025-09-05 12:27:03 +08:00
{ "always" , FF_FRACTION_TRAILING_ZEROS_TYPE_ALWAYS },
{ "never" , FF_FRACTION_TRAILING_ZEROS_TYPE_NEVER },
2025-09-03 14:20:23 +08:00
{},
});
}
2023-10-26 10:26:15 +08:00
else if ( ffStrEqualsIgnCase ( key , "--no-buffer" ))
options -> noBuffer = ffOptionParseBoolean ( value );
else if ( ffStrStartsWithIgnCase ( key , "--bar-" ))
{
const char * subkey = key + strlen ( "--bar-" );
if ( ffStrEqualsIgnCase ( subkey , "char-elapsed" ))
ffOptionParseString ( key , value , & options -> barCharElapsed );
else if ( ffStrEqualsIgnCase ( subkey , "char-total" ))
ffOptionParseString ( key , value , & options -> barCharTotal );
else if ( ffStrEqualsIgnCase ( subkey , "width" ))
options -> barWidth = ( uint8_t ) ffOptionParseUInt32 ( key , value );
2024-06-06 16:36:57 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "border-left" ))
ffOptionParseString ( key , value , & options -> barBorderLeft );
else if ( ffStrEqualsIgnCase ( subkey , "border-right" ))
ffOptionParseString ( key , value , & options -> barBorderRight );
2025-08-01 10:51:26 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "border-left-elapsed" ))
ffOptionParseString ( key , value , & options -> barBorderLeftElapsed );
else if ( ffStrEqualsIgnCase ( subkey , "border-right-elapsed" ))
ffOptionParseString ( key , value , & options -> barBorderRightElapsed );
2025-08-01 13:50:02 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "color-elapsed" ))
2025-08-04 16:46:28 +08:00
{
if ( ! value )
ffStrbufClear ( & options -> barColorElapsed );
else if ( ffStrEqualsIgnCase ( value , "auto" ))
ffStrbufSetStatic ( & options -> barColorElapsed , "auto" );
else
ffOptionParseColor ( value , & options -> barColorElapsed );
}
2025-08-01 13:50:02 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "color-total" ))
ffOptionParseColor ( value , & options -> barColorTotal );
else if ( ffStrEqualsIgnCase ( subkey , "color-border" ))
ffOptionParseColor ( value , & options -> barColorBorder );
2023-10-26 10:26:15 +08:00
else
return false ;
}
2024-07-17 14:42:09 +08:00
else if ( ffStrStartsWithIgnCase ( key , "--freq-" ))
{
const char * subkey = key + strlen ( "--freq-" );
if ( ffStrEqualsIgnCase ( subkey , "ndigits" ))
options -> freqNdigits = ( int8_t ) ffOptionParseInt32 ( key , value );
2025-07-30 14:30:36 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "space-before-unit" ))
{
options -> freqSpaceBeforeUnit = ( FFSpaceBeforeUnitType ) ffOptionParseEnum ( key , value , ( FFKeyValuePair []) {
{ "default" , FF_SPACE_BEFORE_UNIT_DEFAULT },
{ "always" , FF_SPACE_BEFORE_UNIT_ALWAYS },
{ "never" , FF_SPACE_BEFORE_UNIT_NEVER },
{},
});
}
2024-07-23 09:55:48 +08:00
else
return false ;
2024-07-17 14:42:09 +08:00
}
2023-10-26 10:26:15 +08:00
else
return false ;
return true ;
}
void ffOptionsInitDisplay ( FFOptionsDisplay * options )
{
ffStrbufInit ( & options -> colorKeys );
ffStrbufInit ( & options -> colorTitle );
2024-05-08 15:01:57 +08:00
ffStrbufInit ( & options -> colorOutput );
2024-05-28 16:13:06 +08:00
ffStrbufInit ( & options -> colorSeparator );
2024-06-04 14:23:30 +08:00
options -> brightColor = ! instance . state . terminalLightTheme ;
2023-10-26 10:26:15 +08:00
ffStrbufInitStatic ( & options -> keyValueSeparator , ": " );
options -> showErrors = false ;
2024-05-05 20:14:10 +08:00
options -> pipe = ! isatty ( STDOUT_FILENO ) || !! getenv ( "NO_COLOR" );
2023-10-26 10:26:15 +08:00
#ifdef NDEBUG
options -> disableLinewrap = ! options -> pipe ;
#else
options -> disableLinewrap = false ;
2026-03-14 22:27:36 +08:00
options -> debugMode = !! getenv ( "FF_DEBUG" );
2023-10-26 10:26:15 +08:00
#endif
2025-07-30 14:30:36 +08:00
options -> durationSpaceBeforeUnit = FF_SPACE_BEFORE_UNIT_DEFAULT ;
2024-04-25 14:18:25 +08:00
options -> hideCursor = false ;
2024-07-22 10:59:23 +08:00
options -> sizeBinaryPrefix = FF_SIZE_BINARY_PREFIX_TYPE_IEC ;
2023-10-26 10:26:15 +08:00
options -> sizeNdigits = 2 ;
2025-08-06 21:57:05 +08:00
options -> sizeMaxPrefix = 8 ; // YB
2025-07-30 14:30:36 +08:00
options -> sizeSpaceBeforeUnit = FF_SPACE_BEFORE_UNIT_DEFAULT ;
2024-08-12 16:16:47 +08:00
options -> stat = - 1 ;
2023-10-26 10:26:15 +08:00
options -> noBuffer = false ;
options -> keyWidth = 0 ;
2024-07-24 15:12:25 +08:00
options -> keyPaddingLeft = 0 ;
2024-07-24 11:13:37 +08:00
options -> keyType = FF_MODULE_KEY_TYPE_STRING ;
2023-10-26 10:26:15 +08:00
2025-02-14 10:31:13 +08:00
options -> tempUnit = FF_TEMPERATURE_UNIT_DEFAULT ;
2024-02-27 13:11:39 +08:00
options -> tempNdigits = 1 ;
ffStrbufInitStatic ( & options -> tempColorGreen , FF_COLOR_FG_GREEN );
2024-06-04 14:23:30 +08:00
ffStrbufInitStatic ( & options -> tempColorYellow , instance . state . terminalLightTheme ? FF_COLOR_FG_YELLOW : FF_COLOR_FG_LIGHT_YELLOW );
ffStrbufInitStatic ( & options -> tempColorRed , instance . state . terminalLightTheme ? FF_COLOR_FG_RED : FF_COLOR_FG_LIGHT_RED );
2025-07-30 14:30:36 +08:00
options -> tempSpaceBeforeUnit = FF_SPACE_BEFORE_UNIT_DEFAULT ;
2024-02-26 10:46:13 +08:00
2023-10-26 10:26:15 +08:00
ffStrbufInitStatic ( & options -> barCharElapsed , "■" );
ffStrbufInitStatic ( & options -> barCharTotal , "-" );
2024-06-06 16:36:57 +08:00
ffStrbufInitStatic ( & options -> barBorderLeft , "[ " );
ffStrbufInitStatic ( & options -> barBorderRight , " ]" );
2025-08-01 10:51:26 +08:00
ffStrbufInit ( & options -> barBorderLeftElapsed );
ffStrbufInit ( & options -> barBorderRightElapsed );
2025-08-01 15:12:30 +08:00
ffStrbufInitStatic ( & options -> barColorElapsed , "auto" );
2025-08-01 13:50:02 +08:00
ffStrbufInitStatic ( & options -> barColorTotal , instance . state . terminalLightTheme ? FF_COLOR_FG_WHITE : FF_COLOR_FG_LIGHT_WHITE );
ffStrbufInitStatic ( & options -> barColorBorder , instance . state . terminalLightTheme ? FF_COLOR_FG_WHITE : FF_COLOR_FG_LIGHT_WHITE );
2023-10-26 10:26:15 +08:00
options -> barWidth = 10 ;
2025-08-01 13:50:02 +08:00
2025-07-30 14:30:36 +08:00
options -> durationAbbreviation = false ;
options -> durationSpaceBeforeUnit = FF_SPACE_BEFORE_UNIT_DEFAULT ;
2023-11-05 10:07:26 +08:00
options -> percentType = 9 ;
2023-10-26 10:26:15 +08:00
options -> percentNdigits = 0 ;
2024-01-20 19:59:13 +08:00
ffStrbufInitStatic ( & options -> percentColorGreen , FF_COLOR_FG_GREEN );
2024-06-04 14:23:30 +08:00
ffStrbufInitStatic ( & options -> percentColorYellow , instance . state . terminalLightTheme ? FF_COLOR_FG_YELLOW : FF_COLOR_FG_LIGHT_YELLOW );
ffStrbufInitStatic ( & options -> percentColorRed , instance . state . terminalLightTheme ? FF_COLOR_FG_RED : FF_COLOR_FG_LIGHT_RED );
2025-07-30 14:30:36 +08:00
options -> percentSpaceBeforeUnit = FF_SPACE_BEFORE_UNIT_DEFAULT ;
2025-07-30 15:06:16 +08:00
options -> percentWidth = 0 ;
2025-07-30 14:30:36 +08:00
2024-07-17 14:42:09 +08:00
options -> freqNdigits = 2 ;
2025-07-30 14:30:36 +08:00
options -> freqSpaceBeforeUnit = FF_SPACE_BEFORE_UNIT_DEFAULT ;
2025-09-03 09:58:40 +08:00
options -> fractionNdigits = 2 ;
2025-09-02 14:12:58 +08:00
options -> fractionTrailingZeros = FF_FRACTION_TRAILING_ZEROS_TYPE_DEFAULT ;
2024-07-15 11:00:15 +08:00
ffListInit ( & options -> constants , sizeof ( FFstrbuf ));
2023-10-26 10:26:15 +08:00
}
void ffOptionsDestroyDisplay ( FFOptionsDisplay * options )
{
ffStrbufDestroy ( & options -> colorKeys );
ffStrbufDestroy ( & options -> colorTitle );
2024-05-08 15:01:57 +08:00
ffStrbufDestroy ( & options -> colorOutput );
2024-05-28 16:13:06 +08:00
ffStrbufDestroy ( & options -> colorSeparator );
2023-10-26 10:26:15 +08:00
ffStrbufDestroy ( & options -> keyValueSeparator );
ffStrbufDestroy ( & options -> barCharElapsed );
ffStrbufDestroy ( & options -> barCharTotal );
2024-07-15 11:00:15 +08:00
FF_LIST_FOR_EACH ( FFstrbuf , item , options -> constants )
ffStrbufDestroy ( item );
ffListDestroy ( & options -> constants );
2023-10-26 10:26:15 +08:00
}
2023-10-26 11:02:08 +08:00
2026-01-15 15:03:38 +08:00
void ffOptionsGenerateDisplayJsonConfig ( FFdata * data , FFOptionsDisplay * options )
2023-10-26 11:02:08 +08:00
{
2026-01-15 15:03:38 +08:00
yyjson_mut_doc * doc = data -> resultDoc ;
2025-08-04 16:46:28 +08:00
yyjson_mut_val * obj = yyjson_mut_obj_add_obj ( doc , doc -> root , "display" );
2023-10-26 11:02:08 +08:00
2025-08-04 16:46:28 +08:00
if ( options -> stat <= 0 )
yyjson_mut_obj_add_bool ( doc , obj , "stat" , options -> stat == 0 );
else
yyjson_mut_obj_add_int ( doc , obj , "stat" , options -> stat );
2023-10-26 11:02:08 +08:00
2025-08-04 16:46:28 +08:00
yyjson_mut_obj_add_bool ( doc , obj , "pipe" , options -> pipe );
yyjson_mut_obj_add_bool ( doc , obj , "showErrors" , options -> showErrors );
2023-10-26 11:02:08 +08:00
2025-08-04 16:46:28 +08:00
yyjson_mut_obj_add_bool ( doc , obj , "disableLinewrap" , options -> disableLinewrap );
2023-10-26 11:02:08 +08:00
2025-08-04 16:46:28 +08:00
yyjson_mut_obj_add_bool ( doc , obj , "hideCursor" , options -> hideCursor );
2023-10-26 11:02:08 +08:00
2025-08-04 16:46:28 +08:00
yyjson_mut_obj_add_strbuf ( doc , obj , "separator" , & options -> keyValueSeparator );
2023-10-26 11:02:08 +08:00
2025-08-04 16:46:28 +08:00
{
yyjson_mut_val * color = yyjson_mut_obj_add_obj ( doc , obj , "color" );
yyjson_mut_obj_add_strbuf ( doc , color , "keys" , & options -> colorKeys );
yyjson_mut_obj_add_strbuf ( doc , color , "title" , & options -> colorTitle );
yyjson_mut_obj_add_strbuf ( doc , color , "output" , & options -> colorOutput );
yyjson_mut_obj_add_strbuf ( doc , color , "separator" , & options -> colorSeparator );
}
2023-10-26 11:02:08 +08:00
2025-08-04 16:46:28 +08:00
yyjson_mut_obj_add_bool ( doc , obj , "brightColor" , options -> brightColor );
2023-10-26 11:02:08 +08:00
{
2025-08-04 16:46:28 +08:00
yyjson_mut_val * duration = yyjson_mut_obj_add_obj ( doc , obj , "duration" );
yyjson_mut_obj_add_bool ( doc , duration , "abbreviation" , options -> durationAbbreviation );
switch ( options -> durationSpaceBeforeUnit )
{
case FF_SPACE_BEFORE_UNIT_DEFAULT :
yyjson_mut_obj_add_str ( doc , duration , "spaceBeforeUnit" , "default" );
break ;
case FF_SPACE_BEFORE_UNIT_ALWAYS :
yyjson_mut_obj_add_str ( doc , duration , "spaceBeforeUnit" , "always" );
break ;
case FF_SPACE_BEFORE_UNIT_NEVER :
yyjson_mut_obj_add_str ( doc , duration , "spaceBeforeUnit" , "never" );
break ;
2023-10-26 11:02:08 +08:00
}
}
{
2025-08-04 16:46:28 +08:00
yyjson_mut_val * size = yyjson_mut_obj_add_obj ( doc , obj , "size" );
yyjson_mut_obj_add_str ( doc , size , "maxPrefix" , (( const char * []) {
"B" ,
"kB" ,
"MB" ,
"GB" ,
"TB" ,
"PB" ,
"EB" ,
"ZB" ,
"YB" ,
})[ options -> sizeMaxPrefix ]);
switch ( options -> sizeBinaryPrefix )
{
case FF_SIZE_BINARY_PREFIX_TYPE_IEC :
yyjson_mut_obj_add_str ( doc , size , "binaryPrefix" , "iec" );
break ;
case FF_SIZE_BINARY_PREFIX_TYPE_SI :
yyjson_mut_obj_add_str ( doc , size , "binaryPrefix" , "si" );
break ;
case FF_SIZE_BINARY_PREFIX_TYPE_JEDEC :
yyjson_mut_obj_add_str ( doc , size , "binaryPrefix" , "jedec" );
break ;
}
yyjson_mut_obj_add_uint ( doc , size , "ndigits" , options -> sizeNdigits );
switch ( options -> sizeSpaceBeforeUnit )
{
case FF_SPACE_BEFORE_UNIT_DEFAULT :
yyjson_mut_obj_add_str ( doc , size , "spaceBeforeUnit" , "default" );
break ;
case FF_SPACE_BEFORE_UNIT_ALWAYS :
yyjson_mut_obj_add_str ( doc , size , "spaceBeforeUnit" , "always" );
break ;
case FF_SPACE_BEFORE_UNIT_NEVER :
yyjson_mut_obj_add_str ( doc , size , "spaceBeforeUnit" , "never" );
break ;
2024-07-22 10:59:23 +08:00
}
2023-10-26 11:02:08 +08:00
}
{
2025-08-04 16:46:28 +08:00
yyjson_mut_val * temperature = yyjson_mut_obj_add_obj ( doc , obj , "temp" );
switch ( options -> tempUnit )
2023-10-26 11:02:08 +08:00
{
2025-08-04 16:46:28 +08:00
case FF_TEMPERATURE_UNIT_DEFAULT :
yyjson_mut_obj_add_str ( doc , temperature , "unit" , "D" );
break ;
case FF_TEMPERATURE_UNIT_CELSIUS :
yyjson_mut_obj_add_str ( doc , obj , "unit" , "C" );
break ;
case FF_TEMPERATURE_UNIT_FAHRENHEIT :
yyjson_mut_obj_add_str ( doc , obj , "unit" , "F" );
break ;
case FF_TEMPERATURE_UNIT_KELVIN :
yyjson_mut_obj_add_str ( doc , obj , "unit" , "K" );
break ;
}
yyjson_mut_obj_add_uint ( doc , temperature , "ndigits" , options -> tempNdigits );
{
yyjson_mut_val * color = yyjson_mut_obj_add_obj ( doc , temperature , "color" );
yyjson_mut_obj_add_strbuf ( doc , color , "green" , & options -> tempColorGreen );
yyjson_mut_obj_add_strbuf ( doc , color , "yellow" , & options -> tempColorYellow );
yyjson_mut_obj_add_strbuf ( doc , color , "red" , & options -> tempColorRed );
}
switch ( options -> tempSpaceBeforeUnit )
{
case FF_SPACE_BEFORE_UNIT_DEFAULT :
yyjson_mut_obj_add_str ( doc , temperature , "spaceBeforeUnit" , "default" );
break ;
case FF_SPACE_BEFORE_UNIT_ALWAYS :
yyjson_mut_obj_add_str ( doc , temperature , "spaceBeforeUnit" , "always" );
break ;
case FF_SPACE_BEFORE_UNIT_NEVER :
yyjson_mut_obj_add_str ( doc , temperature , "spaceBeforeUnit" , "never" );
break ;
2024-02-26 10:46:13 +08:00
}
2023-10-26 11:02:08 +08:00
}
2023-10-29 00:17:24 +08:00
{
2025-08-04 16:46:28 +08:00
yyjson_mut_val * percent = yyjson_mut_obj_add_obj ( doc , obj , "percent" );
{
yyjson_mut_val * type = yyjson_mut_obj_add_arr ( doc , percent , "type" );
if ( options -> percentType & FF_PERCENTAGE_TYPE_NUM_BIT )
yyjson_mut_arr_add_str ( doc , type , "num" );
if ( options -> percentType & FF_PERCENTAGE_TYPE_BAR_BIT )
yyjson_mut_arr_add_str ( doc , type , "var" );
if ( options -> percentType & FF_PERCENTAGE_TYPE_HIDE_OTHERS_BIT )
yyjson_mut_arr_add_str ( doc , type , "hide-others" );
if ( options -> percentType & FF_PERCENTAGE_TYPE_NUM_COLOR_BIT )
yyjson_mut_arr_add_str ( doc , type , "num-color" );
if ( options -> percentType & FF_PERCENTAGE_TYPE_BAR_MONOCHROME_BIT )
yyjson_mut_arr_add_str ( doc , type , "bar-monochrome" );
}
yyjson_mut_obj_add_uint ( doc , percent , "ndigits" , options -> percentNdigits );
{
yyjson_mut_val * color = yyjson_mut_obj_add_obj ( doc , percent , "color" );
yyjson_mut_obj_add_strbuf ( doc , color , "green" , & options -> percentColorGreen );
yyjson_mut_obj_add_strbuf ( doc , color , "yellow" , & options -> percentColorYellow );
yyjson_mut_obj_add_strbuf ( doc , color , "red" , & options -> percentColorRed );
}
switch ( options -> percentSpaceBeforeUnit )
{
case FF_SPACE_BEFORE_UNIT_DEFAULT :
yyjson_mut_obj_add_str ( doc , percent , "spaceBeforeUnit" , "default" );
break ;
case FF_SPACE_BEFORE_UNIT_ALWAYS :
yyjson_mut_obj_add_str ( doc , percent , "spaceBeforeUnit" , "always" );
break ;
case FF_SPACE_BEFORE_UNIT_NEVER :
yyjson_mut_obj_add_str ( doc , percent , "spaceBeforeUnit" , "never" );
break ;
}
yyjson_mut_obj_add_uint ( doc , percent , "width" , options -> percentWidth );
2023-10-29 00:17:24 +08:00
}
2023-10-26 11:02:08 +08:00
{
2025-08-04 16:46:28 +08:00
yyjson_mut_val * bar = yyjson_mut_obj_add_obj ( doc , obj , "bar" );
yyjson_mut_val * char_ = yyjson_mut_obj_add_obj ( doc , bar , "char" );
yyjson_mut_obj_add_strbuf ( doc , char_ , "elapsed" , & options -> barCharElapsed );
yyjson_mut_obj_add_strbuf ( doc , char_ , "total" , & options -> barCharTotal );
yyjson_mut_val * border = yyjson_mut_obj_add_obj ( doc , bar , "border" );
yyjson_mut_obj_add_strbuf ( doc , border , "left" , & options -> barBorderLeft );
yyjson_mut_obj_add_strbuf ( doc , border , "right" , & options -> barBorderRight );
yyjson_mut_obj_add_strbuf ( doc , border , "leftElapsed" , & options -> barBorderLeftElapsed );
yyjson_mut_obj_add_strbuf ( doc , border , "rightElapsed" , & options -> barBorderRightElapsed );
yyjson_mut_val * color = yyjson_mut_obj_add_obj ( doc , bar , "color" );
yyjson_mut_obj_add_strbuf ( doc , color , "elapsed" , & options -> barColorElapsed );
yyjson_mut_obj_add_strbuf ( doc , color , "total" , & options -> barColorTotal );
yyjson_mut_obj_add_strbuf ( doc , color , "border" , & options -> barColorBorder );
yyjson_mut_obj_add_uint ( doc , bar , "width" , options -> barWidth );
2023-10-26 11:02:08 +08:00
}
2025-08-04 16:46:28 +08:00
{
yyjson_mut_val * fraction = yyjson_mut_obj_add_obj ( doc , obj , "fraction" );
2023-10-26 11:02:08 +08:00
2025-08-04 16:46:28 +08:00
if ( options -> fractionNdigits < 0 )
yyjson_mut_obj_add_null ( doc , fraction , "ndigits" );
else
yyjson_mut_obj_add_uint ( doc , fraction , "ndigits" , ( uint8_t ) options -> fractionNdigits );
}
2023-10-26 11:02:08 +08:00
2025-08-04 16:46:28 +08:00
yyjson_mut_obj_add_bool ( doc , obj , "noBuffer" , options -> noBuffer );
2024-07-24 11:13:37 +08:00
2025-08-04 16:46:28 +08:00
{
yyjson_mut_val * key = yyjson_mut_obj_add_obj ( doc , obj , "key" );
yyjson_mut_obj_add_uint ( doc , key , "width" , options -> keyWidth );
switch (( uint8_t ) options -> keyType )
{
case FF_MODULE_KEY_TYPE_NONE :
yyjson_mut_obj_add_str ( doc , key , "type" , "none" );
break ;
case FF_MODULE_KEY_TYPE_STRING :
yyjson_mut_obj_add_str ( doc , key , "type" , "string" );
break ;
case FF_MODULE_KEY_TYPE_ICON :
yyjson_mut_obj_add_str ( doc , key , "type" , "icon" );
break ;
case FF_MODULE_KEY_TYPE_BOTH :
yyjson_mut_obj_add_str ( doc , key , "type" , "both" );
break ;
}
yyjson_mut_obj_add_uint ( doc , key , "paddingLeft" , options -> keyPaddingLeft );
}
2024-07-24 15:12:25 +08:00
2024-07-17 14:42:09 +08:00
{
2025-08-04 16:46:28 +08:00
yyjson_mut_val * freq = yyjson_mut_obj_add_obj ( doc , obj , "freq" );
yyjson_mut_obj_add_int ( doc , freq , "ndigits" , options -> freqNdigits );
switch ( options -> percentSpaceBeforeUnit )
{
case FF_SPACE_BEFORE_UNIT_DEFAULT :
yyjson_mut_obj_add_str ( doc , freq , "spaceBeforeUnit" , "default" );
break ;
case FF_SPACE_BEFORE_UNIT_ALWAYS :
yyjson_mut_obj_add_str ( doc , freq , "spaceBeforeUnit" , "always" );
break ;
case FF_SPACE_BEFORE_UNIT_NEVER :
yyjson_mut_obj_add_str ( doc , freq , "spaceBeforeUnit" , "never" );
break ;
}
2024-07-17 14:42:09 +08:00
}
2025-08-04 16:46:28 +08:00
{
yyjson_mut_val * constants = yyjson_mut_obj_add_arr ( doc , obj , "constants" );
FF_LIST_FOR_EACH ( FFstrbuf , item , options -> constants )
yyjson_mut_arr_add_strbuf ( doc , constants , item );
}
2023-10-26 11:02:08 +08:00
}