summaryrefslogtreecommitdiff
path: root/tests/extern/kitty/screen_bridge.c
blob: 50f86a736aeb4808b00b641defe4f300c5862944 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/* Test-only entry points for the Kitty screen wrapper in screen.py.
 * Python calls only these functions, so it needs no struct layouts other
 * than the public struct term_cell. The kitty_screen_* accessors read
 * properties that term.h does not expose. They compile against the current
 * terminal layout rather than duplicating byte offsets in Python. */
#include "internal.h"
#include "screen.h"

typedef void (*kitty_reply_fn)(void *ud, const char *bytes, size_t len);

struct term *kitty_term_new(int cols, int rows, kitty_reply_fn reply, void *ud)
{
    return term_new(&(struct term_options){
        .size = { .x = cols, .y = rows },
        .callbacks = { .ud = ud, .reply = reply },
    });
}

/* One snapshot serves every cell read. */
static struct term_snapshot *snap;

void kitty_term_free(struct term *t)
{
    /* A new terminal can get the address of the freed one. The snapshot
     * would then keep its rows, so it goes away too. */
    term_snapshot_free(snap);
    snap = NULL;
    term_free(t);
}

void kitty_term_write(struct term *t, const char *bytes, size_t len)
{
    term_feed(t, bytes, len, 0);
}

bool kitty_term_resize(struct term *t, int cols, int rows)
{
    return term_resize(t, (struct term_vector2i){ .x = cols, .y = rows });
}

int kitty_term_cols(struct term *t) { return term_size(t).x; }
int kitty_term_rows(struct term *t) { return term_size(t).y; }
int kitty_term_cursor_x(struct term *t) { return term_cursor(t).pos.x; }
int kitty_term_cursor_y(struct term *t) { return term_cursor(t).pos.y; }
int kitty_term_cursor_style(struct term *t) { return (int)term_cursor(t).style; }
bool kitty_term_cursor_blink(struct term *t) { return term_cursor(t).blink; }
bool kitty_term_application_cursor(struct term *t) { return term_modes(t).app_cursor; }

/* Update the snapshot from the live screen, as a renderer reads it.
 * Returns NULL when the cell is out of range or memory runs out. */
static struct term_snapshot *cell_snapshot(struct term *t, int col, int row)
{
    struct term_vector2i size = term_size(t);
    if (col < 0 || col >= size.x || row < 0 || row >= size.y)
        return NULL;
    if (!snap)
        snap = term_snapshot_new();
    term_scroll_to(t, 0);
    if (!snap || !term_snapshot_update(snap, t))
        return NULL;
    return snap;
}

bool kitty_term_cell(struct term *t, int col, int row, struct term_cell *out)
{
    struct term_snapshot *s = cell_snapshot(t, col, row);
    if (!s)
        return false;
    *out = term_snapshot_row(s, row)[col];
    return true;
}

/* The code points of a cell's text: one, or a whole grapheme cluster.
 * Returns the number of code points and writes at most cap of them. */
int kitty_term_cell_text(struct term *t, int col, int row, uint32_t *cps, int cap)
{
    struct term_snapshot *s = cell_snapshot(t, col, row);
    if (!s)
        return 0;
    return term_snapshot_cluster(s, term_snapshot_row(s, row)[col].text, cps, cap);
}

#define PROPERTY(type, name) \
    type kitty_screen_##name(struct term *t) { return t->name; }

PROPERTY(int, scroll_top)
PROPERTY(int, scroll_bottom)
PROPERTY(uint32_t, cur_fg)
PROPERTY(uint32_t, cur_bg)
PROPERTY(bool, bold)
PROPERTY(bool, faint)
PROPERTY(bool, italic)
PROPERTY(bool, strike)
PROPERTY(bool, inverse)
PROPERTY(uint8_t, underline)

int kitty_screen_row_length(struct term *t, int row)
{
    if (!t || row < 0 || row >= t->rows) return 0;
    const struct srow *r = term_row(t, row);
    return r ? (int)r->len : 0;
}

/* A tab stores a marker cell that a snapshot shows as a blank. Kitty keeps
 * the tab in its line text, so the wrapper asks for the marker. */
bool kitty_screen_cell_is_tab(struct term *t, int col, int row)
{
    if (col < 0 || col >= t->cols || row < 0 || row >= t->rows)
        return false;
    term_scroll_to(t, 0);
    const struct cell *cells = term_screen_view_row(t, row);
    return cells && cells[col].c == '\t';
}