diff --git a/config/init.lisp b/config/init.lisp index b5cd3e7..63bf2b2 100644 --- a/config/init.lisp +++ b/config/init.lisp @@ -2,6 +2,7 @@ (define TAB-LENGTH 4) (define QUIT-TIMES 1) +(define BACKGROUND-COLOR "light yellow") ;; PACKAGES diff --git a/include/buffer.h b/include/buffer.h new file mode 100644 index 0000000..6951e13 --- /dev/null +++ b/include/buffer.h @@ -0,0 +1,8 @@ +#ifndef BUFFER_H_ +#define BUFFER_H_ + +#include "data.h" + +int new_buffer(enum buffer_type type, char * filename, int width, int height); + +#endif diff --git a/include/color.h b/include/color.h new file mode 100644 index 0000000..136a2e9 --- /dev/null +++ b/include/color.h @@ -0,0 +1,123 @@ +#ifndef COLOR_H_ +#define COLOR_H_ + + +// ============================================================================ +// TEXT STYLES / ATTRIBUTES +// ============================================================================ +#define ANSI_RESET "\x1b[0m" // Reset all attributes +#define ANSI_BOLD "\x1b[1m" // Bold text +#define ANSI_DIM "\x1b[2m" // Dim/faint text +#define ANSI_ITALIC "\x1b[3m" // Italic text +#define ANSI_UNDERLINE "\x1b[4m" // Underline text +#define ANSI_BLINK "\x1b[5m" // Blinking text +#define ANSI_REVERSE "\x1b[7m" // Reverse video (invert colors) +#define ANSI_HIDDEN "\x1b[8m" // Hidden/invisible text +#define ANSI_STRIKETHROUGH "\x1b[9m" // Strikethrough text + +// ============================================================================ +// FOREGROUND COLORS (30-37 standard, 90-97 bright) +// ============================================================================ +#define ANSI_BLACK "\x1b[30m" +#define ANSI_RED "\x1b[31m" +#define ANSI_GREEN "\x1b[32m" +#define ANSI_YELLOW "\x1b[33m" +#define ANSI_BLUE "\x1b[34m" +#define ANSI_MAGENTA "\x1b[35m" +#define ANSI_CYAN "\x1b[36m" +#define ANSI_WHITE "\x1b[37m" + +// Bright/Light foreground colors (90-97) +#define ANSI_BRIGHT_BLACK "\x1b[90m" +#define ANSI_BRIGHT_RED "\x1b[91m" +#define ANSI_BRIGHT_GREEN "\x1b[92m" +#define ANSI_BRIGHT_YELLOW "\x1b[93m" +#define ANSI_BRIGHT_BLUE "\x1b[94m" +#define ANSI_BRIGHT_MAGENTA "\x1b[95m" +#define ANSI_BRIGHT_CYAN "\x1b[96m" +#define ANSI_BRIGHT_WHITE "\x1b[97m" + +// ============================================================================ +// BACKGROUND COLORS (40-47 standard, 100-107 bright) +// ============================================================================ +#define ANSI_BG_BLACK "\x1b[40m" +#define ANSI_BG_RED "\x1b[41m" +#define ANSI_BG_GREEN "\x1b[42m" +#define ANSI_BG_YELLOW "\x1b[43m" +#define ANSI_BG_BLUE "\x1b[44m" +#define ANSI_BG_MAGENTA "\x1b[45m" +#define ANSI_BG_CYAN "\x1b[46m" +#define ANSI_BG_WHITE "\x1b[47m" + +// Bright/Light background colors (100-107) +#define ANSI_BG_BRIGHT_BLACK "\x1b[100m" +#define ANSI_BG_BRIGHT_RED "\x1b[101m" +#define ANSI_BG_BRIGHT_GREEN "\x1b[102m" +#define ANSI_BG_BRIGHT_YELLOW "\x1b[103m" +#define ANSI_BG_BRIGHT_BLUE "\x1b[104m" +#define ANSI_BG_BRIGHT_MAGENTA "\x1b[105m" +#define ANSI_BG_BRIGHT_CYAN "\x1b[106m" +#define ANSI_BG_BRIGHT_WHITE "\x1b[107m" + +// ============================================================================ +// 256-COLOR MODE (for more colors) +// ============================================================================ +// Foreground: \x1b[38;5;Nm where N is 0-255 +// Background: \x1b[48;5;Nm where N is 0-255 +// Example macros: +#define ANSI_FG_256(N) "\x1b[38;5;" #N "m" +#define ANSI_BG_256(N) "\x1b[48;5;" #N "m" + +// ============================================================================ +// TRUE COLOR / 24-BIT COLOR (RGB) +// ============================================================================ +// Foreground: \x1b[38;2;R;G;Bm +// Background: \x1b[48;2;R;G;Bm +// Example macros: +#define ANSI_FG_RGB(R,G,B) "\x1b[38;2;" #R ";" #G ";" #B "m" +#define ANSI_BG_RGB(R,G,B) "\x1b[48;2;" #R ";" #G ";" #B "m" + +// ============================================================================ +// CURSOR MOVEMENT +// ============================================================================ +#define ANSI_CURSOR_UP(N) "\x1b[" #N "A" // Move up N lines +#define ANSI_CURSOR_DOWN(N) "\x1b[" #N "B" // Move down N lines +#define ANSI_CURSOR_RIGHT(N) "\x1b[" #N "C" // Move right N columns +#define ANSI_CURSOR_LEFT(N) "\x1b[" #N "D" // Move left N columns +#define ANSI_CURSOR_HOME "\x1b[H" // Move to home (0,0) +#define ANSI_CURSOR_HIDE "\x1b[?25l" // Hide cursor +#define ANSI_CURSOR_SHOW "\x1b[?25h" // Show cursor + +// ============================================================================ +// SCREEN CONTROL +// ============================================================================ +#define ANSI_CLEAR_SCREEN "\x1b[2J" // Clear entire screen +#define ANSI_CLEAR_LINE "\x1b[K" // Clear from cursor to end of line +#define ANSI_CLEAR_UP "\x1b[1J" // Clear from cursor to start +#define ANSI_CLEAR_DOWN "\x1b[0J" // Clear from cursor to end + +// ============================================================================ +// EXAMPLE USAGE +// ============================================================================ +/* +#include + +int main(void) { + // Simple color example + printf("%sHello in Red%s\n", ANSI_RED, ANSI_RESET); + + // Bold and colored + printf("%s%sBold Green%s\n", ANSI_BOLD, ANSI_GREEN, ANSI_RESET); + + // Background color + printf("%s%sYellow on Blue%s\n", ANSI_YELLOW, ANSI_BG_BLUE, ANSI_RESET); + + // Combine multiple styles + printf("%s%s%sUnderlined Bold Cyan%s\n", + ANSI_UNDERLINE, ANSI_BOLD, ANSI_CYAN, ANSI_RESET); + + return 0; +} +*/ + +#endif diff --git a/include/data.h b/include/data.h index 4e6a4dd..0accf9d 100644 --- a/include/data.h +++ b/include/data.h @@ -20,15 +20,27 @@ typedef struct erow { char *render; /**< The actual line we will print */ } erow; +typedef struct theme { + char *BACKGROUND_COLOR; + char *COLOR_KEYWORD; + char *COLOR_TYPE; + char *COLOR_STRING; + char *COLOR_COMMENT; + char *COLOR_NUMBER; + char *COLOR_DEFAULT; + +} theme_t; + enum editorStatus_e { IDLE, READ_ONLY, - READ_AND_WRITE, + READ_AND_WRITE, }; struct const_t { int TAB_LENGTH; int QUIT_TIMES; + char *THEME; }; struct prefix_t { @@ -40,7 +52,16 @@ struct keyBind_t { char *key_sequence; int prefix_id; Lisp command; - +}; + +enum buffer_type { FILE_BUFF, TERMINAL_BUFF }; + +struct buffer_t { + enum buffer_type type; + int buffer_id; + int width, height; + int x, y; /**< Position of the buffer*/ + char *filename; }; /** @@ -74,12 +95,17 @@ struct editorConfig { Lisp ctx_data; /** Lisp data context */ LispError ctx_error; /** Lisp ctx error */ - struct keyBind_t* key_binds; + struct keyBind_t *key_binds; int number_of_keybinds; - - struct prefix_t* prefix; + + struct prefix_t *prefix; int number_of_prefix; + struct buffer_t buffers[64]; + struct buffer_t ***screen_layout; /**< Which buffer is the current cell*/ + int number_of_buffer; + + theme_t theme; }; /** @@ -94,5 +120,4 @@ struct abuf { extern struct editorConfig E; - #endif diff --git a/include/editor_op.h b/include/editor_op.h index 757b6c8..cfe88e0 100644 --- a/include/editor_op.h +++ b/include/editor_op.h @@ -8,4 +8,6 @@ void editorInsertNewLine(); void editorDelChar(); +void editorSetStatusMessage(const char *fmt, ...); + #endif // EDITOR_OP_H_ diff --git a/include/output.h b/include/output.h index 590f269..6085b84 100644 --- a/include/output.h +++ b/include/output.h @@ -23,6 +23,4 @@ void editorDrawStatusBar(struct abuf *ab); void editorDrawMessageBar(struct abuf *ab); -void editorSetStatusMessage(const char *fmt, ...); - #endif // OUTPUT_H_ diff --git a/include/syntax_highlighter.h b/include/syntax_highlighter.h index 47d3059..294f294 100644 --- a/include/syntax_highlighter.h +++ b/include/syntax_highlighter.h @@ -1,10 +1,10 @@ -#define COLOR_RESET "\033[0m" -#define COLOR_KEYWORD "\033[1;35m" // Bold magenta -#define COLOR_TYPE "\033[1;34m" // Bold blue -#define COLOR_STRING "\033[1;32m" // Bold green -#define COLOR_COMMENT "\033[0;36m" // Cyan -#define COLOR_NUMBER "\033[1;33m" // Bold yellow -#define COLOR_DEFAULT "\033[0;37m" // White +#ifndef SYNTAX_HIGHLIGHTER_H_ +#define SYNTAX_HIGHLIGHTER_H_ + +#include "color.h" + +// Color codes that only affect foreground, preserving your background color +#define COLOR_RESET "\x1b[39m" // Reset all (4 bytes) // Token types typedef enum { @@ -18,3 +18,6 @@ typedef enum { } TokenType; char *highlight_line(const char * line, int *length); + +#endif + diff --git a/main.c b/main.c index 13c10ff..997b076 100644 --- a/main.c +++ b/main.c @@ -18,7 +18,7 @@ #include "include/file_io.h" #include "include/init.h" #include "include/input.h" -#include "include/output.h" +#include "include/editor_op.h" #include "include/terminal.h" struct editorConfig E; diff --git a/src/buffer.c b/src/buffer.c new file mode 100644 index 0000000..573a9c9 --- /dev/null +++ b/src/buffer.c @@ -0,0 +1,20 @@ +#include "../include/data.h" +#include + +int new_buffer(enum buffer_type type, char *filename, int x, int y, int width, + int height) { + // Create a new buffer + + struct buffer_t *buffer = &E.buffers[E.number_of_buffer]; + buffer->type = type; + + if (type == FILE_BUFF) { + strcpy(buffer->filename, filename); + } + buffer->width = width, buffer->height = height; + buffer->x = x, buffer->y = y; + + + + return 1; +} diff --git a/src/builtins.c b/src/builtins.c index 5d53853..e4abc96 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -12,7 +12,6 @@ #include "../include/file_io.h" #include "../include/input.h" #include "../include/row_op.h" -#include "include/output.h" #include #include diff --git a/src/editor_op.c b/src/editor_op.c index 5c846af..2a35642 100644 --- a/src/editor_op.c +++ b/src/editor_op.c @@ -1,9 +1,30 @@ +#include + #include "../include/editor_op.h" #include "../include/row_op.h" extern struct editorConfig E; + +/** + * @brief Sets a temporary status message for display + * @details Formats and stores a message that will be displayed in the message + * bar for 5 seconds. Uses printf-style variable argument formatting. + * @param fmt Printf-style format string + * @param ... Variable arguments for format string + * @note Updates global editor state E (status_msg, status_msg_time) + * @see editorDrawMessageBar() + */ +void editorSetStatusMessage(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + vsnprintf(E.status_msg, sizeof(E.status_msg), fmt, ap); + va_end(ap); + E.status_msg_time = time(NULL); +} + + void editorInsertChar(int c) { if (E.cursor_y == E.numrows) { editorInsertRow(E.numrows, "", 0); diff --git a/src/file_io.c b/src/file_io.c index 4ae9b01..50de430 100644 --- a/src/file_io.c +++ b/src/file_io.c @@ -8,7 +8,7 @@ #include "../include/file_io.h" #include "../include/input.h" -#include "../include/output.h" +#include "../include/editor_op.h" #include #include #include diff --git a/src/init.c b/src/init.c index 6e95282..ac71e59 100644 --- a/src/init.c +++ b/src/init.c @@ -1,9 +1,11 @@ #include "../include/init.h" #include "../include/builtins.h" +#include "../include/color.h" #include "../include/data.h" #include "../include/terminal.h" #include #include +#include #define LISP_IMPLEMENTATION #include "../include/lisp.h" @@ -17,7 +19,7 @@ void registerBuiltin(char *key_sequence, LispCFunc f) { } void initBuiltins() { - // move cursor + // Registering C functions as lisp macro registerBuiltin("move-cursor", moveCursor); registerBuiltin("map-key", mapKey); registerBuiltin("editor-quit", editorQuit); @@ -39,38 +41,8 @@ void initBuiltins() { registerBuiltin("editor-insert-tab", l_editorInserTab); } -void initEditor() { - E.init_file_path = (char *)calloc(256, sizeof(char)); - E.cursor_x = 0; - E.cursor_y = 0; - E.rx = 0; - E.row_offset = 0; - E.col_offset = 0; - E.numrows = 0; - E.row = NULL; - E.dirty = 0; - E.filename = NULL; - E.state = READ_ONLY; - E.status_msg[0] = '\0'; - E.status_msg_time = 0; - if (getWindowSize(&E.screenrows, &E.screencols) == -1) { - die("getWindowSize"); - } - E.screenrows -= 2; +void initConfig() { - E.number_of_keybinds = 0; - E.number_of_prefix = 0; - // General prefix is 0 (no prefix) - E.prefix = (struct prefix_t *)malloc(sizeof(struct prefix_t)); - E.prefix[0].prefix_id = 0; - strncpy(E.prefix[0].prefix_name, "no-prefix", 64); - - E.prefix_state = 0; - - strcat(E.init_file_path, getenv("HOME")); - strcat(E.init_file_path, "/.beluga/config/init.lisp"); - // printf("%s\n", init_file_path); - E.fd_init_file = fopen(E.init_file_path, "r"); E.ctx = lisp_init(); E.env = lisp_env(E.ctx); lisp_lib_load(E.ctx); @@ -83,6 +55,75 @@ void initEditor() { die("init failed"); } lisp_eval(E.ctx_data, &E.ctx_error, E.ctx); +} + +void init_theme() { + E.constantes.THEME = (char *)lisp_string( + lisp_eval(lisp_read("THEME", &E.ctx_error, E.ctx), &E.ctx_error, E.ctx)); + if (strcmp(E.constantes.THEME, "dark") == 0) { + E.theme.BACKGROUND_COLOR = ANSI_BG_RGB(40, 44, 52); + E.theme.COLOR_KEYWORD = ANSI_FG_RGB(198, 120, 221); + E.theme.COLOR_TYPE = ANSI_FG_RGB(97, 175, 239); + E.theme.COLOR_STRING = ANSI_FG_RGB(152, 195, 121); + E.theme.COLOR_COMMENT = ANSI_FG_RGB(92, 99, 112); + E.theme.COLOR_NUMBER = ANSI_FG_RGB(209, 154, 102); + E.theme.COLOR_DEFAULT = ANSI_FG_RGB(171, 178, 191); + } else { + E.theme.BACKGROUND_COLOR = ANSI_BG_RGB(250, 251, 252); + E.theme.COLOR_KEYWORD = ANSI_FG_RGB(166, 38, 164); + E.theme.COLOR_TYPE = ANSI_FG_RGB(4, 90, 180); + E.theme.COLOR_STRING = ANSI_FG_RGB(80, 161, 79); + E.theme.COLOR_COMMENT = ANSI_FG_RGB(152, 152, 152); + E.theme.COLOR_NUMBER = ANSI_FG_RGB(206, 102, 54); + E.theme.COLOR_DEFAULT = ANSI_FG_RGB(86, 89, 90); + } +} + +void initEditor() { + // Init graphics variables + E.cursor_x = 0; + E.cursor_y = 0; + E.rx = 0; + E.row_offset = 0; + E.col_offset = 0; + E.numrows = 0; + E.row = NULL; + // File relative variables + E.dirty = 0; + E.filename = NULL; + E.init_file_path = (char *)calloc(256, sizeof(char)); + strcat(E.init_file_path, getenv("HOME")); + strcat(E.init_file_path, "/.beluga/config/init.lisp"); + E.fd_init_file = fopen(E.init_file_path, "r"); + E.state = READ_ONLY; + + // Status bar + E.status_msg[0] = '\0'; + E.status_msg_time = 0; + if (getWindowSize(&E.screenrows, &E.screencols) == -1) { + die("getWindowSize"); + } + E.screenrows -= 2; + + E.screen_layout = + (struct buffer_t ***)malloc(E.screenrows * sizeof(struct buffer_t **)); + for (int i = 0; i < E.screenrows; ++i) { + E.screen_layout[i] = + (struct buffer_t **)malloc(E.screencols * sizeof(struct buffer_t *)); + } + + // Key binds + E.number_of_keybinds = 0; + E.number_of_prefix = 0; + // General prefix is 0 (no prefix) + E.prefix = (struct prefix_t *)malloc(sizeof(struct prefix_t)); + E.prefix[0].prefix_id = 0; + strncpy(E.prefix[0].prefix_name, "no-prefix", 64); + E.prefix_state = 0; + + initConfig(); + + init_theme(); // To modify diff --git a/src/output.c b/src/output.c index cbb53a4..c7074b4 100644 --- a/src/output.c +++ b/src/output.c @@ -1,13 +1,13 @@ /** * @file output.c * @brief Screen rendering and output module for the Beluga text editor - * @details Handles all screen updates, cursor positioning, status bar rendering, - * and display synchronization using ANSI escape sequences + * @details Handles all screen updates, cursor positioning, status bar + * rendering, and display synchronization using ANSI escape sequences */ #include "../include/output.h" +#include "../include/append_buffer.h" #include "../include/syntax_highlighter.h" -#include #include #include #include @@ -34,6 +34,7 @@ void editorDrawRows(struct abuf *ab) { int file_row; for (y = 0; y < E.screenrows; ++y) { file_row = y + E.row_offset; + abAppend(ab, E.theme.BACKGROUND_COLOR, strlen(E.theme.BACKGROUND_COLOR)); if (file_row >= E.numrows) { if (E.numrows == 0 && y == E.screenrows / 3) { welcome_len = @@ -60,10 +61,13 @@ void editorDrawRows(struct abuf *ab) { len = 0; if (len > E.screencols) len = E.screencols; - char * highlighted = highlight_line(&E.row[file_row].render[E.col_offset], &E.row[file_row].rsize); + char *highlighted = highlight_line(&E.row[file_row].render[E.col_offset], + &E.row[file_row].rsize); abAppend(ab, highlighted, E.row[file_row].rsize); + free(highlighted); } + abAppend(ab, E.theme.BACKGROUND_COLOR, strlen(E.theme.BACKGROUND_COLOR)); abAppend(ab, ERASE_END_LINE, 3); abAppend(ab, "\r\n", 2); } @@ -98,8 +102,9 @@ void editorScroll() { /** * @brief Renders the status bar at the bottom of the screen - * @details Displays filename, line count, dirty flag, and current cursor position - * in an inverted color bar. Right-aligns the cursor position indicator. + * @details Displays filename, line count, dirty flag, and current cursor + * position in an inverted color bar. Right-aligns the cursor position + * indicator. * @param ab Pointer to append buffer structure for accumulating output * @note Uses ANSI escape codes for color inversion */ @@ -150,9 +155,9 @@ void editorDrawMessageBar(struct abuf *ab) { /** * @brief Performs complete screen refresh and buffer synchronization - * @details Clears screen, redraws all visible content (rows, status bar, message bar), - * positions cursor, and writes accumulated buffer to stdout. This is the main - * rendering function called each frame. + * @details Clears screen, redraws all visible content (rows, status bar, + * message bar), positions cursor, and writes accumulated buffer to stdout. This + * is the main rendering function called each frame. * @note Updates global editor state E (via editorScroll()) * @see editorDrawRows() * @see editorDrawStatusBar() @@ -163,9 +168,11 @@ void editorRefreshScreen() { struct abuf ab = ABUF_INIT; char buf[32]; + abAppend(&ab, HIDE_CURSOR, 6); abAppend(&ab, CURSOR_TOP_LEFT, 3); + editorDrawRows(&ab); editorDrawStatusBar(&ab); editorDrawMessageBar(&ab); @@ -178,21 +185,3 @@ void editorRefreshScreen() { write(STDOUT_FILENO, ab.b, ab.len); abFree(&ab); } - - -/** - * @brief Sets a temporary status message for display - * @details Formats and stores a message that will be displayed in the message bar - * for 5 seconds. Uses printf-style variable argument formatting. - * @param fmt Printf-style format string - * @param ... Variable arguments for format string - * @note Updates global editor state E (status_msg, status_msg_time) - * @see editorDrawMessageBar() - */ -void editorSetStatusMessage(const char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - vsnprintf(E.status_msg, sizeof(E.status_msg), fmt, ap); - va_end(ap); - E.status_msg_time = time(NULL); -} diff --git a/src/syntax_highlighter.c b/src/syntax_highlighter.c index 7efdb0a..9194e0d 100644 --- a/src/syntax_highlighter.c +++ b/src/syntax_highlighter.c @@ -1,163 +1,198 @@ #include "../include/syntax_highlighter.h" +#include "../include/data.h" +#include "../include/theme.h" #include #include #include +extern struct editorConfig E; + const char *c_keywords[] = { - "if", "else", "while", "for", "do", "switch", "case", "break", - "continue", "return", "goto", "struct", "union", "enum", - "typedef", "static", "extern", "const", "volatile", "sizeof", - "auto", "register", "inline", "restrict", NULL -}; + "if", "else", "while", "for", "do", "switch", + "case", "break", "#include", "#define", "continue", "return", + "goto", "struct", "union", "enum", "typedef", "static", + "extern", "const", "volatile", "sizeof", "auto", "register", + "inline", "restrict", NULL}; // C types -const char *c_types[] = { - "int", "char", "float", "double", "void", "long", "short", - "unsigned", "signed", "bool", NULL -}; +const char *c_types[] = {"int", "char", "float", "double", + "void", "long", "short", "unsigned", + "signed", "bool", NULL}; // Check if character is alphanumeric or underscore int is_word_char(char c) { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || - (c >= '0' && c <= '9') || c == '_'; + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || c == '_' || c == '#'; } // Check if string is a keyword int is_keyword(const char *word) { - for (int i = 0; c_keywords[i] != NULL; i++) { - if (strcmp(word, c_keywords[i]) == 0) return 1; - } - return 0; + for (int i = 0; c_keywords[i] != NULL; i++) { + if (strcmp(word, c_keywords[i]) == 0) + return 1; + } + return 0; } // Check if string is a type int is_type(const char *word) { - for (int i = 0; c_types[i] != NULL; i++) { - if (strcmp(word, c_types[i]) == 0) return 1; - } - return 0; + for (int i = 0; c_types[i] != NULL; i++) { + if (strcmp(word, c_types[i]) == 0) + return 1; + } + return 0; } // Get color code for token type const char *get_color(TokenType type) { - switch (type) { - case TOKEN_KEYWORD: return COLOR_KEYWORD; - case TOKEN_TYPE: return COLOR_TYPE; - case TOKEN_STRING: return COLOR_STRING; - case TOKEN_COMMENT: return COLOR_COMMENT; - case TOKEN_NUMBER: return COLOR_NUMBER; - default: return COLOR_DEFAULT; - } + switch (type) { + case TOKEN_KEYWORD: + return E.theme.COLOR_KEYWORD; + case TOKEN_TYPE: + return E.theme.COLOR_TYPE; + case TOKEN_STRING: + return E.theme.COLOR_STRING; + case TOKEN_COMMENT: + return E.theme.COLOR_COMMENT; + case TOKEN_NUMBER: + return E.theme.COLOR_NUMBER; + default: + return E.theme.COLOR_DEFAULT; + } } +int comment_section = 0; + // Highlight a line of C code and return the highlighted string // Returns a newly allocated string that must be freed by the caller char *highlight_line(const char *line, int *length) { - char *result = malloc(1024); // Allocate space for result - int result_pos = 0; - int i = 0; + char *result = malloc(1024); // Allocate space for result + int result_pos = 0; + int i = 0; + + while (line[i] != '\0' && line[i] != '\n') { + // Skip whitespace + if (line[i] == ' ' || line[i] == '\t') { + result[result_pos++] = line[i++]; + continue; + } - while (line[i] != '\0' && line[i] != '\n') { - // Skip whitespace - if (line[i] == ' ' || line[i] == '\t') { - result[result_pos++] = line[i++]; - continue; - } + if (comment_section) { + result_pos += sprintf(&result[result_pos], "%s", E.theme.COLOR_COMMENT); + while (line[i] != '\0' && line[i] != '\n') { - // Handle line comments - if (line[i] == '/' && line[i + 1] == '/') { - result_pos += sprintf(&result[result_pos], "%s", COLOR_COMMENT); - while (line[i] != '\0' && line[i] != '\n') { - result[result_pos++] = line[i++]; - } - result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET); - continue; - } - - // Handle block comments - if (line[i] == '/' && line[i + 1] == '*') { - result_pos += sprintf(&result[result_pos], "%s", COLOR_COMMENT); - result[result_pos++] = line[i++]; - result[result_pos++] = line[i++]; - while (line[i] != '\0') { - if (line[i] == '*' && line[i + 1] == '/') { - result[result_pos++] = line[i++]; - result[result_pos++] = line[i++]; - break; - } - result[result_pos++] = line[i++]; - } - result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET); - continue; - } - - // Handle strings - if (line[i] == '"') { - result_pos += sprintf(&result[result_pos], "%s\"", COLOR_STRING); - i++; - while (line[i] != '\0' && line[i] != '"') { - if (line[i] == '\\') { - result[result_pos++] = line[i++]; - result[result_pos++] = line[i++]; - } else { - result[result_pos++] = line[i++]; - } - } - if (line[i] == '"') result[result_pos++] = line[i++]; - result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET); - continue; - } - - // Handle character literals - if (line[i] == '\'') { - result_pos += sprintf(&result[result_pos], "%s'", COLOR_STRING); - i++; - while (line[i] != '\0' && line[i] != '\'') { - if (line[i] == '\\') { - result[result_pos++] = line[i++]; - result[result_pos++] = line[i++]; - } else { - result[result_pos++] = line[i++]; - } - } - if (line[i] == '\'') result[result_pos++] = line[i++]; - result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET); - continue; - } - - // Handle numbers - if (line[i] >= '0' && line[i] <= '9') { - result_pos += sprintf(&result[result_pos], "%s", COLOR_NUMBER); - while (is_word_char(line[i]) || line[i] == '.') { - result[result_pos++] = line[i++]; - } - result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET); - continue; - } - - // Handle identifiers and keywords - if (is_word_char(line[i])) { - int start = i; - while (is_word_char(line[i])) i++; - - char word[256]; - strncpy(word, &line[start], i - start); - word[i - start] = '\0'; - - TokenType type = TOKEN_DEFAULT; - if (is_keyword(word)) type = TOKEN_KEYWORD; - else if (is_type(word)) type = TOKEN_TYPE; - - result_pos += sprintf(&result[result_pos], "%s%s%s", - get_color(type), word, COLOR_RESET); - continue; - } - - // Handle operators and other characters - result[result_pos++] = line[i++]; + if (line[i] == '*' && line[i + 1] == '/') { + comment_section = 0; } - result[result_pos] = '\0'; - *length = result_pos + 1; - return result; + result[result_pos++] = line[i++]; + } + result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET); + continue; + } + + // Handle line comments + if (line[i] == '/' && line[i + 1] == '/') { + result_pos += sprintf(&result[result_pos], "%s", E.theme.COLOR_COMMENT); + while (line[i] != '\0' && line[i] != '\n') { + result[result_pos++] = line[i++]; + } + result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET); + continue; + } + + // Handle block comments + if ((line[i] == '/' && line[i + 1] == '*')) { + comment_section = 1; + result_pos += sprintf(&result[result_pos], "%s", E.theme.COLOR_COMMENT); + result[result_pos++] = line[i++]; + result[result_pos++] = line[i++]; + while (line[i] != '\0') { + if (line[i] == '*' && line[i + 1] == '/') { + result[result_pos++] = line[i++]; + result[result_pos++] = line[i++]; + break; + } + result[result_pos++] = line[i++]; + } + result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET); + continue; + } + + // Handle strings + if (line[i] == '"') { + result_pos += sprintf(&result[result_pos], "%s\"", E.theme.COLOR_STRING); + i++; + while (line[i] != '\0' && line[i] != '"') { + if (line[i] == '\\') { + result[result_pos++] = line[i++]; + result[result_pos++] = line[i++]; + } else { + result[result_pos++] = line[i++]; + } + } + if (line[i] == '"') + result[result_pos++] = line[i++]; + result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET); + continue; + } + + // Handle character literals + if (line[i] == '\'') { + result_pos += sprintf(&result[result_pos], "%s'", E.theme.COLOR_STRING); + i++; + while (line[i] != '\0' && line[i] != '\'') { + if (line[i] == '\\') { + result[result_pos++] = line[i++]; + result[result_pos++] = line[i++]; + } else { + result[result_pos++] = line[i++]; + } + } + if (line[i] == '\'') + result[result_pos++] = line[i++]; + result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET); + continue; + } + + // Handle numbers + if (line[i] >= '0' && line[i] <= '9') { + result_pos += sprintf(&result[result_pos], "%s", E.theme.COLOR_NUMBER); + while (is_word_char(line[i]) || line[i] == '.') { + result[result_pos++] = line[i++]; + } + result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET); + continue; + } + + // Handle identifiers and keywords + if (is_word_char(line[i])) { + int start = i; + while (is_word_char(line[i])) + i++; + + char word[256]; + strncpy(word, &line[start], i - start); + word[i - start] = '\0'; + + TokenType type = TOKEN_DEFAULT; + if (is_keyword(word)) + type = TOKEN_KEYWORD; + else if (is_type(word)) + type = TOKEN_TYPE; + + result_pos += sprintf(&result[result_pos], "%s%s%s", get_color(type), + word, COLOR_RESET); + continue; + } + + // Handle operators and other characters + result_pos += sprintf(&result[result_pos], "%s", E.theme.COLOR_DEFAULT); + result[result_pos++] = line[i++]; + result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET); + } + + result[result_pos] = '\0'; + *length = result_pos + 1; + return result; }