Files
fastfetch/src/logo/logo.c
T

282 lines
8.8 KiB
C
Raw Normal View History

2022-04-02 14:35:43 +02:00
#include "logo.h"
#include <ctype.h>
void ffLogoPrint(FFinstance* instance, const char* data, bool doColorReplacement)
{
uint32_t currentlineLength = 0;
fputs(FASTFETCH_TEXT_MODIFIER_BOLT, stdout);
2022-04-08 15:50:49 +02:00
ffPrintCharTimes(' ', instance->config.logoPaddingLeft);
2022-04-02 14:35:43 +02:00
//Use logoColor[0] as the default color
if(doColorReplacement)
ffPrintColor(&instance->config.logoColors[0]);
while(*data != '\0')
{
//We are at the end of a line. Print paddings and update max line length
if(*data == '\n' || (*data == '\r' && *(data + 1) == '\n'))
{
2022-04-08 15:50:49 +02:00
ffPrintCharTimes(' ', instance->config.logoPaddingRight);
2022-04-02 14:35:43 +02:00
//We have \r\n, skip the \r
if(*data == '\r')
++data;
putchar('\n');
++data;
2022-04-08 15:50:49 +02:00
ffPrintCharTimes(' ', instance->config.logoPaddingLeft);
2022-04-02 14:35:43 +02:00
2022-04-06 14:02:05 +02:00
if(currentlineLength > instance->state.logoWidth)
instance->state.logoWidth = currentlineLength;
2022-04-02 14:35:43 +02:00
currentlineLength = 0;
++instance->state.logoHeight;
continue;
}
//Always print tabs as 4 spaces, to have consistent spacing
if(*data == '\t')
{
2022-04-08 15:50:49 +02:00
ffPrintCharTimes(' ', 4);
2022-04-02 14:35:43 +02:00
++data;
continue;
}
//We have an escape sequence direclty as bytes. We print it, but don't increase the line length
if(*data == '\033' && *(data + 1) == '[')
{
const char* start = data;
fputs("\033[", stdout);
data += 2;
while(isdigit(*data) || *data == ';')
putchar(*data++); // number
//We have a valid control sequence, print it and continue with next char
if(isascii(*data))
{
putchar(*data++); // single letter, end of control sequence
continue;
}
//Invalid control sequence, try to get most accurate length
currentlineLength += (uint32_t) (data - start - 1); //-1 for \033 which for sure doesn't take any space
//Don't continue here, print the char after the letters with the unicode printing
}
//We have a fastfetch color placeholder. Replace it with the esacape sequence, don't increase the line length
if(doColorReplacement && *data == '$')
{
++data;
//If we have $$, or $\0, print it as single $
if(*data == '$' || *data == '\0')
{
putchar('$');
++currentlineLength;
++data;
continue;
}
//Map the number to an array index, so that '1' -> 0, '2' -> 1, etc.
int index = ((int) *data) - 49;
//If the index is valid, print the color. Otherwise continue as normal
if(index < 0 || index >= FASTFETCH_LOGO_MAX_COLORS)
{
putchar('$');
++currentlineLength;
//Don't continue here, we want to print the current char as unicode
}
else
{
ffPrintColor(&instance->config.logoColors[index]);
++data;
continue;
}
}
//Do the printing, respecting unicode
++currentlineLength;
int codepoint = (unsigned char) *data;
uint8_t bytes;
if(codepoint <= 127)
bytes = 1;
else if((codepoint & 0xE0) == 0xC0)
bytes = 2;
else if((codepoint & 0xF0) == 0xE0)
bytes = 3;
else if((codepoint & 0xF8) == 0xF0)
bytes = 4;
else
bytes = 1; //Invalid utf8, print it as is, byte by byte
for(uint8_t i = 0; i < bytes; ++i)
{
if(*data == '\0')
break;
putchar(*data++);
}
}
2022-04-08 15:50:49 +02:00
ffPrintCharTimes(' ', instance->config.logoPaddingRight);
2022-04-02 14:35:43 +02:00
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
//Happens if the last line is the longest
2022-04-06 14:02:05 +02:00
if(currentlineLength > instance->state.logoWidth)
instance->state.logoWidth = currentlineLength;
2022-04-02 14:35:43 +02:00
2022-04-06 14:02:05 +02:00
instance->state.logoWidth += instance->config.logoPaddingLeft + instance->config.logoPaddingRight;
2022-04-02 14:35:43 +02:00
2022-04-06 14:02:05 +02:00
//Go to the leftmost position
fputs("\033[9999999D", stdout);
2022-04-02 14:35:43 +02:00
//If the logo height is > 1, go up the height
if(instance->state.logoHeight > 0)
printf("\033[%uA", instance->state.logoHeight);
}
static void logoPrintFile(FFinstance* instance, bool doColorReplacement)
{
FFstrbuf content;
ffStrbufInitA(&content, 2047);
if(ffAppendFileContent(instance->config.logoSource.chars, &content))
2022-04-02 14:35:43 +02:00
ffLogoPrint(instance, content.chars, doColorReplacement);
else
ffLogoPrintUnknown(instance);
}
static void logoPrintDetected(FFinstance* instance)
{
2022-04-29 21:44:32 +02:00
//If no logo source is given, detect the logo from OS and print the right builtin one
if(instance->config.logoSource.length == 0)
2022-04-29 21:52:42 +02:00
{
2022-04-29 21:44:32 +02:00
ffLogoPrintBuiltinDetected(instance);
2022-04-29 21:52:42 +02:00
return;
}
2022-04-29 21:44:32 +02:00
//If a logo source is given, first look if it is the name of a builtin logo
if(ffLogoPrintBuiltinIfExists(instance))
2022-04-02 14:35:43 +02:00
return;
2022-04-29 21:44:32 +02:00
const FFTerminalShellResult* terminalShell = ffDetectTerminalShell(instance);
FFLogoImageResult imageResult = FF_LOGO_IMAGE_RESULT_INIT_ERROR;
//Terminals that are known to support kitty graphics protocol
//Try to load the logo as image.
if(
ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "kitty") == 0 ||
ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "konsole") == 0 ||
ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "wezterm") == 0 ||
ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "wayst") == 0
) {
imageResult = ffLogoPrintImageIfExists(instance, FF_LOGO_TYPE_KITTY);
if(imageResult == FF_LOGO_IMAGE_RESULT_SUCCESS)
return;
2022-04-02 14:35:43 +02:00
}
2022-04-29 21:44:32 +02:00
//If the logo can be loaded as an image, convert it to ascii art.
//This happens in all terminals, that don't support kitty graphics protocol
if(
imageResult != FF_LOGO_IMAGE_RESULT_RUN_ERROR &&
ffLogoPrintImageIfExists(instance, FF_LOGO_TYPE_CHAFA) == FF_LOGO_IMAGE_RESULT_SUCCESS
) return;
//Print the content of the file as logo
logoPrintFile(instance, true);
2022-04-02 14:35:43 +02:00
}
void ffPrintLogo(FFinstance* instance)
{
if(instance->config.mainColor.length == 0)
ffLogoSetMainColor(instance);
2022-04-29 21:44:32 +02:00
if( //Logo type needs set logo name, but nothing was given. Print question mark
instance->config.logoType != FF_LOGO_TYPE_AUTO &&
instance->config.logoSource.length == 0
)
2022-04-02 14:35:43 +02:00
ffLogoPrintUnknown(instance);
else if(instance->config.logoType == FF_LOGO_TYPE_BUILTIN)
{
if(!ffLogoPrintBuiltinIfExists(instance))
ffLogoPrintUnknown(instance);
}
2022-04-02 14:35:43 +02:00
else if(instance->config.logoType == FF_LOGO_TYPE_FILE)
logoPrintFile(instance, true);
else if(instance->config.logoType == FF_LOGO_TYPE_RAW)
logoPrintFile(instance, false);
2022-04-28 19:15:46 +02:00
else if(instance->config.logoType == FF_LOGO_TYPE_SIXEL || instance->config.logoType == FF_LOGO_TYPE_KITTY || instance->config.logoType == FF_LOGO_TYPE_CHAFA)
{
2022-04-29 21:44:32 +02:00
if(ffLogoPrintImageIfExists(instance, instance->config.logoType) != FF_LOGO_IMAGE_RESULT_SUCCESS)
2022-04-13 23:04:42 +02:00
ffLogoPrintBuiltinDetected(instance);
}
2022-04-02 14:35:43 +02:00
else
logoPrintDetected(instance);
}
2022-04-06 14:02:05 +02:00
static inline void printLogoWidth(const FFinstance* instance)
{
if(instance->state.logoWidth > 0)
printf("\033[%uC", instance->state.logoWidth);
}
2022-04-02 14:35:43 +02:00
void ffPrintRemainingLogo(FFinstance* instance)
{
if(!instance->config.logoPrintRemaining)
return;
for(uint32_t i = instance->state.keysHeight; i <= instance->state.logoHeight; i++)
2022-04-06 14:02:05 +02:00
{
printLogoWidth(instance);
putchar('\n');
}
2022-04-02 14:35:43 +02:00
}
void ffPrintLogoLine(FFinstance* instance)
{
2022-04-06 14:02:05 +02:00
printLogoWidth(instance);
2022-04-02 14:35:43 +02:00
++instance->state.keysHeight;
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
}
void ffPrintLogoAndKey(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat)
{
ffPrintLogoLine(instance);
fputs(FASTFETCH_TEXT_MODIFIER_BOLT, stdout);
ffPrintColor(&instance->config.mainColor);
if(customKeyFormat == NULL || customKeyFormat->length == 0)
{
fputs(moduleName, stdout);
if(moduleIndex > 0)
printf(" %hhu", moduleIndex);
}
else
{
FFstrbuf key;
ffStrbufInit(&key);
ffParseFormatString(&key, customKeyFormat, NULL, 1, (FFformatarg[]){
{FF_FORMAT_ARG_TYPE_UINT8, &moduleIndex}
});
ffStrbufWriteTo(&key, stdout);
ffStrbufDestroy(&key);
}
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
ffStrbufWriteTo(&instance->config.separator, stdout);
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
}