mirror of
https://github.com/marcusDenslow/FERRUM.git
synced 2026-10-25 15:48:50 +01:00
482 lines
18 KiB
C
482 lines
18 KiB
C
/**
|
|
* themes.c
|
|
* Implementation of theme system for shell appearance
|
|
*/
|
|
|
|
#include "themes.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
// Define Windows colors for compatibility
|
|
#define FOREGROUND_BLUE 0x0001
|
|
#define FOREGROUND_GREEN 0x0002
|
|
#define FOREGROUND_RED 0x0004
|
|
#define FOREGROUND_INTENSITY 0x0008
|
|
|
|
#define FOREGROUND_CYAN (FOREGROUND_GREEN | FOREGROUND_BLUE)
|
|
#define FOREGROUND_MAGENTA (FOREGROUND_RED | FOREGROUND_BLUE)
|
|
|
|
// Current active theme
|
|
ShellTheme current_theme;
|
|
|
|
// Define built-in themes
|
|
static ShellTheme default_theme = {
|
|
// Standard console colors
|
|
.PRIMARY_COLOR =
|
|
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, // White
|
|
.SECONDARY_COLOR =
|
|
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, // White (dimmer)
|
|
.ACCENT_COLOR = FOREGROUND_GREEN | FOREGROUND_INTENSITY, // Bright Green
|
|
.SUCCESS_COLOR = FOREGROUND_GREEN | FOREGROUND_INTENSITY, // Bright Green
|
|
.ERROR_COLOR = FOREGROUND_RED | FOREGROUND_INTENSITY, // Bright Red
|
|
.WARNING_COLOR = FOREGROUND_RED | FOREGROUND_GREEN |
|
|
FOREGROUND_INTENSITY, // Bright Yellow
|
|
|
|
.HEADER_COLOR = FOREGROUND_GREEN | FOREGROUND_INTENSITY, // Bright Green
|
|
.STATUS_BAR_COLOR = 0, // Black
|
|
.STATUS_TEXT_COLOR = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE |
|
|
FOREGROUND_INTENSITY, // Bright White
|
|
.PROMPT_COLOR = FOREGROUND_CYAN | FOREGROUND_INTENSITY, // Bright Cyan
|
|
|
|
.DIRECTORY_COLOR = FOREGROUND_GREEN | FOREGROUND_INTENSITY, // Bright Green
|
|
.EXECUTABLE_COLOR = FOREGROUND_RED | FOREGROUND_GREEN |
|
|
FOREGROUND_INTENSITY, // Bright Yellow
|
|
.TEXT_FILE_COLOR =
|
|
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, // White
|
|
.IMAGE_FILE_COLOR = FOREGROUND_RED | FOREGROUND_BLUE |
|
|
FOREGROUND_INTENSITY, // Bright Magenta
|
|
.CODE_FILE_COLOR = FOREGROUND_BLUE | FOREGROUND_INTENSITY, // Bright Blue
|
|
.ARCHIVE_FILE_COLOR = FOREGROUND_RED | FOREGROUND_INTENSITY, // Bright Red
|
|
|
|
.SYNTAX_KEYWORD = FOREGROUND_CYAN | FOREGROUND_INTENSITY, // Bright Cyan
|
|
.SYNTAX_STRING = FOREGROUND_GREEN | FOREGROUND_INTENSITY, // Bright Green
|
|
.SYNTAX_COMMENT = FOREGROUND_INTENSITY, // Gray
|
|
.SYNTAX_NUMBER =
|
|
FOREGROUND_MAGENTA | FOREGROUND_INTENSITY, // Bright Magenta
|
|
.SYNTAX_PREPROCESSOR =
|
|
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY, // Yellow
|
|
|
|
// ANSI colors for default theme (basic colors, not true full 24-bit colors)
|
|
.ANSI_BASE = "\033[37m", // White
|
|
.ANSI_SURFACE = "\033[37m", // White
|
|
.ANSI_OVERLAY = "\033[37m", // White
|
|
.ANSI_MUTED = "\033[37m", // White
|
|
.ANSI_SUBTLE = "\033[37m", // White
|
|
.ANSI_TEXT = "\033[97m", // Bright White
|
|
.ANSI_LOVE = "\033[91m", // Bright Red
|
|
.ANSI_GOLD = "\033[93m", // Bright Yellow
|
|
.ANSI_ROSE = "\033[95m", // Bright Magenta
|
|
.ANSI_PINE = "\033[92m", // Bright Green
|
|
.ANSI_FOAM = "\033[96m", // Bright Cyan
|
|
.ANSI_IRIS = "\033[94m", // Bright Blue
|
|
.ANSI_HIGHLIGHT = "\033[37m", // White
|
|
|
|
// Don't use ANSI colors for default theme
|
|
.use_ansi_colors = FALSE,
|
|
|
|
.name = "default"};
|
|
|
|
static ShellTheme rose_pine_theme = {
|
|
// Legacy console colors (for backward compatibility)
|
|
.PRIMARY_COLOR =
|
|
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, // White (base)
|
|
.SECONDARY_COLOR =
|
|
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, // Muted
|
|
.ACCENT_COLOR = FOREGROUND_BLUE, // Blue for git syntax
|
|
.SUCCESS_COLOR = FOREGROUND_GREEN,
|
|
.ERROR_COLOR = FOREGROUND_RED | FOREGROUND_INTENSITY,
|
|
.WARNING_COLOR = FOREGROUND_RED | FOREGROUND_GREEN,
|
|
|
|
.HEADER_COLOR = FOREGROUND_RED | FOREGROUND_BLUE,
|
|
.STATUS_BAR_COLOR = 0,
|
|
.STATUS_TEXT_COLOR = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE |
|
|
FOREGROUND_INTENSITY,
|
|
.PROMPT_COLOR =
|
|
FOREGROUND_RED | FOREGROUND_INTENSITY, // Bright red for repo name
|
|
|
|
.DIRECTORY_COLOR =
|
|
FOREGROUND_RED | FOREGROUND_INTENSITY, // Bright pink for directory
|
|
|
|
.EXECUTABLE_COLOR = FOREGROUND_RED | FOREGROUND_GREEN,
|
|
.TEXT_FILE_COLOR = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
|
|
.IMAGE_FILE_COLOR = FOREGROUND_BLUE,
|
|
.CODE_FILE_COLOR = FOREGROUND_BLUE,
|
|
.ARCHIVE_FILE_COLOR = FOREGROUND_RED,
|
|
|
|
.SYNTAX_KEYWORD = FOREGROUND_RED | FOREGROUND_BLUE,
|
|
.SYNTAX_STRING = FOREGROUND_GREEN,
|
|
.SYNTAX_COMMENT = FOREGROUND_RED | FOREGROUND_GREEN | 0x8,
|
|
.SYNTAX_NUMBER = FOREGROUND_RED,
|
|
.SYNTAX_PREPROCESSOR = FOREGROUND_RED | FOREGROUND_GREEN,
|
|
|
|
// ANSI true color definitions - exact Rose Pine colors
|
|
.ANSI_BASE = "\033[38;2;25;23;36m", // Base color
|
|
.ANSI_SURFACE = "\033[38;2;31;29;46m", // Surface color
|
|
.ANSI_OVERLAY = "\033[38;2;38;35;58m", // Overlay color
|
|
.ANSI_MUTED = "\033[38;2;110;106;134m", // Muted color
|
|
.ANSI_SUBTLE = "\033[38;2;144;140;170m", // Subtle color
|
|
.ANSI_TEXT = "\033[38;2;224;222;244m", // Text color
|
|
.ANSI_LOVE = "\033[38;2;235;111;146m", // Love/Red color
|
|
.ANSI_GOLD = "\033[38;2;246;193;119m", // Gold color
|
|
// Updated Rose/pink color to a soft peach
|
|
.ANSI_ROSE = "\033[38;2;255;195;195m", // Soft Peach
|
|
.ANSI_PINE = "\033[38;2;49;116;143m", // Pine color
|
|
.ANSI_FOAM = "\033[38;2;156;207;216m", // Foam color
|
|
.ANSI_IRIS = "\033[38;2;196;167;231m", // Iris color
|
|
.ANSI_HIGHLIGHT = "\033[38;2;68;65;90m", // Highlight color
|
|
.ANSI_INVALID_COMMAND = "\033[38;2;205;120;120m",
|
|
|
|
// Enable ANSI colors for Rose Pine theme
|
|
.use_ansi_colors = TRUE,
|
|
|
|
.name = "rose-pine"};
|
|
|
|
static ShellTheme catppuccin_mocha_theme = {
|
|
// Legacy console colors (for backward compatibility)
|
|
.PRIMARY_COLOR = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE |
|
|
FOREGROUND_INTENSITY, // Bright white for text
|
|
.SECONDARY_COLOR =
|
|
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, // White (dimmer)
|
|
.ACCENT_COLOR =
|
|
FOREGROUND_BLUE | FOREGROUND_INTENSITY, // Bright Blue for accent
|
|
.SUCCESS_COLOR = FOREGROUND_GREEN | FOREGROUND_INTENSITY, // Bright Green
|
|
.ERROR_COLOR = FOREGROUND_RED | FOREGROUND_INTENSITY, // Bright Red
|
|
.WARNING_COLOR =
|
|
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY, // Yellow
|
|
|
|
.HEADER_COLOR = FOREGROUND_RED | FOREGROUND_BLUE |
|
|
FOREGROUND_INTENSITY, // Mauve color for headers
|
|
.STATUS_BAR_COLOR = 0, // Black/dark background
|
|
.STATUS_TEXT_COLOR = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE |
|
|
FOREGROUND_INTENSITY, // Bright White
|
|
.PROMPT_COLOR = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE |
|
|
FOREGROUND_INTENSITY, // Blue text for prompt
|
|
|
|
.DIRECTORY_COLOR = FOREGROUND_BLUE | FOREGROUND_GREEN |
|
|
FOREGROUND_INTENSITY, // Teal for directories
|
|
.EXECUTABLE_COLOR = FOREGROUND_RED | FOREGROUND_GREEN |
|
|
FOREGROUND_INTENSITY, // Yellow for executables
|
|
.TEXT_FILE_COLOR = FOREGROUND_RED | FOREGROUND_GREEN |
|
|
FOREGROUND_BLUE, // White for text files
|
|
.IMAGE_FILE_COLOR = FOREGROUND_RED | FOREGROUND_INTENSITY, // Red for images
|
|
.CODE_FILE_COLOR = FOREGROUND_BLUE | FOREGROUND_INTENSITY, // Blue for code
|
|
.ARCHIVE_FILE_COLOR =
|
|
FOREGROUND_GREEN | FOREGROUND_INTENSITY, // Green for archives
|
|
|
|
.SYNTAX_KEYWORD =
|
|
FOREGROUND_BLUE | FOREGROUND_INTENSITY, // Blue for keywords
|
|
.SYNTAX_STRING =
|
|
FOREGROUND_GREEN | FOREGROUND_INTENSITY, // Green for strings
|
|
.SYNTAX_COMMENT = FOREGROUND_INTENSITY, // Gray for comments
|
|
.SYNTAX_NUMBER = FOREGROUND_RED | FOREGROUND_INTENSITY, // Red for numbers
|
|
.SYNTAX_PREPROCESSOR = FOREGROUND_GREEN | FOREGROUND_BLUE |
|
|
FOREGROUND_INTENSITY, // Cyan for preprocessor
|
|
|
|
// ANSI true color definitions for Catppuccin Mocha
|
|
.ANSI_BASE = "\033[38;2;30;30;46m", // Base color #1e1e2e
|
|
.ANSI_SURFACE = "\033[38;2;49;50;68m", // Surface color #313244
|
|
.ANSI_OVERLAY = "\033[38;2;69;71;90m", // Overlay color #45475a
|
|
.ANSI_MUTED = "\033[38;2;186;194;222m", // Muted color #bac2de (subtext1)
|
|
.ANSI_SUBTLE = "\033[38;2;166;173;200m", // Subtle color #a6adc8 (subtext0)
|
|
.ANSI_TEXT = "\033[38;2;205;214;244m", // Text color #cdd6f4
|
|
.ANSI_LOVE = "\033[38;2;243;139;168m", // Love/Red color #f38ba8
|
|
.ANSI_GOLD = "\033[38;2;249;226;175m", // Gold/Yellow color #f9e2af
|
|
.ANSI_ROSE = "\033[38;2;245;194;231m", // Pink color #f5c2e7
|
|
.ANSI_PINE = "\033[38;2;166;227;161m", // Green color #a6e3a1
|
|
.ANSI_FOAM = "\033[38;2;148;226;213m", // Teal color #94e2d5
|
|
.ANSI_IRIS = "\033[38;2;203;166;247m", // Mauve/Purple color #cba6f7
|
|
.ANSI_HIGHLIGHT = "\033[38;2;180;190;254m", // Lavender highlight #b4befe
|
|
|
|
// Enable ANSI colors for Catppuccin Mocha theme
|
|
.use_ansi_colors = TRUE,
|
|
|
|
.name = "catppuccin-mocha"};
|
|
|
|
// Path to the theme configuration file
|
|
char theme_config_path[PATH_MAX];
|
|
|
|
/**
|
|
* Initialize the theme system
|
|
*/
|
|
void init_theme_system(void) {
|
|
// Determine theme config file location in user's home directory
|
|
char *home_dir = getenv("HOME");
|
|
if (home_dir) {
|
|
snprintf(theme_config_path, PATH_MAX, "%s/.lsh_theme", home_dir);
|
|
} else {
|
|
// Fallback to current directory if HOME not available
|
|
strcpy(theme_config_path, ".lsh_theme");
|
|
}
|
|
|
|
// Set default theme initially
|
|
memcpy(¤t_theme, &default_theme, sizeof(ShellTheme));
|
|
|
|
// Try to load theme from config file
|
|
FILE *config_file = fopen(theme_config_path, "r");
|
|
if (config_file) {
|
|
char theme_name[32];
|
|
if (fscanf(config_file, "theme=%31s", theme_name) == 1) {
|
|
// We found a theme name, try to load it
|
|
load_theme(theme_name);
|
|
}
|
|
fclose(config_file);
|
|
} else {
|
|
// Config file doesn't exist, create it with default theme
|
|
config_file = fopen(theme_config_path, "w");
|
|
if (config_file) {
|
|
fprintf(config_file, "theme=default\n");
|
|
fclose(config_file);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Load a specific theme by name
|
|
*
|
|
* @param theme_name Name of the theme to load
|
|
* @return 1 if successful, 0 if theme not found
|
|
*/
|
|
int load_theme(const char *theme_name) {
|
|
if (strcmp(theme_name, "default") == 0) {
|
|
memcpy(¤t_theme, &default_theme, sizeof(ShellTheme));
|
|
return 1;
|
|
} else if (strcmp(theme_name, "rose-pine") == 0) {
|
|
memcpy(¤t_theme, &rose_pine_theme, sizeof(ShellTheme));
|
|
return 1;
|
|
} else if (strcmp(theme_name, "catppuccin-mocha") == 0) {
|
|
memcpy(¤t_theme, &catppuccin_mocha_theme, sizeof(ShellTheme));
|
|
return 1;
|
|
}
|
|
|
|
// Theme not found
|
|
fprintf(stderr, "Theme '%s' not found\n", theme_name);
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Apply the current theme settings
|
|
* Called whenever theme-dependent UI elements need to be updated
|
|
*/
|
|
void apply_current_theme(void) {
|
|
// When called, the shell can update any on-screen elements that depend on
|
|
// theme colors. This function would be called when changing themes or at startup.
|
|
|
|
// In Linux, we'll always use ANSI colors, as the terminal emulator handles this natively
|
|
if (current_theme.use_ansi_colors) {
|
|
// Use ANSI true color
|
|
printf("%s", current_theme.ANSI_TEXT);
|
|
} else {
|
|
// Use standard ANSI color approximation of the theme's primary color
|
|
// Linux terminals always support basic ANSI colors, so we'll map the Windows color attributes
|
|
// to the closest ANSI colors
|
|
|
|
int fg = 37; // Default to white text
|
|
|
|
if (current_theme.PRIMARY_COLOR & 0x01) fg = 34; // Blue
|
|
if (current_theme.PRIMARY_COLOR & 0x02) fg = 32; // Green
|
|
if (current_theme.PRIMARY_COLOR & 0x04) fg = 31; // Red
|
|
|
|
// Combinations
|
|
if ((current_theme.PRIMARY_COLOR & 0x03) == 0x03) fg = 36; // Cyan (Green + Blue)
|
|
if ((current_theme.PRIMARY_COLOR & 0x05) == 0x05) fg = 35; // Magenta (Red + Blue)
|
|
if ((current_theme.PRIMARY_COLOR & 0x06) == 0x06) fg = 33; // Yellow (Red + Green)
|
|
if ((current_theme.PRIMARY_COLOR & 0x07) == 0x07) fg = 37; // White (Red + Green + Blue)
|
|
|
|
// Bright variants
|
|
if (current_theme.PRIMARY_COLOR & 0x08) fg += 60; // Add intensity
|
|
|
|
printf("\033[%dm", fg); // Set the color
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get pointer to the current theme
|
|
*
|
|
* @return Pointer to the current theme structure
|
|
*/
|
|
const ShellTheme *get_current_theme(void) { return ¤t_theme; }
|
|
|
|
/**
|
|
* List all available themes
|
|
*/
|
|
void list_available_themes(void) {
|
|
printf("Available themes:\n");
|
|
printf(" default - Standard shell colors\n");
|
|
printf(
|
|
" rose-pine - Soothing, warm color scheme with true color support\n");
|
|
printf(" catppuccin-mocha - Deep dark theme with vibrant accent colors");
|
|
|
|
// Display which theme is currently active
|
|
printf("\nCurrent theme: %s", current_theme.name);
|
|
|
|
// Display ANSI color status for current theme
|
|
if (current_theme.use_ansi_colors) {
|
|
printf(" (using true color)\n");
|
|
} else {
|
|
printf(" (using standard console colors)\n");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initialize themes at shell startup
|
|
*/
|
|
void init_themes(void) {
|
|
// Call the theme system initialization
|
|
init_theme_system();
|
|
|
|
// Apply the initial theme
|
|
apply_current_theme();
|
|
}
|
|
|
|
/**
|
|
* Shutdown theme system
|
|
*/
|
|
void shutdown_themes(void) {
|
|
// Reset terminal color to default
|
|
printf(ANSI_COLOR_RESET);
|
|
|
|
// Currently, no other cleanup is needed for the theme system
|
|
}
|
|
|
|
/**
|
|
* Command handler for the "theme" command
|
|
*
|
|
* @param args Command arguments
|
|
* @return 1 to continue shell execution, 0 to exit shell
|
|
*/
|
|
int lsh_theme(char **args) {
|
|
if (args[1] == NULL) {
|
|
// No arguments, show usage info and current theme
|
|
printf("Usage: theme <command> [arguments]\n");
|
|
printf("Commands:\n");
|
|
printf(" list List available themes\n");
|
|
printf(" set NAME Set the current theme to NAME\n");
|
|
printf(" show Show current theme details\n");
|
|
printf("\nCurrent theme: %s", current_theme.name);
|
|
|
|
// Display ANSI color status for current theme
|
|
if (current_theme.use_ansi_colors) {
|
|
printf(" (using true color)\n");
|
|
} else {
|
|
printf(" (using standard console colors)\n");
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
// Handle subcommands
|
|
if (strcmp(args[1], "list") == 0) {
|
|
list_available_themes();
|
|
return 1;
|
|
} else if (strcmp(args[1], "set") == 0) {
|
|
if (args[2] == NULL) {
|
|
printf("Usage: theme set <theme_name>\n");
|
|
printf("Try 'theme list' to see available themes\n");
|
|
return 1;
|
|
}
|
|
|
|
// Try to load the requested theme
|
|
if (load_theme(args[2])) {
|
|
// Update theme config file
|
|
FILE *config_file = fopen(theme_config_path, "w");
|
|
if (config_file) {
|
|
fprintf(config_file, "theme=%s\n", args[2]);
|
|
fclose(config_file);
|
|
|
|
// Apply the theme
|
|
apply_current_theme();
|
|
|
|
printf("Theme set to '%s'\n", args[2]);
|
|
|
|
// Display ANSI color status for the selected theme
|
|
if (current_theme.use_ansi_colors) {
|
|
printf("This theme uses true color for better visual appearance.\n");
|
|
}
|
|
} else {
|
|
fprintf(stderr, "Could not save theme setting\n");
|
|
}
|
|
}
|
|
return 1;
|
|
} else if (strcmp(args[1], "show") == 0) {
|
|
printf("Current theme: %s\n", current_theme.name);
|
|
|
|
// Display ANSI color status
|
|
if (current_theme.use_ansi_colors) {
|
|
printf("Using true color mode");
|
|
|
|
// Show a color demo if using ANSI colors
|
|
printf("\nColor sample:\n");
|
|
printf("%sBase %sText %sLove %sGold %sRose %sPine %sFoam %sIris%s\n",
|
|
current_theme.ANSI_BASE, current_theme.ANSI_TEXT,
|
|
current_theme.ANSI_LOVE, current_theme.ANSI_GOLD,
|
|
current_theme.ANSI_ROSE, current_theme.ANSI_PINE,
|
|
current_theme.ANSI_FOAM, current_theme.ANSI_IRIS,
|
|
"\033[0m"); // Reset
|
|
} else {
|
|
printf("Using standard console colors\n");
|
|
}
|
|
|
|
return 1;
|
|
} else {
|
|
printf("Unknown theme command: %s\n", args[1]);
|
|
printf("Try 'theme list' or 'theme set <name>'\n");
|
|
return 1;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
char **get_theme_names(int *theme_count) {
|
|
// Define the hardcoded themes
|
|
char *builtin_themes[] = {"default", "rose-pine", "catppuccin-mocha"};
|
|
int builtin_count = sizeof(builtin_themes) / sizeof(builtin_themes[0]);
|
|
|
|
// Try to open the theme config file to check for custom themes
|
|
FILE *config_file = fopen(theme_config_path, "r");
|
|
char custom_theme[32];
|
|
int has_custom_theme = 0;
|
|
|
|
if (config_file) {
|
|
char theme_line[64];
|
|
while (fgets(theme_line, sizeof(theme_line), config_file)) {
|
|
if (sscanf(theme_line, "theme=%31s", custom_theme) == 1) {
|
|
// Check if this is a custom theme (not one of our builtin themes)
|
|
int is_builtin = 0;
|
|
for (int i = 0; i < builtin_count; i++) {
|
|
if (strcmp(custom_theme, builtin_themes[i]) == 0) {
|
|
is_builtin = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!is_builtin) {
|
|
has_custom_theme = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
fclose(config_file);
|
|
}
|
|
|
|
// Allocate space for themes (builtin + potential custom theme)
|
|
int total_themes = builtin_count + (has_custom_theme ? 1 : 0);
|
|
char **theme_names = (char **)malloc(total_themes * sizeof(char *));
|
|
if (!theme_names) {
|
|
fprintf(stderr, "lsh: allocation error in get_theme_names\n");
|
|
*theme_count = 0;
|
|
return NULL;
|
|
}
|
|
|
|
// Copy builtin theme names
|
|
for (int i = 0; i < builtin_count; i++) {
|
|
theme_names[i] = strdup(builtin_themes[i]);
|
|
}
|
|
|
|
// Add custom theme if found
|
|
if (has_custom_theme) {
|
|
theme_names[builtin_count] = strdup(custom_theme);
|
|
}
|
|
|
|
*theme_count = total_themes;
|
|
return theme_names;
|
|
}
|