ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
error_popup.c File Reference

Go to the source code of this file.

Macros

#define TUI_ERROR_POPUP_WRAPPED_BUFFER_SIZE   65536
#define TUI_ERROR_POPUP_STYLE_BUFFER_SIZE   128
#define TUI_ERROR_POPUP_THREAD_BUFFER_SIZE   160
#define TUI_ERROR_POPUP_FILE_BUFFER_SIZE   1024
#define TUI_ERROR_POPUP_FUNCTION_BUFFER_SIZE   256
#define TUI_ERROR_POPUP_LINE_BUFFER_SIZE   24
#define TUI_ERROR_POPUP_ADDRESS_BUFFER_SIZE   40
#define TUI_ERROR_POPUP_TITLE_BUFFER_SIZE   128
#define TUI_ERROR_POPUP_HEADING_BUFFER_SIZE   256
#define TUI_ERROR_POPUP_CODE_BUFFER_SIZE   512
#define TUI_ERROR_POPUP_CELL_BUFFER_SIZE   1024
#define TUI_ERROR_POPUP_FINAL_OUTPUT_BUFFER_SIZE   65536
#define ERROR_POPUP_LINE_CAPACITY   2048

Functions

bool ui_error_popup_visible (void)
uint64_t ui_error_popup_revision (void)
terminal_size_t ui_error_popup_minimum (void)
void ui_error_popup_key (keyboard_key_t key)
void ui_error_popup_render (frame_buffer_t *out, terminal_size_t size)
void ui_error_popup_reset (void)
void ui_error_popup_preserve (int fd, terminal_size_t size)
void ui_error_popup_flush (void)

Macro Definition Documentation

◆ ERROR_POPUP_LINE_CAPACITY

#define ERROR_POPUP_LINE_CAPACITY   2048

Definition at line 17 of file error_popup.c.

◆ TUI_ERROR_POPUP_ADDRESS_BUFFER_SIZE

#define TUI_ERROR_POPUP_ADDRESS_BUFFER_SIZE   40

Definition at line 9 of file error_popup.c.

◆ TUI_ERROR_POPUP_CELL_BUFFER_SIZE

#define TUI_ERROR_POPUP_CELL_BUFFER_SIZE   1024

Definition at line 13 of file error_popup.c.

Referenced by ui_error_popup_preserve(), and ui_error_popup_render().

◆ TUI_ERROR_POPUP_CODE_BUFFER_SIZE

#define TUI_ERROR_POPUP_CODE_BUFFER_SIZE   512

Definition at line 12 of file error_popup.c.

Referenced by ui_error_popup_preserve(), and ui_error_popup_render().

◆ TUI_ERROR_POPUP_FILE_BUFFER_SIZE

#define TUI_ERROR_POPUP_FILE_BUFFER_SIZE   1024

Definition at line 6 of file error_popup.c.

◆ TUI_ERROR_POPUP_FINAL_OUTPUT_BUFFER_SIZE

#define TUI_ERROR_POPUP_FINAL_OUTPUT_BUFFER_SIZE   65536

Definition at line 14 of file error_popup.c.

◆ TUI_ERROR_POPUP_FUNCTION_BUFFER_SIZE

#define TUI_ERROR_POPUP_FUNCTION_BUFFER_SIZE   256

Definition at line 7 of file error_popup.c.

◆ TUI_ERROR_POPUP_HEADING_BUFFER_SIZE

#define TUI_ERROR_POPUP_HEADING_BUFFER_SIZE   256

Definition at line 11 of file error_popup.c.

Referenced by ui_error_popup_render().

◆ TUI_ERROR_POPUP_LINE_BUFFER_SIZE

#define TUI_ERROR_POPUP_LINE_BUFFER_SIZE   24

Definition at line 8 of file error_popup.c.

◆ TUI_ERROR_POPUP_STYLE_BUFFER_SIZE

#define TUI_ERROR_POPUP_STYLE_BUFFER_SIZE   128

Definition at line 4 of file error_popup.c.

