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);
|
|
|
|
|
|
2022-04-22 15:49:50 +02:00
|
|
|
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)
|
2022-04-22 15:49:50 +02:00
|
|
|
{
|
|
|
|
|
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-11 16:19:02 +02:00
|
|
|
{
|
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-11 16:19:02 +02:00
|
|
|
}
|
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);
|
|
|
|
|
}
|