ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
text.c
Go to the documentation of this file.
1
2/* Storage capacities in elements; text buffers include the terminating NUL. */
3#define UI_TEXT_NUMBER_BUFFER_SIZE 96
4#define UI_TEXT_STYLED_BUFFER_SIZE 4096
5
6/* Existing buffer budgets in bytes, including NUL for text storage. */
7#define UI_TEXT_COLOR_BUFFER_SIZE 128
8
13#include <ctype.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17
19 static _Thread_local char buffers[LOG_COLOR_WHITE + 1][UI_TEXT_COLOR_BUFFER_SIZE];
20 if (color < LOG_COLOR_DEV || color > LOG_COLOR_WHITE) {
21 SET_ERRNO(ERROR_INVALID_PARAM, "Invalid UI text color");
22 return "";
23 }
24 char *out = buffers[color];
25 const char *styled = colored_string(color, "!");
26 const char *marker = strchr(styled, '!');
27 size_t length = marker ? (size_t)(marker - styled) : 0;
28 if (length >= sizeof(buffers[0]))
29 length = sizeof(buffers[0]) - 1;
30 memcpy(out, styled, length);
31 out[length] = '\0';
32 return out;
33}
34
35static void append(char *out, size_t cap, size_t *used, const char *text, size_t length) {
36 if (!cap || *used >= cap - 1)
37 return;
38 size_t room = cap - 1 - *used;
39 if (length > room) {
40 SET_ERRNO(ERROR_BUFFER_OVERFLOW, "UI text buffer needs %zu additional bytes", length - room);
41 return;
42 }
43 memcpy(out + *used, text, length);
44 *used += length;
45 out[*used] = '\0';
46}
47
48size_t ui_text_cell(char *out, size_t cap, const char *text, int width, ui_alignment_t align) {
49 if (!out || !cap) {
50 SET_ERRNO(ERROR_INVALID_PARAM, "UI text requires output storage");
51 return 0;
52 }
53 out[0] = '\0';
54 if (width <= 0)
55 return 0;
56 if (!text)
57 text = "";
58 int columns = 0;
59 const char *end = text;
60 while (*end) {
61 if (end[0] == '\033' && end[1] == '[') {
62 const char *escape = end + 2;
63 while (*escape && !(*escape >= '@' && *escape <= '~'))
64 ++escape;
65 if (!*escape)
66 break;
67 end = escape + 1;
68 continue;
69 }
70 if ((unsigned char)*end < 32)
71 break;
72 int bytes = utf8_next_char_bytes(end, strlen(end));
73 if (bytes <= 0)
74 break;
75 int n = utf8_display_width_n(end, (size_t)bytes);
76 if (n < 0 || columns + n > width)
77 break;
78 columns += n;
79 end += bytes;
80 }
81 size_t used = 0;
82 int pad = width - columns;
83 int left = align == UI_ALIGN_RIGHT ? pad : align == UI_ALIGN_CENTER ? pad / 2 : 0;
84 for (int i = 0; i < left; ++i)
85 append(out, cap, &used, " ", 1);
86 append(out, cap, &used, text, (size_t)(end - text));
87 // A clipped styled cell must not bleed into the following column.
88 if (memchr(text, '\033', (size_t)(end - text)))
89 append(out, cap, &used, "\033[0m", 4);
90 for (int i = left; i < pad; ++i)
91 append(out, cap, &used, " ", 1);
92 return used;
93}
94
95void ui_text_values_style(char *out, size_t cap, const char *text, log_color_t zero_color) {
96 if (!out || !cap) {
97 SET_ERRNO(ERROR_INVALID_PARAM, "UI text requires output storage");
98 return;
99 }
100 size_t used = 0;
101 out[0] = '\0';
102 if (!text)
103 return;
104 for (const char *p = text; *p;) {
105 if (p[0] == '\033' && p[1] == '[') {
106 const char *end = p + 2;
107 while (*end && !(*end >= '@' && *end <= '~'))
108 ++end;
109 if (*end)
110 ++end;
111 append(out, cap, &used, p, (size_t)(end - p));
112 p = end;
113 } else if (isdigit((unsigned char)*p)) {
114 char *end;
115 double value = p[0] == '0' && p[1] == 'x' ? (double)strtoull(p, &end, 16) : strtod(p, &end);
116 char number[UI_TEXT_NUMBER_BUFFER_SIZE];
117 size_t length = (size_t)(end - p);
118 if (length >= sizeof(number))
119 length = sizeof(number) - 1;
120 memcpy(number, p, length);
121 number[length] = '\0';
122 const char *styled = colored_string(value == 0 ? zero_color : LOG_COLOR_FATAL, number);
123 append(out, cap, &used, styled, strlen(styled));
124 p = end;
125 } else if ((p == text || !isalnum((unsigned char)p[-1])) &&
126 ((!strncmp(p, "enabled", 7) && !isalnum((unsigned char)p[7])) ||
127 (!strncmp(p, "disabled", 8) && !isalnum((unsigned char)p[8])))) {
128 bool enabled = *p == 'e';
129 const char *styled = colored_string(enabled ? LOG_COLOR_INFO : LOG_COLOR_ERROR, enabled ? "enabled" : "disabled");
130 append(out, cap, &used, styled, strlen(styled));
131 p += enabled ? 7 : 8;
132 } else {
133 int bytes = utf8_next_char_bytes(p, strlen(p));
134 if (bytes <= 0)
135 break;
136 append(out, cap, &used, p, (size_t)bytes);
137 p += bytes;
138 }
139 }
140}
141
142void ui_text_values(char *out, size_t cap, const char *text) {
144}
145
146void ui_text_render_values(frame_buffer_t *out, const char *text) {
147 char styled[UI_TEXT_STYLED_BUFFER_SIZE];
148 ui_text_values_style(styled, sizeof(styled), text, LOG_COLOR_FATAL);
149 frame_buffer_append(out, styled, strlen(styled));
150}
#define SET_ERRNO(code,...)
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.
struct frame_buffer frame_buffer_t
Opaque frame buffer handle.
bool enabled
Is filtering active?
Definition grep.c:62
@ ERROR_INVALID_PARAM
@ ERROR_BUFFER_OVERFLOW
log_color_t
Color enum for logging - indexes into color arrays.
Definition log/log.h:147
@ LOG_COLOR_FATAL
Definition log/log.h:153
@ LOG_COLOR_ERROR
Definition log/log.h:152
@ LOG_COLOR_INFO
Definition log/log.h:150
@ LOG_COLOR_WHITE
Definition log/log.h:156
int utf8_display_width_n(const char *str, size_t max_bytes)
Calculate terminal display width of a UTF-8 string up to byte limit.
Definition utf8.c:102
const char * colored_string(log_color_t color, const char *text)
Build a colored string for terminal output.
Definition string.c:284
int utf8_next_char_bytes(const char *str, size_t max_bytes)
Get byte length of next UTF-8 character.
Definition utf8.c:177
🖥️ Display Width and Terminal Centering Utilities
static bool size_t gotel_query_t * out
Definition queries.h:8
🔤 String Manipulation and Shell Escaping Utilities
#define UI_TEXT_STYLED_BUFFER_SIZE
Definition text.c:4
const char * ui_text_color_prefix(log_color_t color)
Definition text.c:18
#define UI_TEXT_COLOR_BUFFER_SIZE
Definition text.c:7
void ui_text_values_style(char *out, size_t cap, const char *text, log_color_t zero_color)
Definition text.c:95
size_t ui_text_cell(char *out, size_t cap, const char *text, int width, ui_alignment_t align)
Definition text.c:48
void ui_text_values(char *out, size_t cap, const char *text)
Definition text.c:142
#define UI_TEXT_NUMBER_BUFFER_SIZE
Definition text.c:3
void ui_text_render_values(frame_buffer_t *out, const char *text)
Definition text.c:146
ui_alignment_t
Definition text.h:9
@ UI_ALIGN_RIGHT
Definition text.h:9
@ UI_ALIGN_CENTER
Definition text.h:9
🔤 UTF-8 Encoding and Decoding Utilities