◆ TUI_ERROR_POPUP_THREAD_BUFFER_SIZE

#define TUI_ERROR_POPUP_THREAD_BUFFER_SIZE   160

Definition at line 5 of file error_popup.c.

◆ TUI_ERROR_POPUP_TITLE_BUFFER_SIZE

#define TUI_ERROR_POPUP_TITLE_BUFFER_SIZE   128

Definition at line 10 of file error_popup.c.

Referenced by ui_error_popup_render().

◆ TUI_ERROR_POPUP_WRAPPED_BUFFER_SIZE

#define TUI_ERROR_POPUP_WRAPPED_BUFFER_SIZE   65536

Definition at line 3 of file error_popup.c.

Referenced by ui_error_popup_preserve().

Function Documentation

◆ ui_error_popup_flush()

void ui_error_popup_flush ( void )

Write preserved terminal output after shutdown diagnostics, without allocating or using options.

Definition at line 458 of file error_popup.c.

458 {
459 if (g_final_length)
460 platform_write_all(g_final_fd, g_final_output, g_final_length);
461 g_final_length = 0;
462}
size_t platform_write_all(int fd, const void *buf, size_t count)
Write all bytes to a file descriptor, handling partial writes.

References platform_write_all().

Referenced by asciichat_shared_destroy().

◆ ui_error_popup_key()

void ui_error_popup_key ( keyboard_key_t key)

Definition at line 87 of file error_popup.c.

87 {
88 lock_state();
89 refresh_locked();
90 uint64_t dismiss = 0;
91 size_t previous = g_selected;
92 size_t previous_scroll = g_scroll;
93 switch ((int)key) {
94 case KEY_ESCAPE:
95 case 'q':
96 case '\r':
97 case '\n':
98 /* Dismiss all notifications currently shown. The popup may receive the
99 * first key before its presentation-thread snapshot has been rendered. */
100 dismiss = UINT64_MAX;
101 break;
102 case KEY_LEFT:
103 if (g_selected)
104 --g_selected;
105 break;
106 case KEY_RIGHT:
107 if (g_selected + 1 < g_count)
108 ++g_selected;
109 break;
110 case KEY_HOME:
111 g_selected = 0;
112 break;
113 case KEY_END:
114 g_selected = g_count ? g_count - 1 : 0;
115 break;
116 case KEY_UP:
117 if (g_scroll)
118 --g_scroll;
119 break;
120 case KEY_DOWN:
121 ++g_scroll;
122 break;
123 case KEY_PAGEUP:
124 g_scroll = g_scroll > g_page_rows ? g_scroll - g_page_rows : 0;
125 break;
126 case KEY_PAGEDOWN:
127 g_scroll += g_page_rows;
128 break;
129 default:
130 break;
131 }
132 if (g_selected != previous)
133 g_scroll = 0;
134 size_t maximum = g_body_rows > g_page_rows ? g_body_rows - g_page_rows : 0;
135 if (g_scroll > maximum)
136 g_scroll = maximum;
137 bool selection_changed = previous != g_selected;
138 bool scrolled = previous_scroll != g_scroll && !selection_changed;
139 unlock_state();
140 if (selection_changed)
141 ascii_otel_ui_usage("error", "selected", 0);
142 if (scrolled)
143 ascii_otel_ui_usage("error", "details_scrolled", 0);
144 if (dismiss)
145 ascii_otel_ui_usage("error", "dismissed", 0);
146 if (dismiss)
149}
void errno_notifications_dismiss(uint64_t through_id)
unsigned long long uint64_t
Definition common.h:63
@ KEY_UP
Up arrow key.
Definition keyboard.h:57
@ KEY_ESCAPE
Escape key (ESC).
Definition keyboard.h:55
@ KEY_PAGEDOWN
Definition keyboard.h:71
@ KEY_PAGEUP
Definition keyboard.h:70
@ KEY_LEFT
Left arrow key.
Definition keyboard.h:59
@ KEY_RIGHT
Right arrow key.
Definition keyboard.h:60
@ KEY_END
End key (move to end of line).
Definition keyboard.h:63
@ KEY_DOWN
Down arrow key.
Definition keyboard.h:58
@ KEY_HOME
Home key (move to start of line).
Definition keyboard.h:62
void ascii_otel_ui_usage(const char *screen, const char *event, uint64_t duration_ns)
Definition otel.c:434
void ui_controller_redraw(void)

