diff options
| author | David Moc <personal@cdatgoose.org> | 2026-06-02 13:50:21 +0200 |
|---|---|---|
| committer | David Moc <personal@cdatgoose.org> | 2026-06-02 13:50:21 +0200 |
| commit | a15cb041654ae307add0b998b526c87c3f42bf5f (patch) | |
| tree | 225bb4b70e9fa05aa5f4d2722a1a9cf5fc6fca7f /src/render.c | |
| parent | 6aeaa171dc1ca43392f53cbd02097f76e1b1c5a0 (diff) | |
Add plugin hooks and mode plugins
Diffstat (limited to 'src/render.c')
| -rw-r--r-- | src/render.c | 488 |
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"); } |
