Color theming

This commit is contained in:
Arthur Barraux
2026-01-22 14:00:47 +01:00
parent fa7f8d39d8
commit f3bd5dd1c9
15 changed files with 472 additions and 207 deletions
+1
View File
@@ -2,6 +2,7 @@
(define TAB-LENGTH 4) (define TAB-LENGTH 4)
(define QUIT-TIMES 1) (define QUIT-TIMES 1)
(define BACKGROUND-COLOR "light yellow")
;; PACKAGES ;; PACKAGES
+8
View File
@@ -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
+123
View File
@@ -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 <stdio.h>
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
+26 -1
View File
@@ -20,6 +20,17 @@ typedef struct erow {
char *render; /**< The actual line we will print */ char *render; /**< The actual line we will print */
} erow; } 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 { enum editorStatus_e {
IDLE, IDLE,
READ_ONLY, READ_ONLY,
@@ -29,6 +40,7 @@ enum editorStatus_e {
struct const_t { struct const_t {
int TAB_LENGTH; int TAB_LENGTH;
int QUIT_TIMES; int QUIT_TIMES;
char *THEME;
}; };
struct prefix_t { struct prefix_t {
@@ -40,7 +52,16 @@ struct keyBind_t {
char *key_sequence; char *key_sequence;
int prefix_id; int prefix_id;
Lisp command; 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;
}; };
/** /**
@@ -80,6 +101,11 @@ struct editorConfig {
struct prefix_t *prefix; struct prefix_t *prefix;
int number_of_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; extern struct editorConfig E;
#endif #endif
+2
View File
@@ -8,4 +8,6 @@ void editorInsertNewLine();
void editorDelChar(); void editorDelChar();
void editorSetStatusMessage(const char *fmt, ...);
#endif // EDITOR_OP_H_ #endif // EDITOR_OP_H_
-2
View File
@@ -23,6 +23,4 @@ void editorDrawStatusBar(struct abuf *ab);
void editorDrawMessageBar(struct abuf *ab); void editorDrawMessageBar(struct abuf *ab);
void editorSetStatusMessage(const char *fmt, ...);
#endif // OUTPUT_H_ #endif // OUTPUT_H_
+10 -7
View File
@@ -1,10 +1,10 @@
#define COLOR_RESET "\033[0m" #ifndef SYNTAX_HIGHLIGHTER_H_
#define COLOR_KEYWORD "\033[1;35m" // Bold magenta #define SYNTAX_HIGHLIGHTER_H_
#define COLOR_TYPE "\033[1;34m" // Bold blue
#define COLOR_STRING "\033[1;32m" // Bold green #include "color.h"
#define COLOR_COMMENT "\033[0;36m" // Cyan
#define COLOR_NUMBER "\033[1;33m" // Bold yellow // Color codes that only affect foreground, preserving your background color
#define COLOR_DEFAULT "\033[0;37m" // White #define COLOR_RESET "\x1b[39m" // Reset all (4 bytes)
// Token types // Token types
typedef enum { typedef enum {
@@ -18,3 +18,6 @@ typedef enum {
} TokenType; } TokenType;
char *highlight_line(const char * line, int *length); char *highlight_line(const char * line, int *length);
#endif
+1 -1
View File
@@ -18,7 +18,7 @@
#include "include/file_io.h" #include "include/file_io.h"
#include "include/init.h" #include "include/init.h"
#include "include/input.h" #include "include/input.h"
#include "include/output.h" #include "include/editor_op.h"
#include "include/terminal.h" #include "include/terminal.h"
struct editorConfig E; struct editorConfig E;
+20
View File
@@ -0,0 +1,20 @@
#include "../include/data.h"
#include <string.h>
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;
}
-1
View File
@@ -12,7 +12,6 @@
#include "../include/file_io.h" #include "../include/file_io.h"
#include "../include/input.h" #include "../include/input.h"
#include "../include/row_op.h" #include "../include/row_op.h"
#include "include/output.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
+21
View File
@@ -1,9 +1,30 @@
#include <stdarg.h>
#include "../include/editor_op.h" #include "../include/editor_op.h"
#include "../include/row_op.h" #include "../include/row_op.h"
extern struct editorConfig E; 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) { void editorInsertChar(int c) {
if (E.cursor_y == E.numrows) { if (E.cursor_y == E.numrows) {
editorInsertRow(E.numrows, "", 0); editorInsertRow(E.numrows, "", 0);
+1 -1
View File
@@ -8,7 +8,7 @@
#include "../include/file_io.h" #include "../include/file_io.h"
#include "../include/input.h" #include "../include/input.h"
#include "../include/output.h" #include "../include/editor_op.h"
#include <fcntl.h> #include <fcntl.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
+73 -32
View File
@@ -1,9 +1,11 @@
#include "../include/init.h" #include "../include/init.h"
#include "../include/builtins.h" #include "../include/builtins.h"
#include "../include/color.h"
#include "../include/data.h" #include "../include/data.h"
#include "../include/terminal.h" #include "../include/terminal.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#define LISP_IMPLEMENTATION #define LISP_IMPLEMENTATION
#include "../include/lisp.h" #include "../include/lisp.h"
@@ -17,7 +19,7 @@ void registerBuiltin(char *key_sequence, LispCFunc f) {
} }
void initBuiltins() { void initBuiltins() {
// move cursor // Registering C functions as lisp macro
registerBuiltin("move-cursor", moveCursor); registerBuiltin("move-cursor", moveCursor);
registerBuiltin("map-key", mapKey); registerBuiltin("map-key", mapKey);
registerBuiltin("editor-quit", editorQuit); registerBuiltin("editor-quit", editorQuit);
@@ -39,38 +41,8 @@ void initBuiltins() {
registerBuiltin("editor-insert-tab", l_editorInserTab); registerBuiltin("editor-insert-tab", l_editorInserTab);
} }
void initEditor() { void initConfig() {
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;
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.ctx = lisp_init();
E.env = lisp_env(E.ctx); E.env = lisp_env(E.ctx);
lisp_lib_load(E.ctx); lisp_lib_load(E.ctx);
@@ -83,6 +55,75 @@ void initEditor() {
die("init failed"); die("init failed");
} }
lisp_eval(E.ctx_data, &E.ctx_error, E.ctx); 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 // To modify
+16 -27
View File
@@ -1,13 +1,13 @@
/** /**
* @file output.c * @file output.c
* @brief Screen rendering and output module for the Beluga text editor * @brief Screen rendering and output module for the Beluga text editor
* @details Handles all screen updates, cursor positioning, status bar rendering, * @details Handles all screen updates, cursor positioning, status bar
* and display synchronization using ANSI escape sequences * rendering, and display synchronization using ANSI escape sequences
*/ */
#include "../include/output.h" #include "../include/output.h"
#include "../include/append_buffer.h"
#include "../include/syntax_highlighter.h" #include "../include/syntax_highlighter.h"
#include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -34,6 +34,7 @@ void editorDrawRows(struct abuf *ab) {
int file_row; int file_row;
for (y = 0; y < E.screenrows; ++y) { for (y = 0; y < E.screenrows; ++y) {
file_row = y + E.row_offset; file_row = y + E.row_offset;
abAppend(ab, E.theme.BACKGROUND_COLOR, strlen(E.theme.BACKGROUND_COLOR));
if (file_row >= E.numrows) { if (file_row >= E.numrows) {
if (E.numrows == 0 && y == E.screenrows / 3) { if (E.numrows == 0 && y == E.screenrows / 3) {
welcome_len = welcome_len =
@@ -60,10 +61,13 @@ void editorDrawRows(struct abuf *ab) {
len = 0; len = 0;
if (len > E.screencols) if (len > E.screencols)
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); abAppend(ab, highlighted, E.row[file_row].rsize);
free(highlighted); free(highlighted);
} }
abAppend(ab, E.theme.BACKGROUND_COLOR, strlen(E.theme.BACKGROUND_COLOR));
abAppend(ab, ERASE_END_LINE, 3); abAppend(ab, ERASE_END_LINE, 3);
abAppend(ab, "\r\n", 2); abAppend(ab, "\r\n", 2);
} }
@@ -98,8 +102,9 @@ void editorScroll() {
/** /**
* @brief Renders the status bar at the bottom of the screen * @brief Renders the status bar at the bottom of the screen
* @details Displays filename, line count, dirty flag, and current cursor position * @details Displays filename, line count, dirty flag, and current cursor
* in an inverted color bar. Right-aligns the cursor position indicator. * position in an inverted color bar. Right-aligns the cursor position
* indicator.
* @param ab Pointer to append buffer structure for accumulating output * @param ab Pointer to append buffer structure for accumulating output
* @note Uses ANSI escape codes for color inversion * @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 * @brief Performs complete screen refresh and buffer synchronization
* @details Clears screen, redraws all visible content (rows, status bar, message bar), * @details Clears screen, redraws all visible content (rows, status bar,
* positions cursor, and writes accumulated buffer to stdout. This is the main * message bar), positions cursor, and writes accumulated buffer to stdout. This
* rendering function called each frame. * is the main rendering function called each frame.
* @note Updates global editor state E (via editorScroll()) * @note Updates global editor state E (via editorScroll())
* @see editorDrawRows() * @see editorDrawRows()
* @see editorDrawStatusBar() * @see editorDrawStatusBar()
@@ -163,9 +168,11 @@ void editorRefreshScreen() {
struct abuf ab = ABUF_INIT; struct abuf ab = ABUF_INIT;
char buf[32]; char buf[32];
abAppend(&ab, HIDE_CURSOR, 6); abAppend(&ab, HIDE_CURSOR, 6);
abAppend(&ab, CURSOR_TOP_LEFT, 3); abAppend(&ab, CURSOR_TOP_LEFT, 3);
editorDrawRows(&ab); editorDrawRows(&ab);
editorDrawStatusBar(&ab); editorDrawStatusBar(&ab);
editorDrawMessageBar(&ab); editorDrawMessageBar(&ab);
@@ -178,21 +185,3 @@ void editorRefreshScreen() {
write(STDOUT_FILENO, ab.b, ab.len); write(STDOUT_FILENO, ab.b, ab.len);
abFree(&ab); 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);
}
+66 -31
View File
@@ -1,31 +1,35 @@
#include "../include/syntax_highlighter.h" #include "../include/syntax_highlighter.h"
#include "../include/data.h"
#include "../include/theme.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
extern struct editorConfig E;
const char *c_keywords[] = { const char *c_keywords[] = {
"if", "else", "while", "for", "do", "switch", "case", "break", "if", "else", "while", "for", "do", "switch",
"continue", "return", "goto", "struct", "union", "enum", "case", "break", "#include", "#define", "continue", "return",
"typedef", "static", "extern", "const", "volatile", "sizeof", "goto", "struct", "union", "enum", "typedef", "static",
"auto", "register", "inline", "restrict", NULL "extern", "const", "volatile", "sizeof", "auto", "register",
}; "inline", "restrict", NULL};
// C types // C types
const char *c_types[] = { const char *c_types[] = {"int", "char", "float", "double",
"int", "char", "float", "double", "void", "long", "short", "void", "long", "short", "unsigned",
"unsigned", "signed", "bool", NULL "signed", "bool", NULL};
};
// Check if character is alphanumeric or underscore // Check if character is alphanumeric or underscore
int is_word_char(char c) { int is_word_char(char c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9') || c == '_'; (c >= '0' && c <= '9') || c == '_' || c == '#';
} }
// Check if string is a keyword // Check if string is a keyword
int is_keyword(const char *word) { int is_keyword(const char *word) {
for (int i = 0; c_keywords[i] != NULL; i++) { for (int i = 0; c_keywords[i] != NULL; i++) {
if (strcmp(word, c_keywords[i]) == 0) return 1; if (strcmp(word, c_keywords[i]) == 0)
return 1;
} }
return 0; return 0;
} }
@@ -33,7 +37,8 @@ int is_keyword(const char *word) {
// Check if string is a type // Check if string is a type
int is_type(const char *word) { int is_type(const char *word) {
for (int i = 0; c_types[i] != NULL; i++) { for (int i = 0; c_types[i] != NULL; i++) {
if (strcmp(word, c_types[i]) == 0) return 1; if (strcmp(word, c_types[i]) == 0)
return 1;
} }
return 0; return 0;
} }
@@ -41,15 +46,23 @@ int is_type(const char *word) {
// Get color code for token type // Get color code for token type
const char *get_color(TokenType type) { const char *get_color(TokenType type) {
switch (type) { switch (type) {
case TOKEN_KEYWORD: return COLOR_KEYWORD; case TOKEN_KEYWORD:
case TOKEN_TYPE: return COLOR_TYPE; return E.theme.COLOR_KEYWORD;
case TOKEN_STRING: return COLOR_STRING; case TOKEN_TYPE:
case TOKEN_COMMENT: return COLOR_COMMENT; return E.theme.COLOR_TYPE;
case TOKEN_NUMBER: return COLOR_NUMBER; case TOKEN_STRING:
default: return COLOR_DEFAULT; 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 // Highlight a line of C code and return the highlighted string
// Returns a newly allocated string that must be freed by the caller // Returns a newly allocated string that must be freed by the caller
char *highlight_line(const char *line, int *length) { char *highlight_line(const char *line, int *length) {
@@ -64,9 +77,23 @@ char *highlight_line(const char *line, int *length) {
continue; continue;
} }
if (comment_section) {
result_pos += sprintf(&result[result_pos], "%s", E.theme.COLOR_COMMENT);
while (line[i] != '\0' && line[i] != '\n') {
if (line[i] == '*' && line[i + 1] == '/') {
comment_section = 0;
}
result[result_pos++] = line[i++];
}
result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET);
continue;
}
// Handle line comments // Handle line comments
if (line[i] == '/' && line[i + 1] == '/') { if (line[i] == '/' && line[i + 1] == '/') {
result_pos += sprintf(&result[result_pos], "%s", COLOR_COMMENT); result_pos += sprintf(&result[result_pos], "%s", E.theme.COLOR_COMMENT);
while (line[i] != '\0' && line[i] != '\n') { while (line[i] != '\0' && line[i] != '\n') {
result[result_pos++] = line[i++]; result[result_pos++] = line[i++];
} }
@@ -75,8 +102,9 @@ char *highlight_line(const char *line, int *length) {
} }
// Handle block comments // Handle block comments
if (line[i] == '/' && line[i + 1] == '*') { if ((line[i] == '/' && line[i + 1] == '*')) {
result_pos += sprintf(&result[result_pos], "%s", COLOR_COMMENT); comment_section = 1;
result_pos += sprintf(&result[result_pos], "%s", E.theme.COLOR_COMMENT);
result[result_pos++] = line[i++]; result[result_pos++] = line[i++];
result[result_pos++] = line[i++]; result[result_pos++] = line[i++];
while (line[i] != '\0') { while (line[i] != '\0') {
@@ -93,7 +121,7 @@ char *highlight_line(const char *line, int *length) {
// Handle strings // Handle strings
if (line[i] == '"') { if (line[i] == '"') {
result_pos += sprintf(&result[result_pos], "%s\"", COLOR_STRING); result_pos += sprintf(&result[result_pos], "%s\"", E.theme.COLOR_STRING);
i++; i++;
while (line[i] != '\0' && line[i] != '"') { while (line[i] != '\0' && line[i] != '"') {
if (line[i] == '\\') { if (line[i] == '\\') {
@@ -103,14 +131,15 @@ char *highlight_line(const char *line, int *length) {
result[result_pos++] = line[i++]; result[result_pos++] = line[i++];
} }
} }
if (line[i] == '"') result[result_pos++] = line[i++]; if (line[i] == '"')
result[result_pos++] = line[i++];
result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET); result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET);
continue; continue;
} }
// Handle character literals // Handle character literals
if (line[i] == '\'') { if (line[i] == '\'') {
result_pos += sprintf(&result[result_pos], "%s'", COLOR_STRING); result_pos += sprintf(&result[result_pos], "%s'", E.theme.COLOR_STRING);
i++; i++;
while (line[i] != '\0' && line[i] != '\'') { while (line[i] != '\0' && line[i] != '\'') {
if (line[i] == '\\') { if (line[i] == '\\') {
@@ -120,14 +149,15 @@ char *highlight_line(const char *line, int *length) {
result[result_pos++] = line[i++]; result[result_pos++] = line[i++];
} }
} }
if (line[i] == '\'') result[result_pos++] = line[i++]; if (line[i] == '\'')
result[result_pos++] = line[i++];
result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET); result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET);
continue; continue;
} }
// Handle numbers // Handle numbers
if (line[i] >= '0' && line[i] <= '9') { if (line[i] >= '0' && line[i] <= '9') {
result_pos += sprintf(&result[result_pos], "%s", COLOR_NUMBER); result_pos += sprintf(&result[result_pos], "%s", E.theme.COLOR_NUMBER);
while (is_word_char(line[i]) || line[i] == '.') { while (is_word_char(line[i]) || line[i] == '.') {
result[result_pos++] = line[i++]; result[result_pos++] = line[i++];
} }
@@ -138,23 +168,28 @@ char *highlight_line(const char *line, int *length) {
// Handle identifiers and keywords // Handle identifiers and keywords
if (is_word_char(line[i])) { if (is_word_char(line[i])) {
int start = i; int start = i;
while (is_word_char(line[i])) i++; while (is_word_char(line[i]))
i++;
char word[256]; char word[256];
strncpy(word, &line[start], i - start); strncpy(word, &line[start], i - start);
word[i - start] = '\0'; word[i - start] = '\0';
TokenType type = TOKEN_DEFAULT; TokenType type = TOKEN_DEFAULT;
if (is_keyword(word)) type = TOKEN_KEYWORD; if (is_keyword(word))
else if (is_type(word)) type = TOKEN_TYPE; type = TOKEN_KEYWORD;
else if (is_type(word))
type = TOKEN_TYPE;
result_pos += sprintf(&result[result_pos], "%s%s%s", result_pos += sprintf(&result[result_pos], "%s%s%s", get_color(type),
get_color(type), word, COLOR_RESET); word, COLOR_RESET);
continue; continue;
} }
// Handle operators and other characters // Handle operators and other characters
result_pos += sprintf(&result[result_pos], "%s", E.theme.COLOR_DEFAULT);
result[result_pos++] = line[i++]; result[result_pos++] = line[i++];
result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET);
} }
result[result_pos] = '\0'; result[result_pos] = '\0';