Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
# 2.64.2

Bugfixes:
* Fixes image rendering being wiped quickly (#2374)
* Regression from v2.64.0
Comment thread
CarterLi marked this conversation as resolved.
* Fixes ASCII logo being overwritten in `--dynamic-interval` mode
* Regression from v2.64.0

Logos:
* Updates OpenWrt and adds a small variant (#2376)
* The old one is renamed to `openwrt_old`

# 2.64.1

Features:
Expand Down
11 changes: 8 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url

project(fastfetch
VERSION 2.64.1
VERSION 2.64.2
LANGUAGES C
DESCRIPTION "Fast neofetch-like system information tool"
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
Expand Down Expand Up @@ -1638,6 +1638,11 @@ function(ff_lib_enable VARNAME PKGCONFIG_NAMES CMAKE_NAME) # [CMAKE_TARGET_NAME]
set(${VARNAME}_LIBRARIES ${_FF_CMAKE_TARGET})
endif()
endif()

if(NOT BINARY_LINK_TYPE STREQUAL "dlopen")
# INTERFACE_LINK_LIBRARIES doesn't expose libvarname.a
target_link_libraries(libfastfetch PRIVATE ${_FF_CMAKE_TARGET})
endif()
endif()
else()
set(${VARNAME}_INCLUDE_DIRS ${${CMAKE_NAME}_INCLUDE_DIRS})
Expand Down Expand Up @@ -1691,8 +1696,8 @@ ff_lib_enable(DRM
"Libdrm"
)
ff_lib_enable(VA
"libva"
"Libva"
"libva-drm"
"Libva-drm"
)
ff_lib_enable(VDPAU
"vdpau"
Expand Down
9 changes: 5 additions & 4 deletions src/common/impl/lua.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@
if (__builtin_expect(depth > 15, false)) {
yyjson_mut_doc_free(doc);
lua_pushlstring(
L, "yyjson: recursion depth exceeded; possible circular reference",
strlen("yyjson: recursion depth exceeded; possible circular reference")
);
L, "yyjson: recursion depth exceeded; possible circular reference", strlen("yyjson: recursion depth exceeded; possible circular reference"));

Check failure on line 12 in src/common/impl/lua.c

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/common/impl/lua.c#L12

Does not handle strings that are not \0-terminated; if given one it may perform an over-read (it could cause a crash if unprotected) (CWE-126).
lua_error(L); // noreturn
__builtin_unreachable();
}
Expand Down Expand Up @@ -140,7 +138,7 @@
}
}

const char* ffLuaLoadState() {
const char* ffLuaLoadState(void) {
if (luaData.inited) {
if (luaData.L == NULL) {
return "Lua library is not available";
Expand Down Expand Up @@ -180,6 +178,8 @@
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(liblua, luaopen_string)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(liblua, luaopen_table)
#endif

#if !FF_DISABLE_DLOPEN
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, luaL_checkany)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, luaL_loadbufferx)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, luaL_tolstring)
Expand Down Expand Up @@ -208,6 +208,7 @@
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_tolstring)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_tonumberx)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_type)
#endif

