diff options
Diffstat (limited to 'tests/helpers/term_api.h')
| -rw-r--r-- | tests/helpers/term_api.h | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/tests/helpers/term_api.h b/tests/helpers/term_api.h new file mode 100644 index 0000000..bfa8d71 --- /dev/null +++ b/tests/helpers/term_api.h @@ -0,0 +1,182 @@ +#ifndef WSAP_TEST_TERM_API_H +#define WSAP_TEST_TERM_API_H + +/* + * Short forms of the public terminal API for tests. Cell reads go through + * a snapshot, the same way a renderer reads, so tests check only what the + * terminal shows. + */ + +#include "term/term.h" + +#include <stdbool.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +/* The history size the tests assume. */ +#define TEST_SCROLLBACK 4096 + +static inline struct term *tt_new_opts(int cols, int rows, const struct term_callbacks *cb) +{ + struct term_options opt = { + .size = { .x = cols, .y = rows }, + .scrollback = TEST_SCROLLBACK, + }; + if (cb) + opt.callbacks = *cb; + return term_new(&opt); +} + +static inline struct term *tt_new(int cols, int rows) +{ + return tt_new_opts(cols, rows, NULL); +} + +static inline void tt_write(struct term *t, const char *s, size_t len) +{ + term_feed(t, s, len, 0); +} + +static inline void tt_puts(struct term *t, const char *s) +{ + term_feed(t, s, strlen(s), 0); +} + +static inline int tt_cols(const struct term *t) { return term_size(t).x; } +static inline int tt_rows(const struct term *t) { return term_size(t).y; } +static inline int tt_cursor_x(const struct term *t) { return term_cursor(t).pos.x; } +static inline int tt_cursor_y(const struct term *t) { return term_cursor(t).pos.y; } +static inline int tt_history(const struct term *t) { return term_scrollback(t).total; } +static inline int tt_view_offset(const struct term *t) { return term_scrollback(t).offset; } + +/* One snapshot serves every read. It follows whichever terminal a test + * reads last. */ +static struct term_snapshot *tt_snapshot_for(struct term *t) +{ + static struct term_snapshot *snap; + if (!snap) + snap = term_snapshot_new(); + term_snapshot_update(snap, t); + return snap; +} + +static const struct term_cell tt_blank_cell = { + .text = ' ', .fg = TERM_COLOR_FG, .bg = TERM_COLOR_BG, .width = 1, +}; + +/* A cell of the viewport. Out-of-range columns read as a blank cell. */ +static inline const struct term_cell *tt_view_cell(struct term *t, int col, int row) +{ + struct term_snapshot *s = tt_snapshot_for(t); + const struct term_cell *cells = term_snapshot_row(s, row); + if (!cells) + return NULL; + if (col < 0 || col >= term_snapshot_view(s)->size.x) + return &tt_blank_cell; + return &cells[col]; +} + +/* A cell of the live screen, whatever the viewport shows. */ +static inline const struct term_cell *tt_cell(struct term *t, int col, int row) +{ + int offset = tt_view_offset(t); + if (offset) + term_scroll_to(t, 0); + const struct term_cell *cell = tt_view_cell(t, col, row); + if (offset) + term_scroll_to(t, offset); + return cell; +} + +/* The code points of a cell's text: one, or a whole cluster. The snapshot + * that the last read used must still describe the terminal. */ +static inline int tt_cell_cps(struct term *t, const struct term_cell *cell, + uint32_t *cps, int cap) +{ + return term_snapshot_cluster(tt_snapshot_for(t), cell->text, cps, cap); +} + +/* The first code point of a cell's text. */ +static inline uint32_t tt_cell_cp(struct term *t, const struct term_cell *cell) +{ + uint32_t cp = 0; + if (!(cell->text & TERM_TEXT_CLUSTER)) + return cell->text; + tt_cell_cps(t, cell, &cp, 1); + return cp; +} + +static inline bool tt_is_cluster(const struct term_cell *cell) +{ + return (cell->text & TERM_TEXT_CLUSTER) != 0; +} + +/* The selected columns [begin, end) of a viewport row. */ +static inline struct term_span tt_row_selection(struct term *t, int row) +{ + return term_snapshot_row_selection(tt_snapshot_for(t), row); +} + +static inline bool tt_selected(struct term *t, int col, int row) +{ + struct term_span span = tt_row_selection(t, row); + return col >= span.begin && col < span.end; +} + +/* Select from one viewport cell to another, both inclusive. */ +static inline void tt_select(struct term *t, int x1, int y1, int x2, int y2) +{ + bool forward = y1 < y2 || (y1 == y2 && x1 <= x2); + struct term_vector2i a = { .x = x1, .y = y1 }, b = { .x = x2, .y = y2 }; + term_select_start(t, forward ? a : b, false, TERM_SELECT_CELL); + term_select_extend(t, forward ? b : a, true); +} + +/* The helpers below return new strings. The caller frees them. */ +/* NULL when nothing is selected. */ +static inline char *tt_selection_text(const struct term *t) +{ + size_t n = term_selection_text(t, NULL, 0); + if (!n) + return NULL; + char *text = malloc(n + 1); + if (text) + term_selection_text(t, text, n + 1); + return text; +} + +static inline char *tt_history_text(struct term *t, int max_rows) +{ + size_t n = term_history_text(t, max_rows, NULL, 0); + char *text = malloc(n + 1); + if (text) + term_history_text(t, max_rows, text, n + 1); + return text; +} + +/* NULL when there is no link. */ +static inline char *tt_link_at(struct term *t, int col, int row) +{ + struct term_vector2i cell = { .x = col, .y = row }; + size_t n = term_link_at(t, cell, NULL, 0); + if (!n) + return NULL; + char *url = malloc(n + 1); + if (url) + term_link_at(t, cell, url, n + 1); + return url; +} + +static inline bool tt_resize(struct term *t, int cols, int rows) +{ + return term_resize(t, (struct term_vector2i){ .x = cols, .y = rows }); +} + +/* The ARGB value of a color in the terminal's current palette. */ +static inline uint32_t tt_color(struct term *t, term_color c) +{ + return term_view_color(term_snapshot_view(tt_snapshot_for(t)), c); +} + +#endif |
