add c and jai

This commit is contained in:
2026-07-13 13:02:47 -04:00
parent cf8342f8d4
commit c5b14d7c41
33 changed files with 6306 additions and 0 deletions

235
c/config/config.c Normal file
View File

@@ -0,0 +1,235 @@
// config.c — Global program configuration (config.ini next to binary)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifdef __APPLE__
#include <unistd.h>
#include <libgen.h>
#include <mach-o/dyld.h>
#else
#include <windows.h>
#endif
Config g_config = {0};
////////////////////////////////
// Path resolution
static void config_get_path(char *out, S32 out_size) {
char exe_path[CONFIG_PATH_MAX];
#ifdef __APPLE__
U32 sz = sizeof(exe_path);
_NSGetExecutablePath(exe_path, &sz);
#else
GetModuleFileNameA(NULL, exe_path, CONFIG_PATH_MAX);
#endif
// Strip binary name to get directory
char *sep = strrchr(exe_path, '/');
#ifndef __APPLE__
char *bsep = strrchr(exe_path, '\\');
if (bsep && (!sep || bsep > sep)) sep = bsep;
#endif
if (sep) sep[1] = '\0';
snprintf(out, out_size, "%sconfig.ini", exe_path);
}
////////////////////////////////
// Helpers
static void config_trim(char *s) {
char *start = s;
while (*start == ' ' || *start == '\t') start++;
if (start != s) memmove(s, start, strlen(start) + 1);
S32 len = (S32)strlen(s);
while (len > 0 && (s[len - 1] == ' ' || s[len - 1] == '\t' ||
s[len - 1] == '\r' || s[len - 1] == '\n'))
s[--len] = '\0';
}
////////////////////////////////
// Defaults
static void config_set_defaults(void) {
MemoryZeroStruct(&g_config);
snprintf(g_config.theme, sizeof(g_config.theme), "%s", "Gruvbox Dark");
g_config.show_line_numbers = 1;
g_config.syntax_enabled = 1;
g_config.block_cursor = 1;
g_config.cursor_smear = 1;
g_config.smooth_scroll = 1;
g_config.ui_scale = 1.0f;
g_config.editor_font_size = 15.0f;
snprintf(g_config.editor_font, sizeof(g_config.editor_font), "%s", "FiraCode");
snprintf(g_config.ui_font, sizeof(g_config.ui_font), "%s", "Inter");
g_config.window_width = 1280;
g_config.window_height = 800;
g_config.active_project[0] = '\0';
g_config.recent_dir_count = 0;
}
////////////////////////////////
// Load
static void config_load(void) {
config_set_defaults();
char path[CONFIG_PATH_MAX];
config_get_path(path, sizeof(path));
FILE *f = fopen(path, "rb");
if (!f) {
// No config file — write defaults
config_save();
return;
}
char line_buf[CONFIG_PATH_MAX + 64];
char current_section[64] = {0};
while (fgets(line_buf, sizeof(line_buf), f)) {
config_trim(line_buf);
if (line_buf[0] == '\0' || line_buf[0] == '#' || line_buf[0] == ';')
continue;
// Section header
if (line_buf[0] == '[') {
char *close = strchr(line_buf, ']');
if (close) {
*close = '\0';
snprintf(current_section, sizeof(current_section), "%s", line_buf + 1);
}
continue;
}
// Key = value
char *eq = strchr(line_buf, '=');
if (!eq) continue;
*eq = '\0';
char *key = line_buf;
char *val = eq + 1;
config_trim(key);
config_trim(val);
if (strcmp(current_section, "general") == 0) {
if (strcmp(key, "theme") == 0)
snprintf(g_config.theme, sizeof(g_config.theme), "%s", val);
else if (strcmp(key, "show_line_numbers") == 0)
g_config.show_line_numbers = (strcmp(val, "true") == 0);
else if (strcmp(key, "syntax_enabled") == 0)
g_config.syntax_enabled = (strcmp(val, "true") == 0);
else if (strcmp(key, "block_cursor") == 0)
g_config.block_cursor = (strcmp(val, "true") == 0);
else if (strcmp(key, "cursor_smear") == 0)
g_config.cursor_smear = (strcmp(val, "true") == 0);
else if (strcmp(key, "smooth_scroll") == 0)
g_config.smooth_scroll = (strcmp(val, "true") == 0);
else if (strcmp(key, "ui_scale") == 0)
g_config.ui_scale = (F32)atof(val);
else if (strcmp(key, "editor_font_size") == 0)
g_config.editor_font_size = (F32)atof(val);
else if (strcmp(key, "editor_font") == 0)
snprintf(g_config.editor_font, sizeof(g_config.editor_font), "%s", val);
else if (strcmp(key, "ui_font") == 0)
snprintf(g_config.ui_font, sizeof(g_config.ui_font), "%s", val);
else if (strcmp(key, "active_project") == 0)
snprintf(g_config.active_project, sizeof(g_config.active_project), "%s", val);
else if (strcmp(key, "window_width") == 0)
g_config.window_width = atoi(val);
else if (strcmp(key, "window_height") == 0)
g_config.window_height = atoi(val);
} else if (strcmp(current_section, "recent_dirs") == 0) {
// Keys are "0", "1", "2", etc.
S32 idx = atoi(key);
if (idx >= 0 && idx < CONFIG_MAX_RECENT_DIRS && val[0] != '\0') {
snprintf(g_config.recent_dirs[idx], CONFIG_PATH_MAX, "%s", val);
if (idx + 1 > g_config.recent_dir_count)
g_config.recent_dir_count = idx + 1;
}
}
}
fclose(f);
}
////////////////////////////////
// Save
static void config_save(void) {
char path[CONFIG_PATH_MAX];
config_get_path(path, sizeof(path));
FILE *f = fopen(path, "wb");
if (!f) return;
fprintf(f, "# codeMAX configuration — managed by the program\r\n\r\n");
fprintf(f, "[general]\r\n");
fprintf(f, "theme = %s\r\n", g_config.theme);
fprintf(f, "show_line_numbers = %s\r\n", g_config.show_line_numbers ? "true" : "false");
fprintf(f, "syntax_enabled = %s\r\n", g_config.syntax_enabled ? "true" : "false");
fprintf(f, "block_cursor = %s\r\n", g_config.block_cursor ? "true" : "false");
fprintf(f, "cursor_smear = %s\r\n", g_config.cursor_smear ? "true" : "false");
fprintf(f, "smooth_scroll = %s\r\n", g_config.smooth_scroll ? "true" : "false");
fprintf(f, "ui_scale = %.2f\r\n", g_config.ui_scale);
fprintf(f, "editor_font_size = %.1f\r\n", g_config.editor_font_size);
fprintf(f, "editor_font = %s\r\n", g_config.editor_font);
fprintf(f, "ui_font = %s\r\n", g_config.ui_font);
fprintf(f, "window_width = %d\r\n", g_config.window_width);
fprintf(f, "window_height = %d\r\n", g_config.window_height);
if (g_config.active_project[0] != '\0')
fprintf(f, "active_project = %s\r\n", g_config.active_project);
fprintf(f, "\r\n[recent_dirs]\r\n");
for (S32 i = 0; i < g_config.recent_dir_count; i++) {
if (g_config.recent_dirs[i][0] != '\0')
fprintf(f, "%d = %s\r\n", i, g_config.recent_dirs[i]);
}
fclose(f);
}
////////////////////////////////
// Recent directories
static void config_push_recent_dir(const char *dir) {
if (!dir || dir[0] == '\0') return;
// Normalize path for comparison
char norm[CONFIG_PATH_MAX];
snprintf(norm, sizeof(norm), "%s", dir);
for (char *p = norm; *p; p++) {
if (*p == '/') *p = '\\';
}
// Check if already in list — if so, move to front
S32 existing = -1;
for (S32 i = 0; i < g_config.recent_dir_count; i++) {
#ifdef __APPLE__
if (strcmp(g_config.recent_dirs[i], norm) == 0) { existing = i; break; }
#else
if (_stricmp(g_config.recent_dirs[i], norm) == 0) { existing = i; break; }
#endif
}
if (existing == 0) return; // already at front
// Save the entry if it exists, or use the new dir
char entry[CONFIG_PATH_MAX];
snprintf(entry, sizeof(entry), "%s", norm);
// Shift entries down
S32 start = (existing >= 0) ? existing : g_config.recent_dir_count;
if (start >= CONFIG_MAX_RECENT_DIRS) start = CONFIG_MAX_RECENT_DIRS - 1;
for (S32 i = start; i > 0; i--)
memcpy(g_config.recent_dirs[i], g_config.recent_dirs[i - 1], CONFIG_PATH_MAX);
// Insert at front
snprintf(g_config.recent_dirs[0], CONFIG_PATH_MAX, "%s", entry);
if (existing < 0 && g_config.recent_dir_count < CONFIG_MAX_RECENT_DIRS)
g_config.recent_dir_count++;
config_save();
}