lua_State* L = ffluaL_newstate();
if (L == NULL) {
Expand Down
37 changes: 22 additions & 15 deletions src/common/lua.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,19 @@
#include "fastfetch.h"

#if FF_HAVE_LUA
// Hack. LUA_API is defined as extern which prevents us from implementing the functions ourselves.
#include <luaconf.h>
#undef LUA_API
#undef LUALIB_API
#undef LUAMOD_API
#define LUA_API static inline
#define LUALIB_API LUA_API
#define LUAMOD_API LUA_API

#pragma GCC diagnostic ignored "-Wunused-function"
#if !FF_DISABLE_DLOPEN
// Hack. LUA_API is defined as extern which prevents us from implementing the functions ourselves.
#include <luaconf.h>
#undef LUA_API
#undef LUALIB_API
#undef LUAMOD_API
#define LUA_API static inline
#define LUALIB_API LUA_API
#define LUAMOD_API LUA_API

#pragma GCC diagnostic ignored "-Wunused-function"
#endif

#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
Expand All @@ -24,6 +27,7 @@
#include "common/library.h"

extern struct FFLuaData {
#if !FF_DISABLE_DLOPEN
FF_LIBRARY_SYMBOL(luaL_checkany)
FF_LIBRARY_SYMBOL(luaL_loadbufferx)
FF_LIBRARY_SYMBOL(luaL_tolstring)
Expand Down Expand Up @@ -52,13 +56,13 @@ extern struct FFLuaData {
FF_LIBRARY_SYMBOL(lua_tolstring)
FF_LIBRARY_SYMBOL(lua_tonumberx)
FF_LIBRARY_SYMBOL(lua_type)
#endif

lua_State* L;
bool inited;
} luaData;

const char* ffLuaLoadState();

#if !FF_DISABLE_DLOPEN
FF_A_ALWAYS_INLINE void(lua_settop)(lua_State* L, int idx) {
return luaData.fflua_settop(L, idx);
}
Expand Down Expand Up @@ -148,11 +152,11 @@ FF_A_ALWAYS_INLINE int(lua_rawgeti)(lua_State* L, int idx, lua_Integer n) {
}

FF_A_ALWAYS_INLINE
#if LUA_VERSION_NUM > 503
#if LUA_VERSION_NUM > 503
lua_Unsigned
#else
#else
size_t
#endif
#endif
(lua_rawlen)(lua_State* L, int idx) {
return luaData.fflua_rawlen(L, idx);
}
Expand All @@ -176,5 +180,8 @@ FF_A_ALWAYS_INLINE lua_Number(lua_tonumberx)(lua_State* L, int idx, int* isnum)
FF_A_ALWAYS_INLINE int(lua_type)(lua_State* L, int idx) {
return luaData.fflua_type(L, idx);
}
#endif

const char* ffLuaLoadState(void);
Comment thread
CarterLi marked this conversation as resolved.

#endif
5 changes: 4 additions & 1 deletion src/fastfetch.c
Original file line number Diff line number Diff line change
Expand Up @@ -765,9 +765,12 @@ static void run(FFdata* data) {
}

if (instance.state.dynamicInterval > 0) {
ffLogoPrintRemaining(); // `logoLineCacheClear` inside so that ffLogoPrintLine will use `\e[nC` to move the cursor to the right position instead of reprinting the logo
fputs("\e[J", stdout); // Clear from cursor to the end of the screen to prevent artifacts when the new output is shorter than the previous one
Comment on lines +768 to +769
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 MEDIUM RISK

On subsequent iterations of the dynamic interval loop, ffLogoPrintRemaining() returns early because the cache is empty. This leaves the cursor at the end of the data lines. The following \e[J then clears the remainder of the screen, effectively wiping out any part of the ASCII logo that is taller than the data output. To fix this, you should ensure the cursor moves to max(logoHeight, keysHeight) before clearing.

fflush(stdout);
ffTimeSleep(instance.state.dynamicInterval);
fputs("\e[H", stdout);
fputs("\e[H", stdout); // Move cursor to the top left corner to overwrite the previous output
Comment thread
CarterLi marked this conversation as resolved.
instance.state.keysHeight = 0; // Reset keysHeight so `ffLogoPrintRemaining` will recalculate it
} else {
break;
}
Expand Down
28 changes: 28 additions & 0 deletions src/logo/ascii/o.inc
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,34 @@ static const FFlogo O[] = {
{
.names = { "openwrt" },
.lines = FASTFETCH_DATATEXT_LOGO_OPENWRT,
.colors = {
FF_COLOR_FG_DEFAULT,
FF_COLOR_FG_BLUE,
},
.colorKeys = FF_COLOR_FG_BLUE,
.colorTitle = FF_COLOR_FG_DEFAULT,
},
#endif
#ifdef FASTFETCH_DATATEXT_LOGO_OPENWRT_SMALL
// OpenWrtSmall
{
.names = { "openwrt_small" },
.type = FF_LOGO_LINE_TYPE_SMALL_BIT,
.lines = FASTFETCH_DATATEXT_LOGO_OPENWRT_SMALL,
.colors = {
FF_COLOR_FG_DEFAULT,
FF_COLOR_FG_BLUE,
},
.colorKeys = FF_COLOR_FG_BLUE,
.colorTitle = FF_COLOR_FG_DEFAULT,
},
#endif
#ifdef FASTFETCH_DATATEXT_LOGO_OPENWRT_OLD
// OpenWrtOld
{
.names = { "openwrt_old" },
.type = FF_LOGO_LINE_TYPE_ALTER_BIT,
.lines = FASTFETCH_DATATEXT_LOGO_OPENWRT_OLD,
Comment thread
CarterLi marked this conversation as resolved.
.colors = {
FF_COLOR_FG_BLUE,
},
Expand Down
27 changes: 18 additions & 9 deletions src/logo/ascii/o/openwrt.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
_______
| |.-----.-----.-----.
| - || _ | -__| |
|_______|| __|_____|__|__|
|__|
________ __
| | | |.----.| |_
| | | || _|| _|
|________||__| |____|
..,,..
,;odOMMMMMMMMObo:.
,odOMMMMMO""''""OMMMMMObo.
.dMMMM" .,,. "OMMMb,
'0" ,;ddMMMMMMMMbb:. "0'
oOMMMMO""''""OMMMMOo
$2;. $1'0" .,,. "0' $2.:
.OMM* $1.odMMMMMMbo. $2*MMO.
MMMO $1"0"````"0" $2OMMM
iOMM $1.oo. $2MMMi
OMMl $1:MMMM: $2lMMO
iMMM $1'oo' $2MMMi
OMMb $2dMMO
'OMMO. ,OMMO'
"MMMb. ,dMMM"
"MMMMbgo-,,-ogdMMMM"
"*MMMMMMMMMM*"
`'""'`
9 changes: 9 additions & 0 deletions src/logo/ascii/o/openwrt_old.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
_______
| |.-----.-----.-----.
| - || _ | -__| |
|_______|| __|_____|__|__|
|__|
________ __
| | | |.----.| |_
| | | || _|| _|
|________||__| |____|
9 changes: 9 additions & 0 deletions src/logo/ascii/o/openwrt_small.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
..,..
,odM"""""Mbo,
`.odMMMMMbo.`
$2d,$1" ,mmm, "$2,b
iM $1" . " $2Mi
Ml $1dMb $2lM
'M, $1' $2.M'
"0b. ,d0"
`"WWWWW"`
60 changes: 31 additions & 29 deletions src/logo/logo.c
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ static bool updateLogoPath(void) {
return true;
}

#if !FF_MODULE_DISABLE_MEDIA
#if !FF_MODULE_DISABLE_MEDIA
if (ffStrbufIgnCaseEqualS(&options->source, "media-cover")) {
const FFMediaResult* media = ffDetectMedia(true);
if (media->cover.length == 0) {
Expand All @@ -470,7 +470,7 @@ static bool updateLogoPath(void) {
ffStrbufSet(&options->source, &media->cover);
return true;
}
#endif
#endif

FF_STRBUF_AUTO_DESTROY fullPath = ffStrbufCreateA(128);
if (ffPathExpandEnv(options->source.chars, &fullPath) && ffPathExists(fullPath.chars, FF_PATHTYPE_FILE)) {
Expand Down Expand Up @@ -639,7 +639,7 @@ void ffLogoPrint(void) {
}

if (!ffStrbufEndsWithIgnCaseS(&options->source, ".txt")) {
#if !FF_MODULE_DISABLE_TERMINAL
#if !FF_MODULE_DISABLE_TERMINAL
const FFTerminalResult* terminal = ffDetectTerminal();

bool supportsIterm2 = ffStrbufEqualS(&terminal->prettyName, "iTerm");
Expand All @@ -655,15 +655,15 @@ void ffLogoPrint(void) {
ffStrbufIgnCaseEqualS(&terminal->processName, "wezterm") ||
ffStrbufIgnCaseEqualS(&terminal->processName, "wayst") ||
ffStrbufIgnCaseEqualS(&terminal->processName, "ghostty") ||
#ifdef __APPLE__
#ifdef __APPLE__
ffStrbufIgnCaseEqualS(&terminal->processName, "WarpTerminal") ||
#else
#else
ffStrbufIgnCaseEqualS(&terminal->processName, "warp") ||
#endif
#endif
Comment thread
CarterLi marked this conversation as resolved.
false;
#else
#else
bool supportsKitty = false;
#endif
#endif

// Try to load the logo as an image. If it succeeds, print it and return.
if (logoPrintImageIfExists(supportsKitty ? FF_LOGO_TYPE_IMAGE_KITTY : FF_LOGO_TYPE_IMAGE_CHAFA, false)) {
Expand All @@ -685,37 +685,39 @@ void ffLogoPrint(void) {
}

void ffLogoPrintLine(void) {
uint32_t printedLineWidth = 0;
FFLogoLineCacheState* cache = &instance.state.logoLineCache;
FFOptionsLogo* logo = &instance.config.logo;

if (cache->lines.length > 0 && (logo->position == FF_LOGO_POSITION_LEFT || logo->position == FF_LOGO_POSITION_RIGHT) && cache->nextLine < cache->lines.length) {
FFLogoCachedLine* line = FF_LIST_GET(FFLogoCachedLine, cache->lines, cache->nextLine);
if (cache->lines.length > 0) {
// Line cache is enabled. Always move cursor with whitespaces to make lolcat happy
if (cache->nextLine < cache->lines.length) {
// Print logo line and move cursor
FFLogoCachedLine* line = FF_LIST_GET(FFLogoCachedLine, cache->lines, cache->nextLine);

if (logo->position == FF_LOGO_POSITION_RIGHT && line->chars.length > 0) {
printf("\033[9999999C\033[%uD", cache->rightOffset);
ffStrbufWriteTo(&line->chars, stdout);
fputs("\033[G", stdout);
} else {
ffStrbufWriteTo(&line->chars, stdout);
printedLineWidth = line->width;
}
if (logo->position == FF_LOGO_POSITION_RIGHT) {
printf("\033[9999999C\033[%uD", cache->rightOffset);
ffStrbufWriteTo(&line->chars, stdout);

++cache->nextLine;
}
fputs("\033[G", stdout);
} else {
ffStrbufWriteTo(&line->chars, stdout);

if (instance.state.logoWidth > 0) {
if (instance.config.logo.position == FF_LOGO_POSITION_LEFT) {
uint32_t remaining = instance.state.logoWidth;
remaining = printedLineWidth < remaining ? remaining - printedLineWidth : 0;
ffPrintCharTimes(' ', remaining);
} else {
printf("\033[%uC", instance.state.logoWidth);
uint32_t remaining = instance.state.logoWidth;
remaining = line->width < remaining ? remaining - line->width : 0;
ffPrintCharTimes(' ', remaining);
}
++cache->nextLine;
} else if (logo->position == FF_LOGO_POSITION_LEFT) {
// Move cursor to the start position
ffPrintCharTimes(' ', instance.state.logoWidth);
}
} else if (instance.state.logoWidth > 0) {
printf("\033[%uC", instance.state.logoWidth);
}
Comment on lines +714 to 716
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 MEDIUM RISK

This unconditional cursor shift incorrectly affects right-aligned logos. When instance.config.logo.position == FF_LOGO_POSITION_RIGHT, the cursor should not be shifted to the right before printing keys, as they should start from the first column. Currently, this logic will cause keys to overlap the logo or create unwanted whitespace on the left.


if (instance.state.dynamicInterval > 0) {
if (instance.state.dynamicInterval > 0 && logo->position == FF_LOGO_POSITION_LEFT) {
fputs("\033[K", stdout); // Clear to the end of the line
// Note that we don't clear the line when the logo is on the right, as it will also clear the logo itself
}

++instance.state.keysHeight;
Expand Down
Loading