ascii-chat 0.11.33
Video chat in your terminal
Loading...
Searching...
No Matches
terminal_screen.h File Reference

Reusable "fixed header + scrolling logs" terminal screen abstraction. More...

Go to the source code of this file.

Data Structures

struct  terminal_screen_config_t
 Configuration for terminal screen rendering. More...
 

Typedefs

typedef struct session_log_buffer session_log_buffer_t
 
typedef void(* terminal_screen_header_fn) (frame_buffer_t *buf, terminal_size_t term_size, void *user_data)
 Callback to render the fixed header portion of the screen.
 

Functions

void terminal_screen_render (const terminal_screen_config_t *config)
 Render a terminal screen with fixed header and scrolling logs.
 
void terminal_screen_cleanup (void)
 Clean up terminal screen resources.
 
session_log_buffer_t * terminal_screen_log_init (void)
 Initialize session log buffer for terminal screens.
 
void terminal_screen_log_destroy (void)
 Standard log cleanup for terminal screens.
 
void terminal_screen_log_clear (void)
 Clear buffered logs for terminal screens.
 
session_log_buffer_t * terminal_screen_get_log_buffer (void)
 Get the current session log buffer.
 
void terminal_screen_set_output_fd (int fd)
 Set output file descriptor for terminal screens (splash/status)
 

Detailed Description

Reusable "fixed header + scrolling logs" terminal screen abstraction.

Provides a common pattern for rendering terminal screens with:

  • Fixed header area (caller-defined via callback)
  • Scrolling log feed below header (automatically managed)
  • Terminal size caching to avoid error log spam
  • ANSI-aware line wrapping using display_width()
  • Latest log at bottom (standard terminal behavior)

Definition in file terminal_screen.h.

Typedef Documentation

◆ session_log_buffer_t

Definition at line 21 of file terminal_screen.h.

◆ terminal_screen_header_fn

typedef void(* terminal_screen_header_fn) (frame_buffer_t *buf, terminal_size_t term_size, void *user_data)

Callback to render the fixed header portion of the screen.

Parameters
bufFrame buffer to write header content into (via frame_buffer_printf, etc.)
term_sizeCurrent terminal dimensions (cached, refreshed every 1 second)
user_dataCaller-provided context data

The callback should:

  • Append exactly the number of lines specified in terminal_screen_config_t.fixed_header_lines
  • Use display_width() to ensure lines don't exceed term_size.cols
  • Write to buf parameter (frame_buffer_printf, frame_buffer_append)
  • NOT clear the screen (terminal_screen_render does that)
  • NOT print the final newline if it would be line N+1 (causes scroll)

Definition at line 37 of file terminal_screen.h.

Function Documentation

◆ terminal_screen_cleanup()

void terminal_screen_cleanup ( void  )

Clean up terminal screen resources.

Destroys the internal static frame buffer allocated by terminal_screen_render(). Call at program exit or when terminal screen rendering is no longer needed.

Definition at line 466 of file terminal_screen.c.

466 {
467 if (g_frame_buf) {
468 frame_buffer_destroy(g_frame_buf);
469 g_frame_buf = NULL;
470 }
471}
void frame_buffer_destroy(frame_buffer_t *buf)
Destroy a frame buffer.

References frame_buffer_destroy().

Referenced by asciichat_shared_destroy().

◆ terminal_screen_get_log_buffer()

session_log_buffer_t * terminal_screen_get_log_buffer ( void  )

Get the current session log buffer.

Returns the log buffer owned by this module, or NULL if not initialized. Used by splash/status screens to register with the logger.

Returns
Pointer to log buffer, or NULL

Definition at line 495 of file terminal_screen.c.

495 {
496 return g_session_log_buffer;
497}

◆ terminal_screen_log_clear()

void terminal_screen_log_clear ( void  )

Clear buffered logs for terminal screens.

Clears all previously captured log entries from the buffer. Useful when transitioning between screens to start fresh.

Definition at line 489 of file terminal_screen.c.

