diff --git a/boredos.iso b/boredos.iso index 19ad12d..53c2915 100644 Binary files a/boredos.iso and b/boredos.iso differ diff --git a/build/about.o b/build/about.o deleted file mode 100644 index 97da44e..0000000 Binary files a/build/about.o and /dev/null differ diff --git a/build/cmd.o b/build/cmd.o index bb8f11e..1d98b59 100644 Binary files a/build/cmd.o and b/build/cmd.o differ diff --git a/build/explorer.o b/build/explorer.o index 04fef95..77b3f76 100644 Binary files a/build/explorer.o and b/build/explorer.o differ diff --git a/src/kernel/about.c b/src/kernel/about.c deleted file mode 100644 index 1595d1f..0000000 --- a/src/kernel/about.c +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2023-2026 Chris (boreddevnl) -// This software is released under the GNU General Public License v3.0. See LICENSE file for details. -// This header needs to maintain in any file it is present in, as per the GPL license terms. -#include "about.h" -#include "graphics.h" -#include "wm.h" -#include - -Window win_about; - -static void about_paint(Window *win) { - int offset_x = win->x + 15; - int offset_y = win->y + 35; - - - draw_boredos_logo(win->x + 60, offset_y, 4); - - // Version info - draw_string(offset_x, offset_y + 105, "BoredOS 'Panda'", COLOR_WHITE); - draw_string(offset_x, offset_y + 120, "BoredOS Version 1.64", COLOR_WHITE); - draw_string(offset_x, offset_y + 135, "Kernel Version 3.0.0", COLOR_WHITE); - - // Copyright - draw_string(offset_x, offset_y + 150, "(C) 2026 boreddevnl.", COLOR_WHITE); - draw_string(offset_x, offset_y + 165, "All rights reserved.", COLOR_WHITE); -} - -static void about_click(Window *win, int x, int y) { - (void)win; - (void)x; - (void)y; - // No interactive elements needed for About dialog -} - -void about_init(void) { - win_about.title = "About BoredOS"; - win_about.x = 250; - win_about.y = 180; - win_about.w = 185; - win_about.h = 240; - win_about.visible = false; - win_about.focused = false; - win_about.z_index = 0; - win_about.paint = about_paint; - win_about.handle_click = about_click; - win_about.handle_right_click = NULL; - win_about.handle_key = NULL; -} diff --git a/src/kernel/about.h b/src/kernel/about.h deleted file mode 100644 index ea19e0c..0000000 --- a/src/kernel/about.h +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) 2023-2026 Chris (boreddevnl) -// This software is released under the GNU General Public License v3.0. See LICENSE file for details. -// This header needs to maintain in any file it is present in, as per the GPL license terms. -#ifndef ABOUT_H -#define ABOUT_H - -#include "wm.h" - -extern Window win_about; - -void about_init(void); - -#endif diff --git a/src/kernel/cmd.c b/src/kernel/cmd.c index b3cf54f..8efb8fc 100644 --- a/src/kernel/cmd.c +++ b/src/kernel/cmd.c @@ -43,6 +43,35 @@ typedef enum { MODE_PAGER } CmdMode; +// Shell Configuration +typedef struct { + uint32_t prompt_drive_color; + uint32_t prompt_colon_color; + uint32_t prompt_dir_color; + uint32_t prompt_op_color; + char prompt_op_char; + uint32_t default_text_color; + uint32_t bg_color; + uint32_t cursor_color; + bool show_drive; + bool show_dir; + uint32_t dir_color; + uint32_t file_color; + uint32_t size_color; + uint32_t error_color; + uint32_t success_color; + uint32_t help_color; + uint32_t command_color; + char title_text[64]; + char custom_welcome_message[128]; + char startup_cmd[128]; + char prompt_suffix[32]; + bool welcome_msg; + bool history_save_prompt; +} ShellConfig; + +static ShellConfig shell_config; + // CMD Window State (per-window context) typedef struct { char current_drive; @@ -58,6 +87,7 @@ static int cursor_row = 0; static int cursor_col = 0; static uint32_t current_color = COLOR_DARK_TEXT; static CmdState *cmd_state = NULL; // Will be set in cmd_init +static int current_prompt_len = 0; // Pager State static CmdMode current_mode = MODE_SHELL; @@ -129,6 +159,290 @@ static void itoa(int n, char *buf) { buf[j] = buf[i - 1 - j]; buf[i - 1 - j] = t; } + buf[i] = 0; +} + +// --- Configuration Parsing --- + +static bool parse_bool(const char *s) { + if (!s) return false; + while (*s == ' ' || *s == '\t') s++; + if (cmd_strcmp(s, "true") == 0 || cmd_strcmp(s, "1") == 0 || cmd_strcmp(s, "yes") == 0) return true; + return false; +} + +static int parse_int(const char *s) { + if (!s) return 0; + while (*s == ' ' || *s == '\t') s++; + int res = 0; + int sign = 1; + if (*s == '-') { sign = -1; s++; } + while (*s >= '0' && *s <= '9') { + res = res * 10 + (*s - '0'); + s++; + } + return res * sign; +} + +static uint32_t parse_color(const char *s) { + if (!s) return 0; + while (*s == ' ' || *s == '\t') s++; + if (!*s) return 0; + + // 1. HEX Format: #RRGGBB or 0xRRGGBB + if (s[0] == '#' || (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))) { + const char *hex = (s[0] == '#') ? s + 1 : s + 2; + uint32_t res = 0; + int count = 0; + while (*hex && count < 8) { + char c = *hex++; + if (c >= '0' && c <= '9') res = (res << 4) | (c - '0'); + else if (c >= 'a' && c <= 'f') res = (res << 4) | (c - 'a' + 10); + else if (c >= 'A' && c <= 'F') res = (res << 4) | (c - 'A' + 10); + else break; + count++; + } + if (count == 6) res |= 0xFF000000; + return res; + } + + // 2. RGB Format: rgb(r, g, b) + if (s[0] == 'r' && s[1] == 'g' && s[2] == 'b') { + const char *p = s + 3; + while (*p && *p != '(') p++; + if (*p == '(') { + p++; + while (*p == ' ' || *p == '\t') p++; + int r = parse_int(p); + while (*p && *p != ',' && *p != ')') p++; + if (*p == ',') { + p++; + while (*p == ' ' || *p == '\t') p++; + int g = parse_int(p); + while (*p && *p != ',' && *p != ')') p++; + if (*p == ',') { + p++; + while (*p == ' ' || *p == '\t') p++; + int b = parse_int(p); + return 0xFF000000 | ((uint32_t)(r & 0xFF) << 16) | ((uint32_t)(g & 0xFF) << 8) | (uint32_t)(b & 0xFF); + } + } + } + } + + // 3. Named Colors (assuming s is trimmed and lowercased) + if (cmd_strcmp(s, "black") == 0) return 0xFF000000; + if (cmd_strcmp(s, "white") == 0) return 0xFFFFFFFF; + if (cmd_strcmp(s, "gray") == 0 || cmd_strcmp(s, "grey") == 0) return 0xFF808080; + if (cmd_strcmp(s, "lightgray") == 0 || cmd_strcmp(s, "light gray") == 0 || cmd_strcmp(s, "lightgrey") == 0 || cmd_strcmp(s, "light grey") == 0) return 0xFFD3D3D3; + if (cmd_strcmp(s, "darkgray") == 0 || cmd_strcmp(s, "dark gray") == 0 || cmd_strcmp(s, "darkgrey") == 0 || cmd_strcmp(s, "dark grey") == 0) return 0xFFA9A9A9; + + if (cmd_strcmp(s, "red") == 0) return 0xFFFF0000; + if (cmd_strcmp(s, "lightred") == 0 || cmd_strcmp(s, "light red") == 0) return 0xFFFF7F7F; + if (cmd_strcmp(s, "darkred") == 0 || cmd_strcmp(s, "dark red") == 0) return 0xFF8B0000; + + if (cmd_strcmp(s, "green") == 0) return 0xFF00FF00; + if (cmd_strcmp(s, "lightgreen") == 0 || cmd_strcmp(s, "light green") == 0) return 0xFF90EE90; + if (cmd_strcmp(s, "darkgreen") == 0 || cmd_strcmp(s, "dark green") == 0) return 0xFF006400; + + if (cmd_strcmp(s, "yellow") == 0) return 0xFFFFFF00; + if (cmd_strcmp(s, "lightyellow") == 0 || cmd_strcmp(s, "light yellow") == 0) return 0xFFFFFFE0; + + if (cmd_strcmp(s, "blue") == 0) return 0xFF0000FF; + if (cmd_strcmp(s, "lightblue") == 0 || cmd_strcmp(s, "light blue") == 0) return 0xFFADD8E6; + if (cmd_strcmp(s, "darkblue") == 0 || cmd_strcmp(s, "dark blue") == 0) return 0xFF00008B; + + if (cmd_strcmp(s, "magenta") == 0) return 0xFFFF00FF; + if (cmd_strcmp(s, "lightmagenta") == 0 || cmd_strcmp(s, "light magenta") == 0) return 0xFFFF77FF; + + if (cmd_strcmp(s, "cyan") == 0 || cmd_strcmp(s, "aqua") == 0) return 0xFF00FFFF; + if (cmd_strcmp(s, "lightcyan") == 0 || cmd_strcmp(s, "light cyan") == 0) return 0xFFE0FFFF; + + if (cmd_strcmp(s, "orange") == 0) return 0xFFFFA500; + if (cmd_strcmp(s, "brown") == 0) return 0xFFA52A2A; + if (cmd_strcmp(s, "pink") == 0) return 0xFFFFC0CB; + if (cmd_strcmp(s, "purple") == 0) return 0xFF800080; + if (cmd_strcmp(s, "teal") == 0) return 0xFF008080; + if (cmd_strcmp(s, "lime") == 0) return 0xFF00FF00; + if (cmd_strcmp(s, "maroon") == 0) return 0xFF800000; + if (cmd_strcmp(s, "navy") == 0) return 0xFF000080; + if (cmd_strcmp(s, "indigo") == 0) return 0xFF4B0082; + if (cmd_strcmp(s, "violet") == 0) return 0xFFEE82EE; + + // 4. Fallback: Loose Hex (e.g. "FF00FF") + const char *hex = s; + uint32_t res = 0; + int count = 0; + while (*hex && count < 8) { + char c = *hex++; + if (c >= '0' && c <= '9') res = (res << 4) | (c - '0'); + else if (c >= 'a' && c <= 'f') res = (res << 4) | (c - 'a' + 10); + else if (c >= 'A' && c <= 'F') res = (res << 4) | (c - 'A' + 10); + else break; + count++; + } + if (count == 6) res |= 0xFF000000; + return res; +} + +static void cmd_init_config_defaults(void) { + shell_config.prompt_drive_color = 0xFFCCCCCC; // Default light gray + shell_config.prompt_colon_color = 0xFFCCCCCC; + shell_config.prompt_dir_color = 0xFF569CD6; // Blue + shell_config.prompt_op_color = 0xFFCCCCCC; + shell_config.prompt_op_char = '>'; + shell_config.default_text_color = 0xFFCCCCCC; + shell_config.bg_color = 0xFF1E1E1E; // Dark background + shell_config.cursor_color = 0xFFFFFFFF; + shell_config.show_drive = true; + shell_config.show_dir = true; + shell_config.dir_color = 0xFF569CD6; + shell_config.file_color = 0xFFCCCCCC; + shell_config.size_color = 0xFF6A9955; // Green + shell_config.error_color = 0xFFFF4444; // Red + shell_config.success_color = 0xFF6A9955; + shell_config.help_color = 0xFFCCCCCC; + shell_config.command_color = 0xFFFFFFFF; // White typed text + cmd_strcpy(shell_config.title_text, "Command Prompt"); + cmd_strcpy(shell_config.custom_welcome_message, ""); + cmd_strcpy(shell_config.startup_cmd, ""); + cmd_strcpy(shell_config.prompt_suffix, " "); + shell_config.welcome_msg = true; + shell_config.history_save_prompt = true; +} + +void cmd_load_config(void) { + cmd_init_config_defaults(); + + FAT32_FileHandle *fh = fat32_open("Library/conf/shell.cfg", "r"); + if (!fh) return; + + char buffer[4096]; + int bytes = fat32_read(fh, buffer, sizeof(buffer) - 1); + fat32_close(fh); + + if (bytes <= 0) return; + buffer[bytes] = 0; + + char *line = buffer; + while (*line) { + char *end = line; + while (*end && *end != '\n' && *end != '\r') end++; + + char saved = *end; + *end = 0; + + // Skip comments and empty lines + if (line[0] == '/' && line[1] == '/') { + line = end + (saved ? 1 : 0); + if (saved == '\r' && *line == '\n') line++; + continue; + } + + char *sep = line; + while (*sep && *sep != '=') sep++; + + if (*sep == '=') { + *sep = 0; + char *key = line; + char *val = sep + 1; + + // Trim whitespace from key + char *k_end = sep - 1; + while (k_end > key && (*k_end == ' ' || *k_end == '\t')) { + *k_end-- = 0; + } + + // Trim whitespace from value + while (*val == ' ' || *val == '\t') val++; + char *v_end = val; + while (*v_end) v_end++; + if (v_end > val) { + v_end--; + while (v_end > val && (*v_end == ' ' || *v_end == '\t' || *v_end == '\n' || *v_end == '\r')) { + *v_end-- = 0; + } + } + + // Lowercase value for easier parsing of named colors, EXCEPT for string fields + if (cmd_strcmp(key, "title_text") != 0 && + cmd_strcmp(key, "custom_welcome_message") != 0 && + cmd_strcmp(key, "startup_cmd") != 0 && + cmd_strcmp(key, "prompt_suffix") != 0) { + char *p_low = val; + while (*p_low) { + if (*p_low >= 'A' && *p_low <= 'Z') *p_low += 32; + p_low++; + } + } + + if (cmd_strcmp(key, "prompt_drive_color") == 0) shell_config.prompt_drive_color = parse_color(val); + else if (cmd_strcmp(key, "prompt_colon_color") == 0) shell_config.prompt_colon_color = parse_color(val); + else if (cmd_strcmp(key, "prompt_dir_color") == 0) shell_config.prompt_dir_color = parse_color(val); + else if (cmd_strcmp(key, "prompt_op_color") == 0) shell_config.prompt_op_color = parse_color(val); + else if (cmd_strcmp(key, "prompt_op_char") == 0) { + if (*val) shell_config.prompt_op_char = *val; + } + else if (cmd_strcmp(key, "default_text_color") == 0) shell_config.default_text_color = parse_color(val); + else if (cmd_strcmp(key, "bg_color") == 0) shell_config.bg_color = parse_color(val); + else if (cmd_strcmp(key, "cursor_color") == 0) shell_config.cursor_color = parse_color(val); + else if (cmd_strcmp(key, "show_drive") == 0) shell_config.show_drive = parse_bool(val); + else if (cmd_strcmp(key, "show_dir") == 0) shell_config.show_dir = parse_bool(val); + else if (cmd_strcmp(key, "dir_color") == 0) shell_config.dir_color = parse_color(val); + else if (cmd_strcmp(key, "file_color") == 0) shell_config.file_color = parse_color(val); + else if (cmd_strcmp(key, "size_color") == 0) shell_config.size_color = parse_color(val); + else if (cmd_strcmp(key, "error_color") == 0) shell_config.error_color = parse_color(val); + else if (cmd_strcmp(key, "success_color") == 0) shell_config.success_color = parse_color(val); + else if (cmd_strcmp(key, "help_color") == 0) shell_config.help_color = parse_color(val); + else if (cmd_strcmp(key, "command_color") == 0) shell_config.command_color = parse_color(val); + else if (cmd_strcmp(key, "title_text") == 0) { + cmd_strcpy(shell_config.title_text, val); + } + else if (cmd_strcmp(key, "custom_welcome_message") == 0) { + cmd_strcpy(shell_config.custom_welcome_message, val); + } + else if (cmd_strcmp(key, "startup_cmd") == 0) { + cmd_strcpy(shell_config.startup_cmd, val); + } + else if (cmd_strcmp(key, "prompt_suffix") == 0) { + cmd_strcpy(shell_config.prompt_suffix, val); + } + else if (cmd_strcmp(key, "welcome_msg") == 0) shell_config.welcome_msg = parse_bool(val); + else if (cmd_strcmp(key, "history_save_prompt") == 0) shell_config.history_save_prompt = parse_bool(val); + } + + line = end + (saved ? 1 : 0); + if (saved == '\r' && *line == '\n') line++; + } +} + +// System Call Helper +uint64_t cmd_get_config_value(const char *key) { + if (cmd_strcmp(key, "prompt_drive_color") == 0) return shell_config.prompt_drive_color; + if (cmd_strcmp(key, "prompt_colon_color") == 0) return shell_config.prompt_colon_color; + if (cmd_strcmp(key, "prompt_drive_color") == 0) return shell_config.prompt_drive_color; + if (cmd_strcmp(key, "prompt_colon_color") == 0) return shell_config.prompt_colon_color; + if (cmd_strcmp(key, "prompt_dir_color") == 0) return shell_config.prompt_dir_color; + if (cmd_strcmp(key, "prompt_op_color") == 0) return shell_config.prompt_op_color; + if (cmd_strcmp(key, "default_text_color") == 0) return shell_config.default_text_color; + if (cmd_strcmp(key, "bg_color") == 0) return shell_config.bg_color; + if (cmd_strcmp(key, "cursor_color") == 0) return shell_config.cursor_color; + if (cmd_strcmp(key, "show_drive") == 0) return shell_config.show_drive; + if (cmd_strcmp(key, "show_dir") == 0) return shell_config.show_dir; + if (cmd_strcmp(key, "dir_color") == 0) return shell_config.dir_color; + if (cmd_strcmp(key, "file_color") == 0) return shell_config.file_color; + if (cmd_strcmp(key, "size_color") == 0) return shell_config.size_color; + if (cmd_strcmp(key, "error_color") == 0) return shell_config.error_color; + if (cmd_strcmp(key, "success_color") == 0) return shell_config.success_color; + if (cmd_strcmp(key, "help_color") == 0) return shell_config.help_color; + if (cmd_strcmp(key, "command_color") == 0) return shell_config.command_color; + if (cmd_strcmp(key, "welcome_msg") == 0) return shell_config.welcome_msg; + if (cmd_strcmp(key, "history_save_prompt") == 0) return shell_config.history_save_prompt; + return 0; +} + +void cmd_set_current_color(uint32_t color) { + current_color = color; } // --- History --- @@ -153,25 +467,37 @@ static void cmd_history_add(const char *cmd) { if (history_len < HISTORY_MAX) history_len++; } -static void cmd_print_prompt(void) { - // Clear the current line to prevent old output from corrupting the new command buffer - for (int i = 0; i < CMD_COLS; i++) { - screen_buffer[cursor_row][i].c = 0; - screen_buffer[cursor_row][i].color = current_color; +void cmd_print_prompt(void) { + if (cmd_state) { + current_prompt_len = 0; + cursor_col = 0; + + if (shell_config.show_drive) { + current_color = shell_config.prompt_drive_color; + cmd_putchar(cmd_state->current_drive); + current_color = shell_config.prompt_colon_color; + cmd_putchar(':'); + } + + if (shell_config.show_dir) { + current_color = shell_config.prompt_dir_color; + cmd_write(cmd_state->current_dir); + } + + current_color = shell_config.prompt_op_color; + cmd_putchar(shell_config.prompt_op_char); + + if (shell_config.prompt_suffix[0]) { + cmd_write(shell_config.prompt_suffix); + } + + current_prompt_len = cursor_col; + current_color = shell_config.command_color; } - cursor_col = 0; - - char buf[5]; - buf[0] = cmd_state ? cmd_state->current_drive : 'A'; - buf[1] = ':'; - buf[2] = '>'; - buf[3] = ' '; - buf[4] = 0; - cmd_write(buf); } -static void cmd_clear_line_content(void) { - int prompt_len = 4; // "A:> " +void cmd_clear_line_content(void) { + int prompt_len = current_prompt_len; for (int i = prompt_len; i < CMD_COLS; i++) { screen_buffer[cursor_row][i].c = ' '; screen_buffer[cursor_row][i].color = current_color; @@ -200,7 +526,7 @@ static void cmd_scroll_up() { // Clear bottom row for (int c = 0; c < CMD_COLS; c++) { screen_buffer[CMD_ROWS - 1][c].c = ' '; - screen_buffer[CMD_ROWS - 1][c].color = current_color; + screen_buffer[CMD_ROWS - 1][c].color = shell_config.default_text_color; } } @@ -224,10 +550,15 @@ void cmd_putchar(char c) { if (c == '\n') { cursor_col = 0; cursor_row++; + } else if (c == '\t') { + int spaces = 4 - (cursor_col % 4); + for (int i = 0; i < spaces; i++) cmd_putchar(' '); + return; } else if (c == '\b') { if (cursor_col > 0) { cursor_col--; screen_buffer[cursor_row][cursor_col].c = ' '; + screen_buffer[cursor_row][cursor_col].color = shell_config.default_text_color; } } else { if (cursor_col >= CMD_COLS) { @@ -252,7 +583,6 @@ void cmd_putchar(char c) { // Trigger repaint so output from syscalls is immediately visible wm_mark_dirty(win_cmd.x, win_cmd.y, win_cmd.w, win_cmd.h); - wm_refresh(); } // Public for CLI apps to use @@ -594,6 +924,22 @@ static void internal_cmd_exit(char *args) { cmd_window_exit(); } +static void internal_cmd_reload(char *args) { + (void)args; + cmd_load_config(); + win_cmd.title = shell_config.title_text; + cmd_write("Configuration reloaded.\n"); + cmd_print_prompt(); +} + +static void internal_cmd_cls(char *args) { + (void)args; + cmd_screen_clear(); + cursor_row = 0; + cursor_col = 0; + cmd_print_prompt(); +} + // Command dispatch table typedef struct { const char *name; @@ -609,6 +955,12 @@ static const CommandEntry commands[] = { {"exit", internal_cmd_exit}, {"CD", internal_cmd_cd}, {"cd", internal_cmd_cd}, + {"RELOAD", internal_cmd_reload}, + {"reload", internal_cmd_reload}, + {"CLS", internal_cmd_cls}, + {"cls", internal_cmd_cls}, + {"CLEAR", internal_cmd_cls}, + {"clear", internal_cmd_cls}, {NULL, NULL} }; @@ -793,10 +1145,15 @@ static void cmd_exec_single(char *cmd) { i += 2; while (args[i] == ' ') { temp_args[j++] = ' '; i++; } - // Prepend drive to filename + // Prepend drive and directory to filename if relative if (args[i] && args[i+1] != ':') { temp_args[j++] = cmd_state->current_drive; temp_args[j++] = ':'; + if (args[i] != '/') { + const char *d = cmd_state->current_dir; + while (*d && j < 509) temp_args[j++] = *d++; + if (j > 2 && temp_args[j-1] != '/') temp_args[j++] = '/'; + } } in_redirect = true; } else if (args[i] == '>' && args[i+1] != '>') { @@ -805,10 +1162,15 @@ static void cmd_exec_single(char *cmd) { i++; while (args[i] == ' ') { temp_args[j++] = ' '; i++; } - // Prepend drive to filename + // Prepend drive and directory to filename if relative if (args[i] && args[i+1] != ':') { temp_args[j++] = cmd_state->current_drive; temp_args[j++] = ':'; + if (args[i] != '/') { + const char *d = cmd_state->current_dir; + while (*d && j < 509) temp_args[j++] = *d++; + if (j > 2 && temp_args[j-1] != '/') temp_args[j++] = '/'; + } } in_redirect = true; } else { @@ -823,11 +1185,14 @@ static void cmd_exec_single(char *cmd) { cmd_strcmp(cmd, "cc") == 0 || cmd_strcmp(cmd, "CC") == 0 || cmd_strcmp(cmd, "compc") == 0 || cmd_strcmp(cmd, "COMPC") == 0 || cmd_strcmp(cmd, "touch") == 0 || cmd_strcmp(cmd, "TOUCH") == 0 || + cmd_strcmp(cmd, "mkdir") == 0 || cmd_strcmp(cmd, "MKDIR") == 0 || + cmd_strcmp(cmd, "rm") == 0 || cmd_strcmp(cmd, "RM") == 0 || + cmd_strcmp(cmd, "ls") == 0 || cmd_strcmp(cmd, "LS") == 0 || cmd_strcmp(cmd, "cp") == 0 || cmd_strcmp(cmd, "CP") == 0 || cmd_strcmp(cmd, "mv") == 0 || cmd_strcmp(cmd, "MV") == 0 || cmd_strcmp(cmd, "txtedit") == 0 || cmd_strcmp(cmd, "TXTEDIT") == 0 || cmd_strcmp(cmd, "tx") == 0 || cmd_strcmp(cmd, "TX") == 0) { - // For cat, cc, compc, touch, cp, mv, txtedit: prepend drive to file arguments if not already present + // For filesystem commands: prepend drive and current directory if relative if (args[1] == ':') { // Already has drive letter cmd_strcpy(full_path_arg, args); @@ -1247,40 +1612,43 @@ static void cmd_exec(char *cmd) { // --- Window Functions --- static void cmd_paint(Window *win) { - // Draw Window Content Background + // Fill background + draw_rect(win->x + 4, win->y + 30, win->w - 8, win->h - 34, shell_config.bg_color); + int offset_x = win->x + 4; int offset_y = win->y + 24; - - // Fill background - dark mode terminal - draw_rect(win->x + 4, win->y + 30, win->w - 8, win->h - 34, COLOR_DARK_BG); - int start_y = offset_y + 4; int start_x = offset_x + 4; if (current_mode == MODE_PAGER) { // Draw Pager Content (Wrapped) for (int i = 0; i < CMD_ROWS && (pager_top_line + i) < pager_total_lines; i++) { - draw_string(start_x, start_y + (i * LINE_HEIGHT), pager_wrapped_lines[pager_top_line + i], COLOR_DARK_TEXT); + draw_string(start_x, start_y + (i * LINE_HEIGHT), pager_wrapped_lines[pager_top_line + i], shell_config.default_text_color); } // Status Bar - draw_string(start_x, start_y + (CMD_ROWS * LINE_HEIGHT), "-- Press Q to quit --", COLOR_DARK_TEXT); - + draw_string(start_x, start_y + (CMD_ROWS * LINE_HEIGHT), "-- Press Q to quit --", shell_config.default_text_color); } else { + // Draw Cursor + if (win->focused) { + draw_rect(start_x + (cursor_col * CHAR_WIDTH), start_y + (cursor_row * LINE_HEIGHT), + CHAR_WIDTH, LINE_HEIGHT, shell_config.cursor_color); + } + // Draw Shell Buffer for (int r = 0; r < CMD_ROWS; r++) { for (int c = 0; c < CMD_COLS; c++) { char ch = screen_buffer[r][c].c; if (ch != 0 && ch != ' ') { - draw_char(start_x + (c * CHAR_WIDTH), start_y + (r * LINE_HEIGHT), ch, screen_buffer[r][c].color); + uint32_t color = screen_buffer[r][c].color; + // If cursor is on this character, and cursor color is bright, use background color for char + if (r == cursor_row && c == cursor_col && win->focused) { + color = shell_config.bg_color; + } + draw_char(start_x + (c * CHAR_WIDTH), start_y + (r * LINE_HEIGHT), ch, color); } } } - - // Draw Cursor - if (win->focused) { - draw_rect(start_x + (cursor_col * CHAR_WIDTH), start_y + (cursor_row * LINE_HEIGHT) + 8, CHAR_WIDTH, 2, COLOR_WHITE); - } } } @@ -1301,17 +1669,18 @@ static void cmd_key(Window *target, char c) { if (c == '\n') { // Enter char cmd_buf[CMD_COLS + 1]; int len = 0; - int prompt_len = 4; + int prompt_len = current_prompt_len; for (int i = prompt_len; i < CMD_COLS; i++) { char ch = screen_buffer[cursor_row][i].c; - if (ch == 0) break; + if (ch == 0 || (ch == ' ' && i > prompt_len && screen_buffer[cursor_row][i+1].c == 0)) break; cmd_buf[len++] = ch; } while (len > 0 && cmd_buf[len-1] == ' ') len--; cmd_buf[len] = 0; cmd_putchar('\n'); + current_color = shell_config.default_text_color; if (len > 0) cmd_history_add(cmd_buf); history_pos = -1; @@ -1326,10 +1695,10 @@ static void cmd_key(Window *target, char c) { if (history_pos == -1) { // Save current line int len = 0; - int prompt_len = 4; + int prompt_len = current_prompt_len; for (int i = prompt_len; i < CMD_COLS; i++) { char ch = screen_buffer[cursor_row][i].c; - if (ch == 0) break; + if (ch == 0 || (ch == ' ' && i > prompt_len && screen_buffer[cursor_row][i+1].c == 0)) break; history_save_buf[len++] = ch; } while (len > 0 && history_save_buf[len-1] == ' ') len--; @@ -1356,7 +1725,7 @@ static void cmd_key(Window *target, char c) { } } } else if (c == 19) { // LEFT - if (cursor_col > 4) { + if (cursor_col > current_prompt_len) { cursor_col--; } } else if (c == 20) { // RIGHT @@ -1364,37 +1733,100 @@ static void cmd_key(Window *target, char c) { cursor_col++; } } else if (c == '\b') { // Backspace - if (cursor_col > 4) { + if (cursor_col > current_prompt_len) { + // Shift characters to the left + for (int i = cursor_col; i < CMD_COLS; i++) { + screen_buffer[cursor_row][i - 1] = screen_buffer[cursor_row][i]; + } + screen_buffer[cursor_row][CMD_COLS - 1].c = ' '; cursor_col--; - screen_buffer[cursor_row][cursor_col].c = ' '; + wm_mark_dirty(win_cmd.x, win_cmd.y, win_cmd.w, win_cmd.h); } } else { if (c >= 32 && c <= 126) { - cmd_putchar(c); + // Shift characters to the right + for (int i = CMD_COLS - 1; i > cursor_col; i--) { + screen_buffer[cursor_row][i] = screen_buffer[cursor_row][i - 1]; + } + screen_buffer[cursor_row][cursor_col].c = c; + screen_buffer[cursor_row][cursor_col].color = current_color; + cursor_col++; + wm_mark_dirty(win_cmd.x, win_cmd.y, win_cmd.w, win_cmd.h); } } } void cmd_reset(void) { // Reset terminal to fresh state - cmd_screen_clear(); - cmd_write("BoredOS Command Prompt\n"); - if (msg_count > 0) { - cmd_write("You have "); - cmd_write_int(msg_count); - cmd_write(" new message(s) run \"msgrc\" to see your new message(s).\n"); + cmd_load_config(); + + cursor_row = 0; + cursor_col = 0; + current_color = shell_config.default_text_color; + win_cmd.title = shell_config.title_text; + + if (shell_config.welcome_msg) { + if (shell_config.custom_welcome_message[0]) { + cmd_write(shell_config.custom_welcome_message); + cmd_putchar('\n'); + } else { + cmd_write("BoredOS Command Prompt\n"); + } } + + if (shell_config.startup_cmd[0]) { + // Run startup command without prompt prefix + cmd_exec(shell_config.startup_cmd); + } + cmd_print_prompt(); } -static void create_test_files(void) { +static void create_ramfs_files(void) { if (!fat32_exists("Documents")) fat32_mkdir("Documents"); if (!fat32_exists("Projects")) fat32_mkdir("Projects"); if (!fat32_exists("Documents/Important")) fat32_mkdir("Documents/Important"); if (!fat32_exists("Apps")) fat32_mkdir("Apps"); if (!fat32_exists("Desktop")) fat32_mkdir("Desktop"); if (!fat32_exists("RecycleBin")) fat32_mkdir("RecycleBin"); - if (!fat32_exists("bin")) fat32_mkdir("bin"); + if (!fat32_exists("Library/conf")) fat32_mkdir("Library/conf"); + + // Create default shell configuration file (commented out) + if (!fat32_exists("Library/conf/shell.cfg")) { + FAT32_FileHandle *cfg = fat32_open("Library/conf/shell.cfg", "w"); + if (cfg) { + const char *config_content = + "// BoredOS Shell Configuration\n" + "// Colors: HEX (#RRGGBB), RGB (rgb(r,g,b)), or Names (red, blue, light blue, etc.)\n" + "// ---------------------------------------------------------------------------\n" + "// prompt_drive_color=white\n" + "// prompt_colon_color=gray\n" + "// prompt_dir_color=light blue\n" + "// prompt_op_color=white\n" + "// prompt_op_char=>\n" + "// prompt_suffix= \n" + "// default_text_color=light gray\n" + "// command_color=white\n" + "// bg_color=#1E1E1E\n" + "// cursor_color=white\n" + "// title_text=Command Prompt\n" + "// custom_welcome_message=\n" + "// startup_cmd=\n" + "// welcome_msg=true\n" + "// show_drive=true\n" + "// show_dir=true\n" + "// dir_color=light blue\n" + "// file_color=white\n" + "// size_color=light green\n" + "// error_color=light red\n" + "// success_color=light green\n" + "// help_color=light gray\n" + "// history_save_prompt=true\n"; + fat32_write(cfg, (void *)config_content, cmd_strlen(config_content)); + fat32_close(cfg); + } + } + @@ -1596,14 +2028,18 @@ static void create_test_files(void) { void cmd_init(void) { - create_test_files(); + cmd_init_config_defaults(); + create_ramfs_files(); create_man_entries(); + + // Load config after files are created + cmd_load_config(); - win_cmd.title = "Command Prompt"; + win_cmd.title = shell_config.title_text; win_cmd.x = 50; win_cmd.y = 50; win_cmd.w = (CMD_COLS * CHAR_WIDTH) + 20; - win_cmd.h = (CMD_ROWS * LINE_HEIGHT) + 40; + win_cmd.h = (CMD_ROWS * LINE_HEIGHT) + 50; win_cmd.visible = false; win_cmd.focused = false; diff --git a/src/kernel/cmd.h b/src/kernel/cmd.h index c43a97c..a2cd933 100644 --- a/src/kernel/cmd.h +++ b/src/kernel/cmd.h @@ -22,4 +22,7 @@ void cmd_screen_clear(void); void cmd_increment_msg_count(void); void cmd_reset_msg_count(void); +uint64_t cmd_get_config_value(const char *key); +void cmd_set_current_color(uint32_t color); + #endif \ No newline at end of file diff --git a/src/kernel/explorer.c b/src/kernel/explorer.c index ab57174..86bd1ab 100644 --- a/src/kernel/explorer.c +++ b/src/kernel/explorer.c @@ -9,7 +9,6 @@ #include "memory_manager.h" #include "cmd.h" #include "process.h" -#include "about.h" #define EXPLORER_ITEM_HEIGHT 80 #define EXPLORER_ITEM_WIDTH 120 #define EXPLORER_COLS 4 @@ -853,7 +852,7 @@ static void explorer_open_item(Window *win, int index) { } else if (explorer_strcmp(state->items[index].name, "Control Panel.shortcut") == 0 || explorer_strcmp(state->items[index].name, "Settings.shortcut") == 0) { process_create_elf("/bin/settings.elf", NULL); return; } else if (explorer_strcmp(state->items[index].name, "About.shortcut") == 0) { - target = &win_about; + process_create_elf("/bin/about.elf", NULL); return; } else if (explorer_strcmp(state->items[index].name, "Explorer.shortcut") == 0) { explorer_open_directory("/"); return; } else if (explorer_strcmp(state->items[index].name, "Recycle Bin.shortcut") == 0) { diff --git a/src/kernel/process.c b/src/kernel/process.c index 92214cb..fa5bbf6 100644 --- a/src/kernel/process.c +++ b/src/kernel/process.c @@ -294,7 +294,8 @@ uint64_t process_terminate_current(void) { if (!current_process) return 0; // 1. Cleanup side effects - if (current_process->ui_window && !current_process->is_terminal_proc) { + extern Window win_cmd; + if (current_process->ui_window && (current_process->ui_window != &win_cmd)) { extern void serial_write(const char *str); serial_write("PROC: Terminating proc with window\n"); wm_remove_window((Window *)current_process->ui_window); diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 801b2b8..d99f654 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -15,6 +15,7 @@ #include "kutils.h" #include "network.h" #include "icmp.h" +#include "cmd.h" // Read MSR static inline uint64_t rdmsr(uint32_t msr) { @@ -136,10 +137,8 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u extern void cmd_process_finished(void); if (syscall_num == 1) { // SYS_WRITE - // arg2 is the buffer based on our user_test logic cmd_write((const char*)arg2); } else if (syscall_num == 0 || syscall_num == 60) { // SYS_EXIT - serial_write("Kernel: SYS_EXIT called\n"); uint64_t next_rsp = process_terminate_current(); extern void context_switch_to(uint64_t rsp); context_switch_to(next_rsp); @@ -724,6 +723,14 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u return cli_cmd_ping_syscall(dest_ip); } else if (cmd == 27) { // SYSTEM_CMD_NETWORK_IS_INIT return network_is_initialized() ? 1 : 0; + } else if (cmd == 28) { // SYSTEM_CMD_GET_SHELL_CONFIG + const char *key = (const char *)arg2; + if (!key) return -1; + return cmd_get_config_value(key); + } else if (cmd == 29) { // SYSTEM_CMD_SET_TEXT_COLOR + uint32_t color = (uint32_t)arg2; + cmd_set_current_color(color); + return 0; } return -1; } diff --git a/src/kernel/userland/about.c b/src/kernel/userland/about.c new file mode 100644 index 0000000..4ea2b3a --- /dev/null +++ b/src/kernel/userland/about.c @@ -0,0 +1,83 @@ +// Copyright (c) 2023-2026 Chris (boreddevnl) +// This software is released under the GNU General Public License v3.0. See LICENSE file for details. +// This header needs to maintain in any file it is present in, as per the GPL license terms. +#include "syscall.h" +#include "libui.h" +#include + +static void draw_boredos_logo(ui_window_t win, int x, int y, int scale) { + static const uint8_t brewos_bmp[] = { + 0,0,1,1,1,0,0,0,0,0,0,1,1,1,0,0, + 0,1,1,1,1,0,0,0,0,0,0,1,1,1,1,0, + 1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1, + 1,1,1,1,2,2,2,2,2,2,2,2,1,1,1,1, + 1,1,1,2,2,2,2,2,2,2,2,2,2,1,1,1, + 1,1,2,2,2,1,1,2,2,1,1,2,2,2,1,1, + 1,1,2,2,1,1,1,1,1,1,1,1,2,2,1,1, + 1,1,2,2,1,1,1,1,1,1,1,1,2,2,1,1, + 1,1,2,2,1,1,1,1,1,1,1,1,2,2,1,1, + 1,1,2,2,2,1,1,2,2,1,1,2,2,2,1,1, + 1,1,2,2,2,2,2,1,1,2,2,2,2,2,1,1, + 1,1,2,2,2,2,2,2,2,2,2,2,2,2,1,1, + 1,1,1,2,2,2,2,2,2,2,2,2,2,1,1,1, + 0,1,1,1,2,2,2,2,2,2,2,2,1,1,1,0, + 0,0,1,1,1,2,2,2,2,2,2,1,1,1,0,0, + 0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0 + }; + + for (int r = 0; r < 16; r++) { + for (int c = 0; c < 16; c++) { + uint8_t p = brewos_bmp[r * 16 + c]; + if (p == 1) { + ui_draw_rect(win, x + c * scale, y + r * scale, scale, scale, 0xFF1A1A1A); + } else if (p == 2) { + ui_draw_rect(win, x + c * scale, y + r * scale, scale, scale, 0xFFFEFEFE); + } + } + } +} + +static void about_paint(ui_window_t win) { + int w = 185; + int h = 240; + + //ui_draw_rect(win, 0, 0, w, h, 0xFF1E1E1E); + + int offset_x = 15; + int offset_y = 35; + + draw_boredos_logo(win, 60, offset_y, 4); + + // Version info + ui_draw_string(win, offset_x, offset_y + 105, "BoredOS 'Panda'", 0xFFFFFFFF); + ui_draw_string(win, offset_x, offset_y + 120, "BoredOS Version 1.64", 0xFFFFFFFF); + ui_draw_string(win, offset_x, offset_y + 135, "Kernel Version 3.0.0", 0xFFFFFFFF); + + // Copyright + ui_draw_string(win, offset_x, offset_y + 150, "(C) 2026 boreddevnl.", 0xFFFFFFFF); + ui_draw_string(win, offset_x, offset_y + 165, "All rights reserved.", 0xFFFFFFFF); + + ui_mark_dirty(win, 0, 0, w, h); +} + +int main(void) { + ui_window_t win_about = ui_window_create("About BoredOS", 250, 180, 185, 240); + + about_paint(win_about); + + gui_event_t ev; + while (1) { + if (ui_get_event(win_about, &ev)) { + if (ev.type == GUI_EVENT_PAINT) { + about_paint(win_about); + } else if (ev.type == GUI_EVENT_CLOSE) { + sys_exit(0); + } + } else { + // Avoid high CPU usage + for(volatile int i=0; i<10000; i++); + } + } + + return 0; +} diff --git a/src/kernel/userland/cat.c b/src/kernel/userland/cat.c index 6e33bcc..f99098b 100644 --- a/src/kernel/userland/cat.c +++ b/src/kernel/userland/cat.c @@ -5,6 +5,9 @@ #include int main(int argc, char **argv) { + uint32_t error_color = (uint32_t)sys_get_shell_config("error_color"); + uint32_t default_color = (uint32_t)sys_get_shell_config("default_text_color"); + if (argc < 2) { printf("Usage: cat \n"); return 1; @@ -12,7 +15,9 @@ int main(int argc, char **argv) { int fd = sys_open(argv[1], "r"); if (fd < 0) { + sys_set_text_color(error_color); printf("Error: Cannot open %s\n", argv[1]); + sys_set_text_color(default_color); return 1; } diff --git a/src/kernel/userland/cc.c b/src/kernel/userland/cc.c index d6ea46f..7083d49 100644 --- a/src/kernel/userland/cc.c +++ b/src/kernel/userland/cc.c @@ -13,6 +13,9 @@ #define STR_POOL_SIZE 16384 static int compile_error = 0; +static uint32_t color_error = 0xFFFF4444; +static uint32_t color_success = 0xFF6A9955; +static uint32_t color_default = 0xFFCCCCCC; // --- Lexer --- typedef enum { @@ -59,7 +62,9 @@ static Token tokens[MAX_TOKENS]; static int token_count = 0; static void lex_error(const char *msg) { + sys_set_text_color(color_error); printf("Compiler Error: %s\n", msg); + sys_set_text_color(color_default); compile_error = 1; } @@ -304,7 +309,12 @@ static int add_symbol(const char *name) { static void emit(uint8_t b) { if (code_pos < CODE_SIZE) code[code_pos++] = b; - else { printf("Error: Code buffer overflow\n"); compile_error = 1; } + else { + sys_set_text_color(color_error); + printf("Error: Code buffer overflow\n"); + sys_set_text_color(color_default); + compile_error = 1; + } } static void emit32(int v) { @@ -323,7 +333,12 @@ static int add_string(const char *str) { static void match(TokenType t) { if (compile_error) return; if (tokens[cur_token].type == t) cur_token++; - else { printf("Syntax Error: Expected token %d got %d\n", t, tokens[cur_token].type); compile_error = 1; } + else { + sys_set_text_color(color_error); + printf("Syntax Error: Expected token %d got %d\n", t, tokens[cur_token].type); + sys_set_text_color(color_default); + compile_error = 1; + } } static void expression(); @@ -352,11 +367,21 @@ static void factor() { if (syscall != -1 && tokens[cur_token+1].type == TOK_LPAREN) function_call(syscall); else { int addr = find_symbol(tokens[cur_token].str_val); - if (addr == -1) { printf("Error: Undefined variable: %s\n", tokens[cur_token].str_val); compile_error = 1; } + if (addr == -1) { + sys_set_text_color(color_error); + printf("Error: Undefined variable: %s\n", tokens[cur_token].str_val); + sys_set_text_color(color_default); + compile_error = 1; + } emit(OP_LOAD); emit32(addr); cur_token++; } } else if (tokens[cur_token].type == TOK_LPAREN) { cur_token++; expression(); match(TOK_RPAREN); } - else { printf("Syntax Error: Unexpected token in factor\n"); compile_error = 1; } + else { + sys_set_text_color(color_error); + printf("Syntax Error: Unexpected token in factor\n"); + sys_set_text_color(color_default); + compile_error = 1; + } } static void term() { @@ -461,10 +486,19 @@ static void program() { } int main(int argc, char **argv) { + color_error = (uint32_t)sys_get_shell_config("error_color"); + color_success = (uint32_t)sys_get_shell_config("success_color"); + color_default = (uint32_t)sys_get_shell_config("default_text_color"); + if (argc < 2) { printf("Usage: cc \n"); return 1; } int fh = sys_open(argv[1], "r"); - if (fh < 0) { printf("Error: Cannot open source file.\n"); return 1; } + if (fh < 0) { + sys_set_text_color(color_error); + printf("Error: Cannot open source file.\n"); + sys_set_text_color(color_default); + return 1; + } char *source = (char*)malloc(MAX_SOURCE); if (!source) { printf("Error: Out of memory for source buffer.\n"); sys_close(fh); return 1; } @@ -515,8 +549,14 @@ int main(int argc, char **argv) { if (out_fh >= 0) { sys_write_fs(out_fh, code, code_pos); sys_close(out_fh); + sys_set_text_color(color_success); printf("Compilation successful. Output: %s\n", out_name); - } else { printf("Error: Cannot write output file.\n"); } + sys_set_text_color(color_default); + } else { + sys_set_text_color(color_error); + printf("Error: Cannot write output file.\n"); + sys_set_text_color(color_default); + } return 0; } diff --git a/src/kernel/userland/help.c b/src/kernel/userland/help.c index 96c0cf4..de6dfb0 100644 --- a/src/kernel/userland/help.c +++ b/src/kernel/userland/help.c @@ -6,6 +6,9 @@ int main(int argc, char **argv) { (void)argc; (void)argv; + uint32_t help_color = sys_get_shell_config("help_color"); + if (help_color != 0) sys_set_text_color(help_color); + printf("BoredOS CLI Help\n"); printf("---------------------------\n"); printf("ls [path] - List directory contents\n"); diff --git a/src/kernel/userland/libc/syscall.c b/src/kernel/userland/libc/syscall.c index bc3cc01..9210391 100644 --- a/src/kernel/userland/libc/syscall.c +++ b/src/kernel/userland/libc/syscall.c @@ -179,3 +179,11 @@ int sys_network_is_initialized(void) { return (int)syscall2(SYS_SYSTEM, SYSTEM_CMD_NETWORK_IS_INIT, 0); } +uint64_t sys_get_shell_config(const char *key) { + return (uint64_t)sys_system(SYSTEM_CMD_GET_SHELL_CONFIG, (uint64_t)key, 0, 0, 0); +} + +void sys_set_text_color(uint32_t color) { + sys_system(SYSTEM_CMD_SET_TEXT_COLOR, (uint64_t)color, 0, 0, 0); +} + diff --git a/src/kernel/userland/libc/syscall.h b/src/kernel/userland/libc/syscall.h index 94798cf..64325fb 100644 --- a/src/kernel/userland/libc/syscall.h +++ b/src/kernel/userland/libc/syscall.h @@ -56,6 +56,8 @@ #define SYSTEM_CMD_NETWORK_GET_DNS 25 #define SYSTEM_CMD_ICMP_PING 26 #define SYSTEM_CMD_NETWORK_IS_INIT 27 +#define SYSTEM_CMD_GET_SHELL_CONFIG 28 +#define SYSTEM_CMD_SET_TEXT_COLOR 29 // Internal assembly entry into Ring 0 extern uint64_t syscall0(uint64_t sys_num); @@ -113,4 +115,7 @@ int sys_udp_send(const net_ipv4_address_t *dest_ip, uint16_t dest_port, uint16_t int sys_icmp_ping(const net_ipv4_address_t *dest_ip); int sys_network_is_initialized(void); +uint64_t sys_get_shell_config(const char *key); +void sys_set_text_color(uint32_t color); + #endif diff --git a/src/kernel/userland/ls.c b/src/kernel/userland/ls.c index b39e0ec..fc0260f 100644 --- a/src/kernel/userland/ls.c +++ b/src/kernel/userland/ls.c @@ -5,12 +5,18 @@ #include int main(int argc, char **argv) { + uint32_t dir_color = (uint32_t)sys_get_shell_config("dir_color"); + uint32_t file_color = (uint32_t)sys_get_shell_config("file_color"); + uint32_t size_color = (uint32_t)sys_get_shell_config("size_color"); + uint32_t error_color = (uint32_t)sys_get_shell_config("error_color"); + uint32_t default_color = (uint32_t)sys_get_shell_config("default_text_color"); + char path[256]; if (argc > 1) { strcpy(path, argv[1]); } else { - if (!getcwd(path, sizeof(path))) { - strcpy(path, "."); + if (!sys_getcwd(path, sizeof(path))) { + strcpy(path, "/"); } } @@ -18,18 +24,25 @@ int main(int argc, char **argv) { int count = sys_list(path, entries, 128); if (count < 0) { + sys_set_text_color(error_color); printf("Error: Cannot list directory %s\n", path); + sys_set_text_color(default_color); return 1; } for (int i = 0; i < count; i++) { if (entries[i].is_directory) { + sys_set_text_color(dir_color); printf("[DIR] %s\n", entries[i].name); } else { - printf("[FILE] %s (%d bytes)\n", entries[i].name, entries[i].size); + sys_set_text_color(file_color); + printf("[FILE] %s", entries[i].name); + sys_set_text_color(size_color); + printf(" (%d bytes)\n", entries[i].size); } } + sys_set_text_color(default_color); printf("\nTotal: %d items\n", count); return 0; } diff --git a/src/kernel/userland/mkdir.c b/src/kernel/userland/mkdir.c index af758a3..592d7fb 100644 --- a/src/kernel/userland/mkdir.c +++ b/src/kernel/userland/mkdir.c @@ -5,16 +5,24 @@ #include int main(int argc, char **argv) { + uint32_t error_color = (uint32_t)sys_get_shell_config("error_color"); + uint32_t success_color = (uint32_t)sys_get_shell_config("success_color"); + uint32_t default_color = (uint32_t)sys_get_shell_config("default_text_color"); + if (argc < 2) { printf("Usage: mkdir \n"); return 1; } if (sys_mkdir(argv[1]) == 0) { + sys_set_text_color(success_color); printf("Created directory: %s\n", argv[1]); } else { + sys_set_text_color(error_color); printf("Error: Cannot create directory %s\n", argv[1]); + sys_set_text_color(default_color); return 1; } + sys_set_text_color(default_color); return 0; } diff --git a/src/kernel/userland/rm.c b/src/kernel/userland/rm.c index 312da41..a8fa250 100644 --- a/src/kernel/userland/rm.c +++ b/src/kernel/userland/rm.c @@ -5,6 +5,10 @@ #include int main(int argc, char **argv) { + uint32_t error_color = (uint32_t)sys_get_shell_config("error_color"); + uint32_t success_color = (uint32_t)sys_get_shell_config("success_color"); + uint32_t default_color = (uint32_t)sys_get_shell_config("default_text_color"); + if (argc < 2) { printf("Usage: rm \n"); return 1; @@ -12,10 +16,14 @@ int main(int argc, char **argv) { // Simple rm (no recursive support yet for simplicity, but can be added) if (sys_delete(argv[1]) == 0) { + sys_set_text_color(success_color); printf("Deleted: %s\n", argv[1]); } else { + sys_set_text_color(error_color); printf("Error: Cannot delete %s\n", argv[1]); + sys_set_text_color(default_color); return 1; } + sys_set_text_color(default_color); return 0; } diff --git a/src/kernel/wm.c b/src/kernel/wm.c index 0b18924..1d734ad 100644 --- a/src/kernel/wm.c +++ b/src/kernel/wm.c @@ -12,7 +12,6 @@ #include #include #include "wallpaper.h" -#include "about.h" #include "fat32.h" #include "nanojpeg.h" #include "memory_manager.h" @@ -1583,7 +1582,7 @@ void wm_handle_click(int x, int y) { int item = rel_y / 20; if (item == 0) { // About - wm_bring_to_front(&win_about); + process_create_elf("/bin/about.elf", NULL); } else if (item == 1) { // Settings Window *existing = wm_find_window_by_title("Settings"); if (existing) wm_bring_to_front(existing); @@ -1882,7 +1881,7 @@ void wm_handle_right_click(int x, int y) { if (existing) wm_bring_to_front(existing); else process_create_elf("/bin/paint.elf", NULL); } else if (str_starts_with(start_menu_pending_app, "About")) { - wm_bring_to_front(&win_about); + process_create_elf("/bin/about.elf", NULL); } else if (str_starts_with(start_menu_pending_app, "Shutdown")) { k_shutdown(); } else if (str_starts_with(start_menu_pending_app, "Restart")) { @@ -1912,7 +1911,7 @@ void wm_handle_right_click(int x, int y) { } else if (str_ends_with(icon->name, "Terminal.shortcut")) { wm_bring_to_front(&win_cmd); handled = true; } else if (str_ends_with(icon->name, "About.shortcut")) { - wm_bring_to_front(&win_about); handled = true; + process_create_elf("/bin/about.elf", NULL); handled = true; } else if (str_ends_with(icon->name, "Files.shortcut")) { explorer_open_directory("/"); handled = true; } else if (str_ends_with(icon->name, "Recycle Bin.shortcut")) { @@ -2379,7 +2378,6 @@ void wm_init(void) { cmd_init(); explorer_init(); - about_init(); wallpaper_init(); refresh_desktop_icons(); @@ -2387,19 +2385,16 @@ void wm_init(void) { // Initialize z-indices win_cmd.z_index = 0; win_explorer.z_index = 1; - win_about.z_index = 2; all_windows[0] = &win_cmd; all_windows[1] = &win_explorer; - all_windows[2] = &win_about; - window_count = 3; + window_count = 2; win_explorer.visible = false; win_explorer.focused = false; win_explorer.z_index = 10; win_cmd.visible = false; - win_about.visible = false; force_redraw = true; }