References ascii_otel_ui_usage(), errno_notifications_dismiss(), KEY_DOWN, KEY_END, KEY_ESCAPE, KEY_HOME, KEY_LEFT, KEY_PAGEDOWN, KEY_PAGEUP, KEY_RIGHT, KEY_UP, and ui_controller_redraw().

Referenced by ui_input_read_key().

◆ ui_error_popup_minimum()

terminal_size_t ui_error_popup_minimum ( void )

Definition at line 83 of file error_popup.c.

83 {
84 return (terminal_size_t){.cols = 60, .rows = 14};
85}

Referenced by ui_controller_state(), and ui_error_popup_render().

◆ ui_error_popup_preserve()

void ui_error_popup_preserve ( int fd,
terminal_size_t size )

Preserve pending notifications using cached terminal dimensions before queue retirement. Callers own an interactive terminal and must prevent concurrent rendering. This formatter performs no console queries and does not wait for input.

Definition at line 395 of file error_popup.c.

395 {
397 return;
399 size_t count = errno_notifications_snapshot(entries, ARRAY_SIZE(entries), NULL);
400 if (!count)
401 return;
402 bool previous = errno_notifications_suppress(true);
403 frame_buffer_t *output = frame_buffer_create(0, 0);
404 if (output) {
405 bool colors = !GET_OPTION(strip_ansi) && terminal_should_color_output(fd, options_terminal_settings());
406 bool unicode = terminal_should_use_utf8(GET_OPTION(force_utf8));
407 int width = MIN(size.cols > 0 ? size.cols - 1 : 79, 100);
408 width = MAX(width, 8);
409 int body_width = width - 4;
410 size_t first = count > 4 ? count - 4 : 0;
411 frame_buffer_append(output, "\033[0m\033[?25h\r\n", 12);
412 if (first)
413 frame_buffer_printf(output, "%zu pending notifications; showing the latest 4.\n", count);
414 for (size_t i = first; i < count; ++i) {
416 const char *side = unicode ? "│" : "|";
417 ui_popup_rule(output, width, UI_POPUP_TOP, false, unicode, LOG_COLOR_RESET);
418 frame_buffer_append(output, "\n", 1);
419 ui_text_cell(cell, sizeof(cell), "ERROR", body_width, UI_ALIGN_LEFT);
420 frame_buffer_printf(output, "%s %s %s\n", side, colors ? colored_string(LOG_COLOR_ERROR, cell) : cell, side);
421 format_error_heading(code, sizeof(code), &entries[i]);
422 ui_text_cell(cell, sizeof(cell), code, body_width, UI_ALIGN_LEFT);
423 frame_buffer_printf(output, "%s %s %s\n", side, cell, side);
424 build_body(&entries[i], body_width, colors);
425 for (size_t line = 0; line < g_line_count; ++line) {
426 const char *start = g_wrapped + g_lines[line];
427 const char *end = strchr(start, '\n');
429 size_t length = end ? (size_t)(end - start) : strlen(start);
430 length = MIN(length, sizeof(line_text) - 1);
431 memcpy(line_text, start, length);
432 line_text[length] = '\0';
433 ui_text_cell(cell, sizeof(cell), line_text, body_width, UI_ALIGN_LEFT);
434 frame_buffer_printf(output, "%s %s%s %s\n", side, cell, colors ? "\033[0m" : "", side);
435 }
436 ui_popup_rule(output, width, UI_POPUP_BOTTOM, false, unicode, LOG_COLOR_RESET);
437 frame_buffer_append(output, "\n", 1);
438 }
439 if (frame_buffer_get_length(output) <= sizeof(g_final_output)) {
440 g_final_length = frame_buffer_get_length(output);
441 memcpy(g_final_output, frame_buffer_get_content(output), g_final_length);
442 g_final_fd = fd;
443 } else {
444 char message[ASCIICHAT_ERRNO_MESSAGE_MAX];
445 sanitize(message, sizeof(message), entries[count - 1].context_message);
446 int length = safe_snprintf(g_final_output, sizeof(g_final_output), "\nERROR\n%s (%d): %s\nDetails: %s\n",
447 asciichat_error_name(entries[count - 1].code), entries[count - 1].code,
448 asciichat_error_string(entries[count - 1].code), message);
449 g_final_length = length > 0 ? MIN((size_t)length, sizeof(g_final_output) - 1) : 0;
450 g_final_fd = fd;
451 }
452 }
453 if (output)
454 frame_buffer_destroy(output);
456}
bool errno_notifications_pending(void)
size_t errno_notifications_snapshot(asciichat_error_context_t *out, size_t capacity, uint64_t *dropped)
bool errno_notifications_suppress(bool suppress)
#define ASCIICHAT_ERRNO_MESSAGE_MAX
#define ASCIICHAT_ERRNO_HISTORY_SIZE
#define TUI_ERROR_POPUP_WRAPPED_BUFFER_SIZE
Definition error_popup.c:3
#define TUI_ERROR_POPUP_CELL_BUFFER_SIZE
Definition error_popup.c:13
#define TUI_ERROR_POPUP_CODE_BUFFER_SIZE
Definition error_popup.c:12
unsigned char colors[(512 *256 *2) *3]
Definition fft.c:22
unsigned int width
Definition fft.c:23
void frame_buffer_append(frame_buffer_t *buf, const char *str, size_t len)
Append raw bytes to the buffer.
void frame_buffer_destroy(frame_buffer_t *buf)
Destroy a frame buffer.
size_t frame_buffer_get_length(const frame_buffer_t *buf)
Get the current content length of the frame buffer.
const char * frame_buffer_get_content(const frame_buffer_t *buf)
Get a pointer to the buffer content.
frame_buffer_t * frame_buffer_create(int rows, int cols)
Create a new frame buffer.
void frame_buffer_printf(frame_buffer_t *buf, const char *fmt,...)
Printf-style append to the buffer.
struct frame_buffer frame_buffer_t
Opaque frame buffer handle.
#define MIN(a, b)
Return the minimum of two values.
Definition common.h:170
#define ARRAY_SIZE(arr)
Calculate the number of elements in an array.
Definition common.h:180
#define MAX(a, b)
Return the maximum of two values.
Definition common.h:175
@ LOG_COLOR_RESET
Definition log/log.h:155
@ LOG_COLOR_ERROR
Definition log/log.h:152
#define GET_OPTION(field)
Safely get a specific option field (lock-free read).
Definition options.h:1336
#define options_terminal_settings()
Definition options.h:1296
int safe_snprintf(char *buffer, size_t buffer_size, const char *format,...)
Platform-safe snprintf wrapper.
const char * colored_string(log_color_t color, const char *text)
Build a colored string for terminal output.
Definition string.c:284
asciichat_error_t ui_popup_rule(frame_buffer_t *out, int width, ui_popup_edge_t edge, bool double_border, bool unicode, log_color_t color)
Definition popup.c:12
@ UI_POPUP_BOTTOM
Definition popup.h:9
@ UI_POPUP_TOP
Definition popup.h:9
size_t ui_text_cell(char *out, size_t cap, const char *text, int width, ui_alignment_t align)
Definition text.c:48
@ UI_ALIGN_LEFT
Definition text.h:9