489 {
490 if (g_session_log_buffer) {
491 session_log_buffer_clear(g_session_log_buffer);
492 }
493}
void session_log_buffer_clear(session_log_buffer_t *buf)
Clear all log entries from buffer.

References session_log_buffer_clear().

Referenced by splash_log_clear(), ui_mdns_log_clear(), and ui_status_log_clear().

◆ terminal_screen_log_destroy()

void terminal_screen_log_destroy ( void  )

Standard log cleanup for terminal screens.

Destroys the session log buffer after screens are done rendering.

Definition at line 482 of file terminal_screen.c.

482 {
483 if (g_session_log_buffer) {
484 session_log_buffer_destroy(g_session_log_buffer);
485 g_session_log_buffer = NULL;
486 }
487}
void session_log_buffer_destroy(session_log_buffer_t *buf)
Cleanup session log buffer instance.

References session_log_buffer_destroy().

Referenced by splash_log_destroy(), ui_mdns_log_destroy(), and ui_status_log_destroy().

◆ terminal_screen_log_init()

session_log_buffer_t * terminal_screen_log_init ( void  )

Initialize session log buffer for terminal screens.

Creates a new session log buffer owned by this module. Splash and status screens use this buffer to display logs.

Returns
Pointer to created buffer, or NULL on failure

Definition at line 473 of file terminal_screen.c.

473 {
474 if (g_session_log_buffer) {
475 return g_session_log_buffer; // Already initialized
476 }
477
478 g_session_log_buffer = session_log_buffer_create();
479 return g_session_log_buffer;
480}
session_log_buffer_t * session_log_buffer_create(void)
Create a new session log buffer instance.

References session_log_buffer_create().

Referenced by splash_log_init(), ui_mdns_log_init(), and ui_status_log_init().

◆ terminal_screen_render()

void terminal_screen_render ( const terminal_screen_config_t *  config)

Render a terminal screen with fixed header and scrolling logs.

Renders a screen following the pattern:

  1. Clear screen and move cursor to home (both stdout and stderr)
  2. Call render_header() callback to draw fixed header
  3. Calculate log area: rows - fixed_header_lines - 1 (prevent scroll)
  4. Fetch recent logs from session_log_buffer
  5. Calculate which logs fit (working backwards, accounting for wrapping)
  6. Display logs chronologically (oldest to newest, latest at bottom)
  7. Fill remaining lines to prevent terminal scroll
  8. Flush stdout
Parameters
configScreen configuration (header callback, line count, etc.)

Terminal size is cached internally with 1-second refresh interval to avoid flooding error logs if terminal size checks fail repeatedly.

Definition at line 107 of file terminal_screen.c.

