/* SPDX-License-Identifier: GPL-3.0-or-later */ /* * vfetch - neofetch but the ascii part is a video * * Copyright (C) 2026 Doan Luu Duc Tai * */ #include "fetch.h" #include #include #include #include #include #include #include #include #include #include "utils.h" static VfetchError try_fastfetch(AppState *state, const VfetchArgs *args) { VfetchError err = run_command_fork_output("fastfetch --logo none --pipe false", &state->live_fetch_output, args->debug); if (err == VFETCH_SUCCESS) { state->fetch_command = g_strdup("fastfetch --logo none --pipe false"); if (!state->fetch_command) { return VFETCH_ERROR_MEMORY_ALLOCATION; } } return err; } static VfetchError try_neofetch(AppState *state, const VfetchArgs *args) { log_verbose(state, args->verbose, args->debug, "fastfetch failed, trying neofetch..."); VfetchError err = run_command_fork_output( "neofetch --off", &state->live_fetch_output, args->debug); if (err == VFETCH_SUCCESS) { state->fetch_command = g_strdup("neofetch --off"); if (!state->fetch_command) { err = VFETCH_ERROR_MEMORY_ALLOCATION; return err; } } return err; } static VfetchError set_fetch_unavailable(void) { (void)fputs("\nERROR: Neither 'fastfetch' nor 'neofetch' could be found in " "your system's PATH.\n\n", stderr); (void)fputs(" Action Required:\n", stderr); (void)fputs(" - Please install either 'fastfetch' or 'neofetch'.\n", stderr); (void)fputs(" - Alternatively, to disable the system information display, " "use the '--fetch-tool none' flag.\n\n", stderr); return VFETCH_ERROR_COMMAND_FAILED; } static VfetchError fail_fetch_unavailable_override(const char *tool_name) { (void)fprintf(stderr, "\nERROR: The specified fetch tool ('%s') is not available in " "your system's PATH.\n\n", tool_name); (void)fputs(" Action Required:\n", stderr); (void)fputs( " - Please install the tool or correct the --fetch-tool argument.\n", stderr); (void)fputs(" - To disable the system information display, use " "'--fetch-tool none'.\n\n", stderr); return VFETCH_ERROR_COMMAND_FAILED; } static VfetchError handle_fetch_override(AppState *state, const VfetchArgs *args) { log_verbose(state, args->verbose, args->debug, "User specified fetch tool: '%s'", args->fetch_tool_arg); if (strcmp(args->fetch_tool_arg, "fastfetch") == 0) { if (try_fastfetch(state, args) != VFETCH_SUCCESS) { return fail_fetch_unavailable_override("fastfetch"); } } else if (strcmp(args->fetch_tool_arg, "neofetch") == 0) { if (try_neofetch(state, args) != VFETCH_SUCCESS) { return fail_fetch_unavailable_override("neofetch"); } } return VFETCH_SUCCESS; } static VfetchError handle_fetch_fallback(AppState *state, const VfetchArgs *args) { log_verbose(state, args->verbose, args->debug, "No fetch tool specified, using fallback logic."); if (try_fastfetch(state, args) == VFETCH_SUCCESS) { return VFETCH_SUCCESS; } if (try_neofetch(state, args) == VFETCH_SUCCESS) { return VFETCH_SUCCESS; } return set_fetch_unavailable(); } VfetchError initialize_fetch_utility(AppState *state, const VfetchArgs *args) { log_verbose( state, args->verbose, args->debug, "Initializing fetch utility..."); if (args->fetch_tool_arg) { return handle_fetch_override(state, args); } return handle_fetch_fallback(state, args); } VfetchError start_fetch_thread(AppState *state, VfetchArgs *args) { if (args->fetch_tool_arg && strcmp(args->fetch_tool_arg, "none") == 0) { state->fetch_command = g_strdup("echo"); state->live_fetch_output = g_strdup(""); if (!state->fetch_command || !state->live_fetch_output) { return VFETCH_ERROR_MEMORY_ALLOCATION; } return VFETCH_SUCCESS; } if (!state->fetch_command) { VfetchError err = initialize_fetch_utility(state, args); if (err) { return err; } } atomic_store_explicit(&state->last_fetch_lines, count_lines(state->live_fetch_output), memory_order_relaxed); return VFETCH_SUCCESS; } #define K_DEFAULT_TERMINAL_WIDTH 80 void render_fetch_panel(char *screen_buffer, size_t screen_buffer_size, size_t *current_len, AppState *state, const VfetchArgs *args) { struct winsize window_size = {0}; char *fetch_output_copy = NULL; size_t terminal_width = K_DEFAULT_TERMINAL_WIDTH; if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &window_size) == 0 && window_size.ws_col > 0) { terminal_width = window_size.ws_col; } (void)pthread_mutex_lock(&state->fetch_mutex); if (state->live_fetch_output) { fetch_output_copy = g_strdup(state->live_fetch_output); } size_t current_fetch_lines = atomic_load_explicit(&state->last_fetch_lines, memory_order_relaxed); size_t prev_fetch_lines = state->previous_fetch_lines; state->previous_fetch_lines = current_fetch_lines; (void)pthread_mutex_unlock(&state->fetch_mutex); uint32_t fetch_x = args->pad_x + args->width + 4; size_t clear_width = terminal_width > fetch_x ? terminal_width - fetch_x : 0; size_t lines_to_clear = (prev_fetch_lines > current_fetch_lines) ? prev_fetch_lines : current_fetch_lines; if (lines_to_clear > 0 && clear_width > 0) { Rect rect_to_clear = {.height = lines_to_clear, .width = clear_width, .start_x = fetch_x, .start_y = args->pad_y}; clear_rect_in_buffer( screen_buffer, screen_buffer_size, current_len, &rect_to_clear); } const char *fetch_output_to_draw = fetch_output_copy ? fetch_output_copy : "..."; append_block_to_buffer(screen_buffer, screen_buffer_size, current_len, fetch_x, args->pad_y, fetch_output_to_draw, strlen(fetch_output_to_draw)); g_free(fetch_output_copy); } #undef K_DEFAULT_TERMINAL_WIDTH