References ARRAY_SIZE, ASCIICHAT_ERRNO_HISTORY_SIZE, ASCIICHAT_ERRNO_MESSAGE_MAX, colored_string(), colors, errno_notifications_pending(), errno_notifications_snapshot(), errno_notifications_suppress(), frame_buffer_append(), frame_buffer_create(), frame_buffer_destroy(), frame_buffer_get_content(), frame_buffer_get_length(), frame_buffer_printf(), GET_OPTION, LOG_COLOR_ERROR, LOG_COLOR_RESET, MAX, MIN, options_terminal_settings, safe_snprintf(), TUI_ERROR_POPUP_CELL_BUFFER_SIZE, TUI_ERROR_POPUP_CODE_BUFFER_SIZE, TUI_ERROR_POPUP_WRAPPED_BUFFER_SIZE, UI_ALIGN_LEFT, UI_POPUP_BOTTOM, ui_popup_rule(), UI_POPUP_TOP, ui_text_cell(), and width.

Referenced by ui_controller_shutdown().

◆ ui_error_popup_render()

void ui_error_popup_render ( frame_buffer_t * out,
terminal_size_t size )

Definition at line 312 of file error_popup.c.

312 {
314 lock_state();
315 refresh_locked();
316 size_t count = g_count, selected = g_selected;
317 uint64_t displayed_latest = g_latest, dropped = g_dropped;
318 if (count)
319 error = g_entries[selected];
320 unlock_state();
321 if (!count)
322 return;
323 terminal_size_t minimum = ui_error_popup_minimum();
324 frame_buffer_append(out, "\033[0m\033[?25l", 10);
325 if (ui_too_small(size, minimum)) {
326 ui_too_small_render(out, size, minimum);
327 return;
328 }
329 lock_state();
330 g_displayed_latest = displayed_latest;
331 unlock_state();
332 bool colors = !GET_OPTION(strip_ansi) &&
333 terminal_should_color_output(frame_buffer_get_screen_output_fd(), options_terminal_settings());
334 int width = MIN(size.cols - 4, 100);
335 int body_width = width - 6;
336 if (g_cached_id != error.error_id || g_cached_width != body_width || g_cached_color != colors)
337 build_body(&error, body_width, colors);
338 size_t desired_rows = g_trace_start ? MIN(g_line_count, g_trace_start + 12) : g_line_count;
339 int body_rows = MIN(size.rows - 8, MIN(22, (int)desired_rows));
340 size_t fixed_rows = g_trace_start && g_trace_start < (size_t)body_rows ? g_trace_start : 0;
341 if (g_trace_start && !fixed_rows)
342 body_rows = MIN(body_rows, 12);
343 int height = body_rows + 6;
344 int top = (size.rows - height) / 2 + 1, left = (size.cols - width) / 2 + 1;
345 size_t scroll_rows = g_line_count - fixed_rows;
346 size_t page_rows = (size_t)body_rows - fixed_rows;
347 lock_state();
348 g_body_rows = scroll_rows;
349 g_page_rows = page_rows;
350 size_t maximum = scroll_rows > page_rows ? scroll_rows - page_rows : 0;
351 g_scroll = MIN(g_scroll, maximum);
352 size_t scroll = g_scroll;
353 unlock_state();
356 safe_snprintf(title, sizeof(title), "Error (%zu) %zu of %zu%s", count, selected + 1, count,
357 dropped ? " [older errors dropped]" : "");
359 ui_text_cell(heading, sizeof(heading), title, width - 4, UI_ALIGN_LEFT);
360 frame_buffer_printf(out, "\033[%d;%dH%s", top + 1, left + 2,
361 colors ? colored_string(LOG_COLOR_ERROR, heading) : heading);
363 format_error_heading(code, sizeof(code), &error);
364 ui_text_cell(cell, sizeof(cell), code, width - 4, UI_ALIGN_LEFT);
365 frame_buffer_printf(out, "\033[%d;%dH%s", top + 2, left + 2, cell);
366 for (int i = 0; i < body_rows; ++i) {
367 size_t index = (size_t)i < fixed_rows ? (size_t)i : (size_t)i + scroll;
368 if (index >= g_line_count)
369 break;
370 const char *start = g_wrapped + g_lines[index];
371 const char *end = strchr(start, '\n');
372 frame_buffer_printf(out, "\033[%d;%dH%.*s\033[0m", top + 4 + i, left + 2,
373 (int)(end ? end - start : (ptrdiff_t)strlen(start)), start);
374 }
375 ui_scrollbar_render(out, top + 4 + (int)fixed_rows, left + width - 3, (int)page_rows, scroll_rows, page_rows, scroll);
376 const char *orange = colors ? ui_text_color_prefix(LOG_COLOR_DEV) : "";
377 const char *reset = colors ? "\033[0m" : "";
378 frame_buffer_printf(out, "\033[%d;%dH%s?%s Help", top + height - 2, left + 2, orange, reset);
379 ui_button_t button = {.label = "Dismiss all", .shortcut = '\r'};
380 ui_buttons_render(out, top + height - 2, left + 10, width - 20, &button, 1, 0);
381}
void ui_buttons_render(frame_buffer_t *out, int row, int left, int width, const ui_button_t *b, size_t n, size_t selected)
Definition buttons.c:29
#define TUI_ERROR_POPUP_HEADING_BUFFER_SIZE
Definition error_popup.c:11
#define TUI_ERROR_POPUP_TITLE_BUFFER_SIZE
Definition error_popup.c:10
terminal_size_t ui_error_popup_minimum(void)
Definition error_popup.c:83
unsigned int height
Definition fft.c:23
int frame_buffer_get_screen_output_fd(void)
Get current output file descriptor for terminal screens.
@ LOG_COLOR_DEV
Definition log/log.h:148
asciichat_error_t ui_popup_frame(frame_buffer_t *out, int row, int col, int width, int height, log_color_t color)
Definition popup.c:28
static bool size_t index
Definition queries.h:8
static bool size_t gotel_query_t * out
Definition queries.h:8
void ui_scrollbar_render(frame_buffer_t *out, int row, int col, int height, size_t total, size_t visible, size_t offset)
Definition scrollbar.c:40
const char * ui_text_color_prefix(log_color_t color)
Definition text.c:18
void ui_too_small_render(frame_buffer_t *buffer, terminal_size_t actual, terminal_size_t minimum)
Definition too_small.c:38
bool ui_too_small(terminal_size_t actual, terminal_size_t minimum)
Definition too_small.c:10