107 {
108 // Validate config
109 if (!config || !config->render_header) {
110 return;
111 }
112
113 // Track startup timing (first 500ms)
114 static bool first_render = true;
115 if (first_render) {
116 g_render_start_time_ns = platform_get_monotonic_time_us() * 1000;
117 first_render = false;
118 }
119
121 uint64_t elapsed_ms = (now_ns - g_render_start_time_ns) / 1000000;
122
123 // Ensure cursor is visible for log-only UI (splash, status screens)
124 (void)terminal_cursor_show();
125
126 // Update terminal size (cached with 1-second refresh interval)
127 // Always check on first call (when still at default 24x80) to get correct dimensions immediately
129 bool should_check = (g_cached_term_size.rows == 24 && g_cached_term_size.cols == 80) ||
130 (now_us - g_last_term_size_check_us >= TERM_SIZE_CHECK_INTERVAL_US);
131
132 if (should_check) {
133 terminal_size_t new_size = {0};
134
135 // PRIORITY 1: COLUMNS and ROWS environment variables (most reliable, user-controlled)
136 const char *cols_env = SAFE_GETENV("COLUMNS");
137 const char *rows_env = SAFE_GETENV("ROWS");
138 if (cols_env && rows_env) {
139 char *endptr;
140 errno = 0;
141 long cols_val = strtol(cols_env, &endptr, 10);
142 if (*endptr == '\0' && errno == 0 && cols_val > 0 && cols_val <= INT_MAX) {
143 int cols = (int)cols_val;
144 errno = 0;
145 long rows_val = strtol(rows_env, &endptr, 10);
146 if (*endptr == '\0' && errno == 0 && rows_val > 0 && rows_val <= INT_MAX) {
147 int rows = (int)rows_val;
148 new_size.cols = cols;
149 new_size.rows = rows;
150 } else {
151 log_error("terminal_screen_render: Invalid ROWS value: %s", rows_env);
152 }
153 } else {
154 log_error("terminal_screen_render: Invalid COLUMNS value: %s", cols_env);
155 }
156 }
157
158 // PRIORITY 2: Options-provided width/height (explicit user settings)
159 if (new_size.cols == 0 || new_size.rows == 0) {
160 const options_t *opts = options_get();
161 if (opts && opts->width > 0 && opts->height > 0) {
162 new_size.cols = opts->width;
163 new_size.rows = opts->height;
164 }
165 }
166
167 // PRIORITY 3: Terminal auto-detection
168 if (new_size.cols == 0 || new_size.rows == 0) {
169 if (terminal_get_size(&new_size) != ASCIICHAT_OK) {
170 // If terminal detection fails, use defaults
171 new_size.cols = 80;
172 new_size.rows = 24;
173 }
174 }
175
176 if (new_size.cols > 0 && new_size.rows > 0) {
177 g_cached_term_size = new_size;
178 }
179 g_last_term_size_check_us = now_us;
180 }
181
182 bool grep_entering = log_search_is_entering();
183
184 // When transitioning out of grep mode, clear the log cache so all logs are redrawn
185 // (grep mode may have shown filtered logs, need to refresh for normal view)
186 static bool last_grep_state = false;
187 if (last_grep_state && !grep_entering) {
188 terminal_screen_clear_cache();
189 }
190
191 // Also clear cache when pattern changes while still in grep mode (e.g., user backspaces to empty)
192 if (grep_entering && log_search_needs_rerender()) {
193 terminal_screen_clear_cache();
194 }
195
196 last_grep_state = grep_entering;
197
198 // Allocate or reuse frame buffer (module-level static to avoid malloc per frame)
199 if (!g_frame_buf) {
200 g_frame_buf = frame_buffer_create(g_cached_term_size.rows, g_cached_term_size.cols);
201 if (!g_frame_buf) {
202 return; // Allocation failed
203 }
204 }
205
206 frame_buffer_reset(g_frame_buf);
207
208 if (!grep_entering) {
209 // Redraw in place; frame_buffer_flush erases each rendered line without
210 // exposing a full-screen clear between frames.
211 frame_buffer_cursor_home(g_frame_buf);
212 } else {
213 // Grep mode: overwrite in place, never clear whole screen
214 frame_buffer_cursor_home(g_frame_buf);
215 }
216
217 // Render fixed header via callback (writes into frame buffer)
218 config->render_header(g_frame_buf, g_cached_term_size, config->user_data);
219
220 // If logs are disabled, flush and return
221 if (!config->show_logs) {
222 frame_buffer_flush(g_frame_buf);
223 return;
224 }
225
226 // Measure actual header height by pre-rendering and counting display lines
227 int actual_header_height = config->fixed_header_lines;
228
229 if (config->render_header) {
230 // Pre-render header to a temporary buffer to measure its display height
231 frame_buffer_t *temp_buf = frame_buffer_create(config->fixed_header_lines + 10, g_cached_term_size.cols);
232 if (temp_buf) {
233 config->render_header(temp_buf, g_cached_term_size, config->user_data);
234
235 // Measure display height of the rendered header
236 // The buffer contains ANSI codes + text. We count newlines and account for wrapped lines.
237 int measured_height = 0;
238 const char *content = frame_buffer_get_content(temp_buf);
239 size_t buf_len = frame_buffer_get_length(temp_buf);
240 const char *buf_end = content + buf_len;
241 const char *line_start = content;
242
243 while (content < buf_end) {
244 if (*content == '\n') {
245 // Found end of line - measure this line's display height
246 size_t line_len = content - line_start;
247 char line_buf[1024];
248 if (line_len < sizeof(line_buf)) {
249 memcpy(line_buf, line_start, line_len);
250 line_buf[line_len] = '\0';
251
252 int line_height = display_height(line_buf, g_cached_term_size.cols);
253 if (line_height <= 0)
254 line_height = 1;
255 measured_height += line_height;
256 }
257 line_start = content + 1;
258 }
259 content++;
260 }
261
262 if (measured_height > 0) {
263 actual_header_height = measured_height;
264 }
265 frame_buffer_destroy(temp_buf);
266 }
267 }
268
269 // Calculate log area: total rows - actual header height - 1 (prevent scroll)
270 // When grep search is open, subtract additional row to prevent header bump
271 int log_area_rows = g_cached_term_size.rows - actual_header_height - (grep_entering ? 2 : 1);
272
273 if (log_area_rows <= 0) {
274 // Terminal too small for logs, flush header and return
275 frame_buffer_flush(g_frame_buf);
276 if (grep_entering) {
277 log_search_render_input_line(g_cached_term_size.cols);
278 }
279 return;
280 }
281
282 // When grep input is active, reserve 1 row for the grep input line at bottom.
283 // Subtract 1 from log_area_rows to prevent logs from overlapping the grep input.
284 int renderable_log_rows = grep_entering ? (log_area_rows - 1) : log_area_rows;
285
286 // Fetch and filter logs
287 session_log_entry_t *log_entries = NULL;
288 size_t log_count = 0;
289
290 if (log_search_is_active()) {
291 asciichat_error_t result = log_search_gather_and_filter_logs(&log_entries, &log_count);
292 if (result != ASCIICHAT_OK || !log_entries) {
294 if (log_entries) {
295 log_count = session_log_buffer_get_recent(g_session_log_buffer, log_entries, SESSION_LOG_BUFFER_SIZE);
296 }
297 }
298 } else {
299 // Get logs from in-memory buffer
300 session_log_entry_t *buffer_entries =
302 if (buffer_entries) {
303 size_t buffer_count =
304 session_log_buffer_get_recent(g_session_log_buffer, buffer_entries, SESSION_LOG_BUFFER_SIZE);
305 log_entries = buffer_entries;
306 log_count = buffer_count;
307 }
308 }
309
310 // Display logs - most recent at bottom, oldest scrolled off top.
311 // Calculate a stable window: show logs that fit in available space, newest last.
312 // This ensures smooth scrolling as new logs arrive (no jumping viewport).
313 // Use renderable_log_rows when in grep mode to account for grep input line.
314 // CRITICAL: account for multi-line logs via display_height() in pre-selection.
315 // Without this, logs overflow and push the header off screen.
316 int first_log_to_display = log_count; // Start past the end (no logs selected)
317 int total_lines_used = 0;
318 int available_rows = grep_entering ? renderable_log_rows : log_area_rows;
319
320 // Work backwards from newest to oldest log, selecting which fit
321 for (int i = (int)log_count - 1; i >= 0; i--) {
322 int lines_for_msg = display_height(log_entries[i].message, g_cached_term_size.cols);
323 if (lines_for_msg <= 0) {
324 lines_for_msg = 1;
325 }
326 // Check if adding this log would exceed available space
327 if (total_lines_used + lines_for_msg <= available_rows) {
328 total_lines_used += lines_for_msg;
329 first_log_to_display = i; // This is the first (oldest) log we'll display
330 }
331 // Continue checking older logs - they might be shorter and still fit
332 }
333
334 // If no logs fit, show nothing (just padding)
335 if (first_log_to_display == (int)log_count) {
336 first_log_to_display = log_count; // Will result in 0 logs to display
337 }
338
339 int logs_to_display = log_count - first_log_to_display;
340
341 // Log detailed info about what logs are being displayed
342 int logs_displayed_count = logs_to_display;
343 if (elapsed_ms < 500) {
344 log_dev_every(1 * NS_PER_SEC_INT, "[STARTUP_FRAME] t=%llu log_count=%zu first=%d display=%d area=%d",
345 (unsigned long long)elapsed_ms, log_count, first_log_to_display, logs_displayed_count, log_area_rows);
346 } else {
348 "[HEIGHT_CALC] log_count=%zu first_log_to_display=%d logs_displayed=%d "
349 "renderable_log_rows=%d",
350 log_count, first_log_to_display, logs_displayed_count, renderable_log_rows);
351 }
352
353 if (!grep_entering) {
354 // Normal mode: accumulate everything (header + logs + blank lines) into frame buffer,
355 // then flush atomically. This prevents real-time logs from appearing after the frame,
356 // which would cause the display to scroll and push the header up.
357
358 // Output logs to frame buffer, counting actual display lines (accounting for wrapping)
359 int terminal_lines_used = 0;
360 for (int i = first_log_to_display; i < (int)log_count && terminal_lines_used < log_area_rows; i++) {
361 const char *msg = log_entries[i].message;
362
363 // Calculate how many display lines this message will consume when wrapped
364 // Uses display_height() which handles ANSI codes and UTF-8 properly
365 int lines_for_this_msg = display_height(msg, g_cached_term_size.cols);
366 if (lines_for_this_msg <= 0) {
367 lines_for_this_msg = 1;
368 }
369
370 // Only output if it fits in remaining space
371 if (terminal_lines_used + lines_for_this_msg <= log_area_rows) {
372 frame_buffer_printf(g_frame_buf, "%s\n", msg);
373 terminal_lines_used += lines_for_this_msg;
374 }
375 }
376
377 // Pad remaining log area with blank lines to maintain fixed frame height.
378 // This ensures every frame has exactly the same height on screen,
379 // preventing flicker caused by dynamic frame height changes.
380 while (terminal_lines_used < log_area_rows) {
381 frame_buffer_printf(g_frame_buf, "\n");
382 terminal_lines_used++;
383 }
384
385 // Flush entire frame (header + logs + blank lines) in one atomic write
386 frame_buffer_flush(g_frame_buf);
387 } else {
388 // Grep mode: render logs with frame buffer (same as normal mode)
389 // Just apply grep highlighting to visible logs
390
391 int terminal_lines_used = 0;
392 for (int i = first_log_to_display; i < (int)log_count && terminal_lines_used < log_area_rows; i++) {
393 const char *original_msg = log_entries[i].message;
394 const char *msg = original_msg;
395
396 // Strip ANSI codes first to match against plain text
397 char plain_text[SESSION_LOG_LINE_MAX] = {0};
398 strip_ansi_codes(original_msg, plain_text, sizeof(plain_text));
399
400 // Apply highlighting if match found in plain text
401 size_t match_start = 0, match_len = 0;
402 if (log_search_get_match_info(plain_text, &match_start, &match_len) && match_len > 0) {
403 // Validate match is within bounds
404 size_t plain_len = strlen(plain_text);
405 if (match_start < plain_len && (match_start + match_len) <= plain_len) {
406 const char *highlighted = grep_highlight_colored(original_msg, plain_text, match_start, match_len);
407 if (highlighted && highlighted[0] != '\0') {
408 msg = highlighted;
409 }
410 }
411 }
412
413 int msg_display_width = display_width(msg);
414 if (msg_display_width < 0) {
415 msg_display_width = (int)strlen(msg);
416 }
417 int lines_for_this_msg = 1;
418 if (g_cached_term_size.cols > 0 && msg_display_width > g_cached_term_size.cols) {
419 lines_for_this_msg = (msg_display_width + g_cached_term_size.cols - 1) / g_cached_term_size.cols;
420 }
421
422 if (terminal_lines_used + lines_for_this_msg <= log_area_rows) {
423 frame_buffer_printf(g_frame_buf, "%s\n", msg);
424 terminal_lines_used += lines_for_this_msg;
425 }
426 }
427
428 // Pad remaining log area with blank lines
429 while (terminal_lines_used < log_area_rows) {
430 frame_buffer_printf(g_frame_buf, "\n");
431 terminal_lines_used++;
432 }
433
434 // Flush frame buffer before rendering grep UI
435 frame_buffer_flush(g_frame_buf);
436
437 // Grep input line UI (position cursor at bottom and display "/" prompt with pattern)
438 // Get the search pattern under mutex protection
439 mutex_t *grep_mutex = log_search_get_mutex();
440 if (grep_mutex && g_cached_term_size.rows > 0) {
441 mutex_lock(grep_mutex);
442 int pattern_len = log_search_get_input_len();
443 const char *pattern = log_search_get_input_buffer();
444 int cursor_pos = log_search_get_cursor_position();
445
446 // Render grep input line at bottom of screen
447 printf("\x1b[%d;1H/", g_cached_term_size.rows);
448 if (pattern_len > 0 && pattern) {
449 printf("%.*s", pattern_len, pattern);
450 }
451
452 // Position cursor at current edit position
453 int cursor_offset = pattern_len - cursor_pos;
454 if (cursor_offset > 0) {
455 printf("\x1b[%dD", cursor_offset);
456 }
457 fflush(stdout);
458
459 mutex_unlock(grep_mutex);
460 }
461 }
462
463 SAFE_FREE(log_entries);
464}
void frame_buffer_cursor_home(frame_buffer_t *buf)
Append cursor home escape code (\033[H)
void frame_buffer_reset(frame_buffer_t *buf)
Clear buffer contents while keeping allocation.
void frame_buffer_flush(frame_buffer_t *buf)
Flush the entire buffer to stdout in one atomic write.
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.
const char * grep_highlight_colored(const char *colored_text, const char *plain_text, size_t match_start, size_t match_len)
Highlight matches in colored text while preserving original colors.
Definition grep.c:755
#define SAFE_FREE(ptr)
Definition common.h:376
#define SAFE_MALLOC(size, cast)
Definition common.h:264
#define SAFE_GETENV(name)
Definition common.h:434
unsigned long long uint64_t
Definition common.h:59
asciichat_error_t
Error and exit codes - unified status values (0-255)
Definition error_codes.h:49
@ ASCIICHAT_OK
Definition error_codes.h:51
#define log_error(...)
Log an ERROR message.
Definition log/log.h:587
#define NS_PER_SEC_INT
Definition time.h:157
const options_t * options_get(void)
Get current options (lock-free read)
Definition rcu.c:496
asciichat_error_t terminal_get_size(terminal_size_t *size)
Get terminal size.
#define mutex_lock(mutex)
Lock a mutex (with debug tracking in debug builds)
uint64_t platform_get_monotonic_time_us(void)
Get monotonic time in microseconds.
int errno
#define mutex_unlock(mutex)
Unlock a mutex (with debug tracking in debug builds)
asciichat_error_t terminal_cursor_show(void)
Show terminal cursor.
int display_width(const char *text)
Calculate the visible display width of text with ANSI escape codes.
int display_height(const char *text, int terminal_width)
Calculate how many display lines text will consume when wrapped.
#define log_debug_every(interval_us, fmt,...)
Rate-limited DEBUG logging.
Definition log/log.h:702
#define log_dev_every(interval_us, fmt,...)
Rate-limited DEV logging.
Definition log/log.h:699
size_t session_log_buffer_get_recent(session_log_buffer_t *buf, session_log_entry_t *out_entries, size_t max_count)
Get recent log entries from buffer.
void * log_search_get_mutex(void)
Get the mutex protecting grep state.
Definition search.c:936
bool log_search_needs_rerender(void)
Check if screen needs immediate re-render.
Definition search.c:884
bool log_search_is_entering(void)
Check if currently in input mode (typing pattern)
Definition search.c:385
int log_search_get_input_len(void)
Get current input buffer length (must hold mutex)
Definition search.c:940
const char * log_search_get_input_buffer(void)
Get current input buffer content (must hold mutex)
Definition search.c:948
bool log_search_is_active(void)
Check if filtering is active.
Definition search.c:390
bool log_search_get_match_info(const char *message, size_t *out_match_start, size_t *out_match_len)
Get match info for highlighting a log message.
Definition search.c:729
int log_search_get_cursor_position(void)
Get current cursor position in input buffer (must hold mutex)
Definition search.c:944
void log_search_render_input_line(int width)
Render grep input line at bottom of screen.
Definition search.c:691
asciichat_error_t log_search_gather_and_filter_logs(session_log_entry_t **out_entries, size_t *out_count)
Gather and filter logs for display.
Definition search.c:530
Frame buffer structure.
Mutex type (POSIX: pthread_mutex_t with debug tracking)
Consolidated options structure.
int height
Terminal height in characters (int for OPTION_TYPE_INT compat)
int width
Terminal width in characters (int for OPTION_TYPE_INT compat)
Single log entry with sequence number for ordering.
char message[1024]
Formatted log message (may include ANSI colors)
terminal_screen_header_fn render_header
Callback to draw header content.
int fixed_header_lines
How many lines the header takes (e.g., 4 for status, 8 for splash)
bool show_logs
Whether to show log feed below header.
void * user_data
Passed to render_header callback.
Terminal size structure.
Definition terminal.h:163
int cols
Number of columns (width) in terminal.
Definition terminal.h:165
int rows
Number of rows (height) in terminal.
Definition terminal.h:164
#define TERM_SIZE_CHECK_INTERVAL_US

References ASCIICHAT_OK, terminal_size_t::cols, display_height(), display_width(), errno, terminal_screen_config_t::fixed_header_lines, frame_buffer_create(), frame_buffer_cursor_home(), frame_buffer_destroy(), frame_buffer_flush(), frame_buffer_get_content(), frame_buffer_get_length(), frame_buffer_printf(), frame_buffer_reset(), grep_highlight_colored(), options_state::height, log_debug_every, log_dev_every, log_error, log_search_gather_and_filter_logs(), log_search_get_cursor_position(), log_search_get_input_buffer(), log_search_get_input_len(), log_search_get_match_info(), log_search_get_mutex(), log_search_is_active(), log_search_is_entering(), log_search_needs_rerender(), log_search_render_input_line(), session_log_entry_t::message, mutex_lock, mutex_unlock, NS_PER_SEC_INT, options_get(), platform_get_monotonic_time_us(), terminal_screen_config_t::render_header, terminal_size_t::rows, SAFE_FREE, SAFE_GETENV, SAFE_MALLOC, session_log_buffer_get_recent(), SESSION_LOG_BUFFER_SIZE, SESSION_LOG_LINE_MAX, terminal_screen_config_t::show_logs, TERM_SIZE_CHECK_INTERVAL_US, terminal_cursor_show(), terminal_get_size(), terminal_screen_config_t::user_data, and options_state::width.

Referenced by ui_status_display(), and ui_status_display_interactive().

◆ terminal_screen_set_output_fd()

void terminal_screen_set_output_fd ( int  fd)

Set output file descriptor for terminal screens (splash/status)

Parameters
fdFile descriptor (STDOUT_FILENO for TTY, STDERR_FILENO for piped)

Configures where splash and status screens write their output. Should be called before terminal_screen_render() to control output destination.

Definition at line 499 of file terminal_screen.c.

499 {
501}
void frame_buffer_set_screen_output_fd(int fd)
Set output file descriptor for terminal screen (splash/status) rendering.

References frame_buffer_set_screen_output_fd().

Referenced by splash_intro_start(), and ui_status_display().