aboutsummaryrefslogtreecommitdiff
path: root/src/render.c
diff options
context:
space:
mode:
authorDavid Moc <personal@cdatgoose.org>2026-06-02 13:50:21 +0200
committerDavid Moc <personal@cdatgoose.org>2026-06-02 13:50:21 +0200
commita15cb041654ae307add0b998b526c87c3f42bf5f (patch)
tree225bb4b70e9fa05aa5f4d2722a1a9cf5fc6fca7f /src/render.c
parent6aeaa171dc1ca43392f53cbd02097f76e1b1c5a0 (diff)
Add plugin hooks and mode plugins
Diffstat (limited to 'src/render.c')
-rw-r--r--src/render.c488
1 files changed, 414 insertions, 74 deletions
diff --git a/src/render.c b/src/render.c
index 86bc535..527f29c 100644
--- a/src/render.c
+++ b/src/render.c
@@ -40,6 +40,18 @@ static float ecex_maxf(float a, float b) {
return a > b ? a : b;
}
+static size_t minibuffer_row_count(app_t *app) {
+ if (!app || app->mode != APP_MODE_PREFIX || !app->message[0]) return 1;
+
+ size_t rows = 1;
+ for (const char *p = app->message; *p; ++p) {
+ if (*p != '\n') continue;
+ rows++;
+ if (rows >= ECEX_MINIBUFFER_MAX_ROWS) return ECEX_MINIBUFFER_MAX_ROWS;
+ }
+ return rows;
+}
+
static ui_metrics_t ui_metrics(app_t *app) {
float size = app && app->font.size_px > 1.0f ? app->font.size_px : 16.0f;
float line_h = app && app->font.line_height > 1.0f
@@ -56,7 +68,7 @@ static ui_metrics_t ui_metrics(app_t *app) {
m.content_bottom_pad = m.pad_y;
m.status_h = line_h + m.pad_y * 2.0f;
- m.minibuffer_h = line_h + m.pad_y * 2.0f;
+ m.minibuffer_h = line_h * (float)minibuffer_row_count(app) + m.pad_y * 2.0f;
m.cursor_w = ecex_maxf(2.0f, size * 0.10f);
m.cursor_h = ecex_maxf(1.0f, app ? app->font.ascent_px + app->font.descent_px : size);
@@ -198,7 +210,7 @@ static void render_status_bar(app_t *app) {
char status[768];
snprintf(status,
sizeof(status),
- " %s%s %s line:%zu col:%zu top:%zu size:%zu buffers:%zu windows:%zu commands:%zu%s%s",
+ "%s%s | %s | Ln %zu, Col %zu | Top %zu | %zu bytes | %zu buffers / %zu windows%s%s",
buf->name ? buf->name : "(unnamed)",
buf->modified ? " *" : "",
ecex_buffer_major_mode_name(app->ed, buf),
@@ -208,7 +220,6 @@ static void render_status_bar(app_t *app) {
buf->len,
app->ed->buffer_count,
ecex_window_count(app->ed),
- app->ed->command_count,
buf->path ? " " : "",
buf->path ? buf->path : "");
@@ -262,6 +273,11 @@ static void render_minibuffer(app_t *app) {
app->ed->theme.minibuffer_bg.b);
draw_rect(0.0f, y, (float)app->width, h);
+ glColor3f(app->ed->theme.status_border.r,
+ app->ed->theme.status_border.g,
+ app->ed->theme.status_border.b);
+ draw_rect(0.0f, y, (float)app->width, 1.0f);
+
glColor3f(app->ed->theme.minibuffer_fg.r,
app->ed->theme.minibuffer_fg.g,
app->ed->theme.minibuffer_fg.b);
@@ -345,9 +361,29 @@ static void render_minibuffer(app_t *app) {
}
}
} else if (app->mode == APP_MODE_PREFIX) {
- char line[ECEX_PREFIX_SIZE + 8];
- snprintf(line, sizeof(line), "%s-", app->prefix);
- draw_text(&app->font, text_x, text_y, line);
+ if (app->message[0]) {
+ const char *line = app->message;
+ size_t row = 0;
+ while (line && *line && row < ECEX_MINIBUFFER_MAX_ROWS) {
+ const char *end = strchr(line, '\n');
+ size_t len = end ? (size_t)(end - line) : strlen(line);
+ char scratch[ECEX_MINIBUFFER_SIZE];
+ if (len >= sizeof(scratch)) len = sizeof(scratch) - 1;
+ memcpy(scratch, line, len);
+ scratch[len] = '\0';
+ draw_text(&app->font,
+ text_x,
+ line_baseline(app, y + m.pad_y + app->font.line_height * (float)row),
+ scratch);
+ row++;
+ if (!end) break;
+ line = end + 1;
+ }
+ } else {
+ char line[ECEX_PREFIX_SIZE + 8];
+ snprintf(line, sizeof(line), "%s-", app->prefix);
+ draw_text(&app->font, text_x, text_y, line);
+ }
} else {
draw_text(&app->font, text_x, text_y, app->message);
}
@@ -418,6 +454,241 @@ static void draw_selection_for_line(app_t *app,
draw_rect(x, line_top, w, app->font.line_height);
}
+static int c_syntax_ident_start(char c) {
+ return (c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') ||
+ c == '_';
+}
+
+static int c_syntax_ident_char(char c) {
+ return c_syntax_ident_start(c) || (c >= '0' && c <= '9');
+}
+
+static int c_syntax_keyword(const char *text, size_t len) {
+ static const char *keywords[] = {
+ "alignas", "alignof", "auto", "bool", "break", "case", "char",
+ "const", "constexpr", "continue", "default", "do", "double",
+ "else", "enum", "extern", "false", "float", "for", "goto", "if",
+ "inline", "int", "long", "nullptr", "register", "restrict",
+ "return", "short", "signed", "sizeof", "static", "static_assert",
+ "struct", "switch", "thread_local", "true", "typedef", "typeof",
+ "typeof_unqual", "union", "unsigned", "void", "volatile", "while",
+ "_Alignas", "_Alignof", "_Atomic", "_Bool", "_Complex", "_Generic",
+ "_Imaginary", "_Noreturn", "_Static_assert", "_Thread_local", "NULL",
+ "size_t", "ptrdiff_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t",
+ "int8_t", "int16_t", "int32_t", "int64_t", "FILE"
+ };
+
+ for (size_t i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) {
+ if (strlen(keywords[i]) == len && strncmp(text, keywords[i], len) == 0) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int c_syntax_line_is_preprocessor(buffer_t *buf, size_t line_start, size_t line_end) {
+ if (!buf || !buf->data) return 0;
+ size_t i = line_start;
+ while (i < line_end && (buf->data[i] == ' ' || buf->data[i] == '\t')) i++;
+ return i < line_end && buf->data[i] == '#';
+}
+
+static int c_syntax_block_comment_at(buffer_t *buf, size_t pos) {
+ if (!buf || !buf->data) return 0;
+
+ int in_block = 0;
+ int in_string = 0;
+ int in_char = 0;
+ int escaped = 0;
+
+ for (size_t i = 0; i < pos && i < buf->len; i++) {
+ char c = buf->data[i];
+ char next = i + 1 < pos && i + 1 < buf->len ? buf->data[i + 1] : '\0';
+
+ if (in_block) {
+ if (c == '*' && next == '/') {
+ in_block = 0;
+ i++;
+ }
+ continue;
+ }
+
+ if (in_string) {
+ if (escaped) escaped = 0;
+ else if (c == '\\') escaped = 1;
+ else if (c == '"') in_string = 0;
+ else if (c == '\n') in_string = 0;
+ continue;
+ }
+
+ if (in_char) {
+ if (escaped) escaped = 0;
+ else if (c == '\\') escaped = 1;
+ else if (c == '\'') in_char = 0;
+ else if (c == '\n') in_char = 0;
+ continue;
+ }
+
+ if (c == '/' && next == '*') {
+ in_block = 1;
+ i++;
+ } else if (c == '/' && next == '/') {
+ while (i < pos && i < buf->len && buf->data[i] != '\n') i++;
+ } else if (c == '"') {
+ in_string = 1;
+ } else if (c == '\'') {
+ in_char = 1;
+ }
+ }
+
+ return in_block;
+}
+
+static void c_syntax_set_color(app_t *app, int kind, int highlighted) {
+ if (highlighted) {
+ set_editor_text_color(app, highlighted);
+ return;
+ }
+
+ switch (kind) {
+ case 1: glColor3f(0.43f, 0.78f, 1.00f); break; /* keyword */
+ case 2: glColor3f(0.68f, 0.91f, 0.42f); break; /* string */
+ case 3: glColor3f(0.64f, 0.67f, 0.73f); break; /* comment */
+ case 4: glColor3f(1.00f, 0.58f, 0.78f); break; /* number */
+ case 5: glColor3f(1.00f, 0.82f, 0.25f); break; /* preprocessor */
+ default: set_editor_text_color(app, highlighted); break;
+ }
+}
+
+static void c_syntax_draw_span(app_t *app,
+ buffer_t *buf,
+ size_t start,
+ size_t end,
+ float *x,
+ float baseline,
+ int kind,
+ int highlighted) {
+ if (!app || !buf || !x || start >= end) return;
+
+ char *span = buffer_substring(buf, start, end);
+ if (!span) return;
+
+ c_syntax_set_color(app, kind, highlighted);
+ draw_text(&app->font, *x, baseline, span);
+ *x += text_width(&app->font, span);
+ free(span);
+}
+
+static void draw_c_syntax_line(app_t *app,
+ buffer_t *buf,
+ size_t line_start,
+ size_t visible_start,
+ size_t line_end,
+ float x,
+ float baseline,
+ int highlighted) {
+ if (!app || !buf || !buf->data || visible_start >= line_end) return;
+
+ if (c_syntax_line_is_preprocessor(buf, line_start, line_end)) {
+ c_syntax_draw_span(app, buf, visible_start, line_end, &x, baseline, 5, highlighted);
+ return;
+ }
+
+ int in_block = c_syntax_block_comment_at(buf, visible_start);
+ size_t pos = visible_start;
+
+ while (pos < line_end) {
+ if (in_block) {
+ size_t end = pos;
+ while (end + 1 < line_end &&
+ !(buf->data[end] == '*' && buf->data[end + 1] == '/')) {
+ end++;
+ }
+ if (end + 1 < line_end) {
+ end += 2;
+ in_block = 0;
+ } else {
+ end = line_end;
+ }
+ c_syntax_draw_span(app, buf, pos, end, &x, baseline, 3, highlighted);
+ pos = end;
+ continue;
+ }
+
+ char c = buf->data[pos];
+ char next = pos + 1 < line_end ? buf->data[pos + 1] : '\0';
+
+ if (c == '/' && next == '/') {
+ c_syntax_draw_span(app, buf, pos, line_end, &x, baseline, 3, highlighted);
+ break;
+ }
+
+ if (c == '/' && next == '*') {
+ size_t end = pos + 2;
+ while (end + 1 < line_end &&
+ !(buf->data[end] == '*' && buf->data[end + 1] == '/')) {
+ end++;
+ }
+ if (end + 1 < line_end) end += 2;
+ else end = line_end;
+ c_syntax_draw_span(app, buf, pos, end, &x, baseline, 3, highlighted);
+ pos = end;
+ continue;
+ }
+
+ if (c == '"' || c == '\'') {
+ char quote = c;
+ size_t end = pos + 1;
+ int escaped = 0;
+ while (end < line_end) {
+ char sc = buf->data[end++];
+ if (escaped) {
+ escaped = 0;
+ } else if (sc == '\\') {
+ escaped = 1;
+ } else if (sc == quote) {
+ break;
+ }
+ }
+ c_syntax_draw_span(app, buf, pos, end, &x, baseline, 2, highlighted);
+ pos = end;
+ continue;
+ }
+
+ if ((c >= '0' && c <= '9') || (c == '.' && next >= '0' && next <= '9')) {
+ size_t end = pos + 1;
+ while (end < line_end) {
+ char nc = buf->data[end];
+ if ((nc >= '0' && nc <= '9') ||
+ (nc >= 'a' && nc <= 'f') ||
+ (nc >= 'A' && nc <= 'F') ||
+ nc == 'x' || nc == 'X' || nc == 'u' || nc == 'U' ||
+ nc == 'l' || nc == 'L' || nc == '.' || nc == '+' || nc == '-') {
+ end++;
+ } else {
+ break;
+ }
+ }
+ c_syntax_draw_span(app, buf, pos, end, &x, baseline, 4, highlighted);
+ pos = end;
+ continue;
+ }
+
+ if (c_syntax_ident_start(c)) {
+ size_t end = pos + 1;
+ while (end < line_end && c_syntax_ident_char(buf->data[end])) end++;
+ int kind = c_syntax_keyword(buf->data + pos, end - pos) ? 1 : 0;
+ c_syntax_draw_span(app, buf, pos, end, &x, baseline, kind, highlighted);
+ pos = end;
+ continue;
+ }
+
+ c_syntax_draw_span(app, buf, pos, pos + 1, &x, baseline, 0, highlighted);
+ pos++;
+ }
+}
+
static void draw_buffer_line(app_t *app,
buffer_t *buf,
view_rect_t rect,
@@ -467,12 +738,20 @@ static void draw_buffer_line(app_t *app,
draw_text(&app->font, rect.x + m.pad_x * 0.5f, line_baseline(app, line_top), nbuf);
}
- char *line = buffer_substring(buf, start, line_end);
- if (!line) return;
+ float text_x = rect.x + m.content_x + gutter;
+ float baseline = line_baseline(app, line_top);
+ const char *mode_name = ecex_buffer_major_mode_name(app->ed, buf);
- set_editor_text_color(app, highlighted);
- draw_text(&app->font, rect.x + m.content_x + gutter, line_baseline(app, line_top), line);
- free(line);
+ if (mode_name && strcmp(mode_name, "c-mode") == 0) {
+ draw_c_syntax_line(app, buf, line_start, start, line_end, text_x, baseline, highlighted);
+ } else {
+ char *line = buffer_substring(buf, start, line_end);
+ if (!line) return;
+
+ set_editor_text_color(app, highlighted);
+ draw_text(&app->font, text_x, baseline, line);
+ free(line);
+ }
}
@@ -653,7 +932,7 @@ void ecex_draw_text_aligned(ecex_draw_context_t *ctx, float x, float y, float w,
ecex_draw_text(ctx, tx, y, text);
}
-void ecex_draw_color_rgba8(ecex_draw_context_t *ctx, int r, int g, int b, int a) {
+void ecex_draw_color_rgba8_i(ecex_draw_context_t *ctx, int r, int g, int b, int a) {
if (!ctx) return;
if (r < 0) r = 0; if (r > 255) r = 255;
if (g < 0) g = 0; if (g > 255) g = 255;
@@ -705,10 +984,7 @@ static const char *ecex_draw_label_text(int label_id) {
}
static unsigned char ecex_ascii5x7_bits(char ch, int row) {
- /* Tiny host-side pixel font used by CCDJIT-safe label helpers. This avoids
- * routing plugin labels through the normal stb/font text renderer, which is
- * useful while plugin callback ABI issues are being isolated. Bits are
- * returned left-to-right in the low 5 bits. */
+ /* Last-resort fallback for host labels when no editor font texture exists. */
if (row < 0 || row >= 7) return 0;
switch (ch) {
case '0': { static const unsigned char b[7] = {14,17,19,21,25,17,14}; return b[row]; }
@@ -778,47 +1054,91 @@ static void ecex_draw_mini_text_i(ecex_draw_context_t *ctx, int x, int y, const
}
}
+static int ecex_draw_has_loaded_font(ecex_draw_context_t *ctx) {
+ app_t *app = draw_context_app(ctx);
+ return app && app->font.texture != 0;
+}
+
+static void ecex_draw_host_text_i(ecex_draw_context_t *ctx, int x, int y, const char *text) {
+ if (!ctx || !text) return;
+ if (ecex_draw_has_loaded_font(ctx)) {
+ ecex_draw_text(ctx, (float)x, (float)y, text);
+ } else {
+ ecex_draw_mini_text_i(ctx, x, y, text);
+ }
+}
+
+static void ecex_draw_color_packed_rgba8_i(ecex_draw_context_t *ctx, unsigned int rgba) {
+ ecex_draw_color_rgba8_i(ctx,
+ (int)((rgba >> 24) & 0xffu),
+ (int)((rgba >> 16) & 0xffu),
+ (int)((rgba >> 8) & 0xffu),
+ (int)(rgba & 0xffu));
+}
-extern const char *ecex_text_get_for_draw(ecex_t *ed, void *owner, int id);
-void ecex_draw_text_id_i(ecex_draw_context_t *ctx, void *owner, int id, int x, int y) {
+void ecex_draw_plugin_text_i(ecex_draw_context_t *ctx, void *owner, int id, int x, int y) {
app_t *app;
const char *text;
if (!ctx || !ctx->internal) return;
app = (app_t *)ctx->internal;
if (!app || !app->ed) return;
- text = ecex_text_get_for_draw(app->ed, owner, id);
+ text = ecex_plugin_text_get_drawable(app->ed, owner, id);
if (!text) text = "";
/*
- * Plugin-safe real-font path: plugin code passes only owner/id and integer
- * coordinates. The string itself lives in the host text registry, and the
+ * Plugin-safe real-font path: plugin code passes only plugin/id and integer
+ * coordinates. The string itself lives in plugin-owned host storage, and the
* actual font renderer is called here on the host side, not directly from
- * JIT-owned stack/string memory. Fixed labels may still use the mini-font
- * helpers, but arbitrary plugin text such as Markdown should render with
- * the loaded editor font.
+ * JIT-owned stack/string memory.
*/
- ecex_draw_text(ctx, (float)x, (float)y, text);
+ ecex_draw_host_text_i(ctx, x, y, text);
+}
+
+void ecex_draw_plugin_text_rect_i(ecex_draw_context_t *ctx,
+ void *owner,
+ int id,
+ int x,
+ int y,
+ int w,
+ int h,
+ int padding,
+ unsigned int bg_rgba,
+ unsigned int fg_rgba) {
+ app_t *app;
+ const char *text;
+ if (!ctx || !ctx->internal || w <= 0 || h <= 0) return;
+ app = (app_t *)ctx->internal;
+ if (!app || !app->ed) return;
+ if (padding < 0) padding = 0;
+
+ text = ecex_plugin_text_get_drawable(app->ed, owner, id);
+ if (!text) text = "";
+
+ ecex_draw_color_packed_rgba8_i(ctx, bg_rgba);
+ ecex_draw_rect_i(ctx, x, y, w, h);
+ ecex_draw_color_packed_rgba8_i(ctx, fg_rgba);
+ ecex_draw_host_text_i(ctx, x + padding, y + padding, text);
}
-int ecex_draw_context_height_i(ecex_draw_context_t *ctx) {
+int ecex_draw_context_height_px(ecex_draw_context_t *ctx) {
if (!ctx) return 0;
return (int)ctx->h;
}
-int ecex_draw_context_line_height_i(ecex_draw_context_t *ctx) {
+int ecex_draw_context_line_height_px(ecex_draw_context_t *ctx) {
int line_h;
if (!ctx) return 18;
line_h = (int)ctx->line_height;
return line_h < 18 ? 18 : line_h;
}
-int ecex_markdown_body_y_i(ecex_draw_context_t *ctx) {
+int ecex_markdown_body_y_px(ecex_draw_context_t *ctx) {
int line_h;
if (!ctx) return 36;
- line_h = ecex_draw_context_line_height_i(ctx);
+ line_h = ecex_draw_context_line_height_px(ctx);
return (int)ctx->content_y + line_h * 2;
}
@@ -925,12 +1245,12 @@ static void md_host_set_and_draw(ecex_draw_context_t *ctx, void *owner, int y, i
if (!app || !app->ed) return;
start = md_host_trim_start(text);
len = md_host_trim_len(start);
- if (ecex_text_set(app->ed, owner, 2, start, len) == 0) {
+ if (ecex_plugin_text_set((ecex_plugin_t *)owner, 2, start, len) == 0) {
ecex_draw_markdown_line_auto_i(ctx, owner, 2, y, style);
}
}
-int ecex_markdown_draw_line_from_buffer_i(ecex_draw_context_t *ctx, void *owner, buffer_t *buffer, int line_index, int y, int in_code) {
+int ecex_markdown_draw_buffer_line_i(ecex_draw_context_t *ctx, void *owner, buffer_t *buffer, int line_index, int y, int in_code) {
char line[512];
const char *text = NULL;
int copied;
@@ -942,8 +1262,8 @@ int ecex_markdown_draw_line_from_buffer_i(ecex_draw_context_t *ctx, void *owner,
if (!ctx || !ctx->internal || !buffer) return 18;
app = (app_t *)ctx->internal;
- line_h = ecex_draw_context_line_height_i(ctx);
- copied = ecex_buffer_line_copy(buffer, line_index, line, (int)sizeof(line));
+ line_h = ecex_draw_context_line_height_px(ctx);
+ copied = ecex_buffer_line_copy_text(buffer, line_index, line, (int)sizeof(line));
if (line_index < 4) {
ecex_log_int("markdown_host_line: index=", line_index);
ecex_log_int("markdown_host_line: copied=", copied);
@@ -953,14 +1273,14 @@ int ecex_markdown_draw_line_from_buffer_i(ecex_draw_context_t *ctx, void *owner,
if (md_host_line_is_fence(line)) {
next_in_code = !next_in_code;
- if (app && app->ed) ecex_text_set(app->ed, owner, 2, next_in_code ? "code" : "end code", -1);
+ if (app && app->ed) ecex_plugin_text_set((ecex_plugin_t *)owner, 2, next_in_code ? "code" : "end code", -1);
ecex_draw_markdown_line_auto_i(ctx, owner, 2, y, 5);
advance = line_h + 8;
return advance | (next_in_code ? 0x10000 : 0);
}
if (next_in_code) {
- if (app && app->ed) ecex_text_set(app->ed, owner, 2, line, copied > 224 ? 224 : copied);
+ if (app && app->ed) ecex_plugin_text_set((ecex_plugin_t *)owner, 2, line, copied > 224 ? 224 : copied);
ecex_draw_markdown_line_auto_i(ctx, owner, 2, y, 3);
return line_h | 0x10000;
}
@@ -973,7 +1293,7 @@ int ecex_markdown_draw_line_from_buffer_i(ecex_draw_context_t *ctx, void *owner,
}
if (md_host_line_is_hr(line)) {
- if (app && app->ed) ecex_text_set(app->ed, owner, 2, "", 0);
+ if (app && app->ed) ecex_plugin_text_set((ecex_plugin_t *)owner, 2, "", 0);
ecex_draw_markdown_line_auto_i(ctx, owner, 2, y, 6);
return line_h;
}
@@ -1008,13 +1328,13 @@ void ecex_draw_markdown_canvas_i(ecex_draw_context_t *ctx, void *owner, int titl
if (w < 1) w = full_w - x * 2;
if (w < 1) w = 1;
if (line_h < 18) line_h = 18;
- ecex_draw_color_rgba8(ctx, 29, 32, 33, 255);
+ ecex_draw_color_rgba8_i(ctx, 29, 32, 33, 255);
ecex_draw_rect_i(ctx, 0, 0, full_w, full_h);
- ecex_draw_color_rgba8(ctx, 250, 241, 199, 255);
- title = (app && app->ed) ? ecex_text_get_for_draw(app->ed, owner, title_id) : "";
+ ecex_draw_color_rgba8_i(ctx, 250, 241, 199, 255);
+ title = (app && app->ed) ? ecex_plugin_text_get_drawable(app->ed, owner, title_id) : "";
if (!title) title = "";
ecex_draw_text(ctx, (float)x, (float)y, title);
- ecex_draw_color_rgba8(ctx, 80, 73, 69, 255);
+ ecex_draw_color_rgba8_i(ctx, 80, 73, 69, 255);
ecex_draw_line_i(ctx, x, y + line_h + 8, x + w, y + line_h + 8, 1);
}
@@ -1024,49 +1344,49 @@ void ecex_draw_markdown_text_i(ecex_draw_context_t *ctx, void *owner, int text_i
int h;
if (!ctx || !ctx->internal) return;
app = (app_t *)ctx->internal;
- text = (app && app->ed) ? ecex_text_get_for_draw(app->ed, owner, text_id) : "";
+ text = (app && app->ed) ? ecex_plugin_text_get_drawable(app->ed, owner, text_id) : "";
if (!text) text = "";
if (w < 1) w = 1;
if (line_h < 18) line_h = 18;
h = line_h + 4;
switch (style) {
case 1: /* heading */
- ecex_draw_color_rgba8(ctx, 69, 84, 96, 255);
+ ecex_draw_color_rgba8_i(ctx, 69, 84, 96, 255);
ecex_draw_rect_i(ctx, x, y - 5, w, h + 6);
- ecex_draw_color_rgba8(ctx, 250, 189, 47, 255);
+ ecex_draw_color_rgba8_i(ctx, 250, 189, 47, 255);
ecex_draw_text(ctx, (float)(x + 10), (float)y, text);
break;
case 2: /* quote */
- ecex_draw_color_rgba8(ctx, 131, 165, 152, 255);
+ ecex_draw_color_rgba8_i(ctx, 131, 165, 152, 255);
ecex_draw_rect_i(ctx, x, y - 2, 4, h);
- ecex_draw_color_rgba8(ctx, 213, 196, 161, 255);
+ ecex_draw_color_rgba8_i(ctx, 213, 196, 161, 255);
ecex_draw_text(ctx, (float)(x + 14), (float)y, text);
break;
case 3: /* code */
- ecex_draw_color_rgba8(ctx, 40, 40, 40, 255);
+ ecex_draw_color_rgba8_i(ctx, 40, 40, 40, 255);
ecex_draw_rect_i(ctx, x, y - 2, w, h);
- ecex_draw_color_rgba8(ctx, 213, 196, 161, 255);
+ ecex_draw_color_rgba8_i(ctx, 213, 196, 161, 255);
ecex_draw_text(ctx, (float)(x + 10), (float)y, text);
break;
case 4: /* list */
- ecex_draw_color_rgba8(ctx, 184, 187, 38, 255);
+ ecex_draw_color_rgba8_i(ctx, 184, 187, 38, 255);
ecex_draw_rect_i(ctx, x + 6, y + line_h / 2 - 3, 6, 6);
- ecex_draw_color_rgba8(ctx, 235, 219, 178, 255);
+ ecex_draw_color_rgba8_i(ctx, 235, 219, 178, 255);
ecex_draw_text(ctx, (float)(x + 24), (float)y, text);
break;
case 5: /* fence */
- ecex_draw_color_rgba8(ctx, 80, 73, 69, 255);
+ ecex_draw_color_rgba8_i(ctx, 80, 73, 69, 255);
ecex_draw_rect_i(ctx, x, y - 3, w, line_h + 6);
- ecex_draw_color_rgba8(ctx, 142, 192, 124, 255);
+ ecex_draw_color_rgba8_i(ctx, 142, 192, 124, 255);
ecex_draw_text(ctx, (float)(x + 10), (float)y, text);
break;
case 6: /* hr */
- ecex_draw_color_rgba8(ctx, 80, 73, 69, 255);
+ ecex_draw_color_rgba8_i(ctx, 80, 73, 69, 255);
ecex_draw_line_i(ctx, x, y + line_h / 2, x + w, y + line_h / 2, 2);
break;
case 0:
default:
- ecex_draw_color_rgba8(ctx, 235, 219, 178, 255);
+ ecex_draw_color_rgba8_i(ctx, 235, 219, 178, 255);
ecex_draw_text(ctx, (float)x, (float)y, text);
break;
}
@@ -1106,7 +1426,7 @@ void ecex_draw_markdown_line_auto_i(ecex_draw_context_t *ctx, void *owner, int t
}
void ecex_draw_label_i(ecex_draw_context_t *ctx, int x, int y, int label_id) {
- ecex_draw_mini_text_i(ctx, x, y, ecex_draw_label_text(label_id));
+ ecex_draw_host_text_i(ctx, x, y, ecex_draw_label_text(label_id));
}
static void ecex_i32_to_ascii(int value, char *buf, size_t cap) {
@@ -1131,11 +1451,12 @@ static void ecex_i32_to_ascii(int value, char *buf, size_t cap) {
void ecex_draw_stat_i(ecex_draw_context_t *ctx, int x, int y, int label_id, int value) {
char num[24];
+ char text[128];
const char *prefix = ecex_draw_label_text(label_id);
if (!ctx || !prefix) return;
- ecex_draw_mini_text_i(ctx, x, y, prefix);
ecex_i32_to_ascii(value, num, sizeof(num));
- ecex_draw_mini_text_i(ctx, x + (int)strlen(prefix) * 12, y, num);
+ snprintf(text, sizeof(text), "%s%s", prefix, num);
+ ecex_draw_host_text_i(ctx, x, y, text);
}
@@ -1177,13 +1498,13 @@ static int ecex_tetris_preview_shape_cell(int piece, int rot, int col, int row)
}
static void ecex_draw_tetris_preview_color(ecex_draw_context_t *ctx, int piece, int alpha) {
- if (piece == 0) ecex_draw_color_rgba8(ctx, 51, 191, 242, alpha);
- else if (piece == 1) ecex_draw_color_rgba8(ctx, 242, 217, 51, alpha);
- else if (piece == 2) ecex_draw_color_rgba8(ctx, 179, 89, 242, alpha);
- else if (piece == 3) ecex_draw_color_rgba8(ctx, 77, 217, 89, alpha);
- else if (piece == 4) ecex_draw_color_rgba8(ctx, 242, 64, 64, alpha);
- else if (piece == 5) ecex_draw_color_rgba8(ctx, 64, 102, 242, alpha);
- else ecex_draw_color_rgba8(ctx, 242, 140, 51, alpha);
+ if (piece == 0) ecex_draw_color_rgba8_i(ctx, 51, 191, 242, alpha);
+ else if (piece == 1) ecex_draw_color_rgba8_i(ctx, 242, 217, 51, alpha);
+ else if (piece == 2) ecex_draw_color_rgba8_i(ctx, 179, 89, 242, alpha);
+ else if (piece == 3) ecex_draw_color_rgba8_i(ctx, 77, 217, 89, alpha);
+ else if (piece == 4) ecex_draw_color_rgba8_i(ctx, 242, 64, 64, alpha);
+ else if (piece == 5) ecex_draw_color_rgba8_i(ctx, 64, 102, 242, alpha);
+ else ecex_draw_color_rgba8_i(ctx, 242, 140, 51, alpha);
}
void ecex_draw_tetris_preview_i(ecex_draw_context_t *ctx, int piece, int x, int y, int cell, int alpha) {
@@ -1198,7 +1519,7 @@ void ecex_draw_tetris_preview_i(ecex_draw_context_t *ctx, int piece, int x, int
/* Clear a small preview box first so the old preview shape cannot linger
* when the new piece occupies fewer cells than the previous I piece. */
- ecex_draw_color_rgba8(ctx, 20, 23, 28, 255);
+ ecex_draw_color_rgba8_i(ctx, 20, 23, 28, 255);
ecex_draw_rect_i(ctx, x - 2, y - 2, cell * 4 + 4, cell * 4 + 4);
for (r = 0; r < 4; ++r) {
@@ -1275,15 +1596,23 @@ static void render_custom_buffer(app_t *app, buffer_t *buf, view_rect_t rect, si
const char *trace_env = getenv("ECEX_TRACE_CALLBACKS");
trace_callbacks = trace_env && trace_env[0] && trace_env[0] != '0';
if (trace_callbacks) {
- fprintf(stderr, "ecex-log: render_callback_enter buffer=%p fn=%p userdata=%p window=%zu %.1fx%.1f\n",
- (void *)buf, (void *)buf->render_fn, buf->render_userdata, index, rect.w, rect.h);
- fflush(stderr);
+ char msg[256];
+ snprintf(msg,
+ sizeof(msg),
+ "render callback start buffer=%p fn=%p userdata=%p window=%zu %.1fx%.1f",
+ (void *)buf,
+ (void *)buf->render_fn,
+ buf->render_userdata,
+ index,
+ rect.w,
+ rect.h);
+ ecex_log_group_begin(msg);
}
int result = buf->render_fn(app->ed, buf, &ctx, buf->render_userdata);
if (trace_callbacks) {
- fprintf(stderr, "ecex-log: render_callback_leave buffer=%p result=%d\n",
- (void *)buf, result);
- fflush(stderr);
+ char msg[128];
+ snprintf(msg, sizeof(msg), "render callback end buffer=%p result=%d", (void *)buf, result);
+ ecex_log_group_end(msg);
}
}
@@ -1310,13 +1639,13 @@ static void render_buffer_window(app_t *app, ecex_window_t *win, size_t index, f
glEnable(GL_SCISSOR_TEST);
glScissor(sx, sy, sw, sh);
- if (index == app->ed->current_window_index) {
- ensure_cursor_visible(app, buf, rect);
- }
-
int replace_content = buf->render_fn && (buf->render_flags & ECEX_RENDER_REPLACE_CONTENT);
if (!replace_content) {
+ if (index == app->ed->current_window_index) {
+ ensure_cursor_visible(app, buf, rect);
+ }
+
size_t rows = visible_row_count_for_rect(app, rect);
size_t pos = offset_for_line(buf, buf->scroll_line);
float line_top = rect.y + m.content_top;
@@ -1373,6 +1702,15 @@ void render(app_t *app) {
glfwGetFramebufferSize(app->window, &app->width, &app->height);
+ char frame_start[128];
+ snprintf(frame_start,
+ sizeof(frame_start),
+ "frame start size=%dx%d windows=%zu",
+ app->width,
+ app->height,
+ ecex_window_count(app->ed));
+ ecex_log_group_begin(frame_start);
+
setup_2d(app->width, app->height);
glClearColor(app->ed->theme.bg.r,
@@ -1387,4 +1725,6 @@ void render(app_t *app) {
render_windows(app);
render_minibuffer(app);
render_status_bar(app);
+
+ ecex_log_group_end("frame end");
}