References colored_string(), colors, asciichat_error_context_t::error_id, frame_buffer_append(), frame_buffer_get_screen_output_fd(), frame_buffer_printf(), GET_OPTION, height, index, LOG_COLOR_DEV, LOG_COLOR_ERROR, LOG_COLOR_RESET, MIN, options_terminal_settings, out, safe_snprintf(), TUI_ERROR_POPUP_CELL_BUFFER_SIZE, TUI_ERROR_POPUP_CODE_BUFFER_SIZE, TUI_ERROR_POPUP_HEADING_BUFFER_SIZE, TUI_ERROR_POPUP_TITLE_BUFFER_SIZE, UI_ALIGN_LEFT, ui_buttons_render(), ui_error_popup_minimum(), ui_popup_frame(), ui_scrollbar_render(), ui_text_cell(), ui_text_color_prefix(), ui_too_small(), ui_too_small_render(), and width.

◆ ui_error_popup_reset()

void ui_error_popup_reset ( void )

Definition at line 383 of file error_popup.c.

383 {
384 lock_state();
385 g_count = g_selected = g_scroll = 0;
386 g_latest = g_displayed_latest = g_dropped = 0;
387 unlock_state();
388 g_cached_id = 0;
389}

Referenced by ui_controller_shutdown().

◆ ui_error_popup_revision()

uint64_t ui_error_popup_revision ( void )

Definition at line 75 of file error_popup.c.

75 {
76 lock_state();
77 refresh_locked();
78 uint64_t revision = g_latest;
79 unlock_state();
80 return revision;
81}

◆ ui_error_popup_visible()

bool ui_error_popup_visible ( void )

Error notifications are an overlay, independent of the selected application screen.

Definition at line 71 of file error_popup.c.

71 {
73}

References errno_notifications_pending().

Referenced by ui_controller_current_screen(), ui_input_read_key(), and update_banner_show_prompt().