summaryrefslogtreecommitdiff
path: root/tests/extern/kitty/screen_bridge.c
diff options
context:
space:
mode:
authorBerke Güzel <wenekar1@gmail.com>2026-10-12 17:49:34 +0300
committerBerke Güzel <wenekar1@gmail.com>2026-10-12 17:49:34 +0300
commit4384435941b8c7658856b381d071aee2e0035e89 (patch)
tree5ece99c3dd1decb8ec3fd404c0ece2b5865a552a /tests/extern/kitty/screen_bridge.c
term: move the term core to subprojects/term
The core now builds, tests, and benchmarks alone, as a Meson subproject with no dependency on the main tree. - include/term/ holds term.h and the header-only unicode/. src/ holds the core and its private headers. The main tree gets only include/term through term_dep, so it cannot reach a private header. - The term tests, the term benchmarks, the Kitty parser suite, and tools/amalgamate.py and tools/generate_unicode.py move with it. The tests run as term:<name>. - The main build passes its -march (arch_flag) and b_ndebug to the subproject. A directory configured before this commit needs meson configure -Dterm:arch_flag=-march=... once. - The term tests compile with -UNDEBUG. They do work inside assert. - The subproject exports term_test_dep with term_api.h, for the main tree's render, thumbnail, color, and selection tests. - The Kitty bridge used struct vector2i and has not compiled since the public API redesign. It builds again. 2 of its 14 tests fail: REP after a tab, and a cursor report after a resize. - dirgraph.py drops the term and unicode layers. Its self-test uses pty. - The symbols test ignores the __odr_asan symbols that ASan adds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'tests/extern/kitty/screen_bridge.c')
-rw-r--r--tests/extern/kitty/screen_bridge.c113
1 files changed, 113 insertions, 0 deletions
diff --git a/tests/extern/kitty/screen_bridge.c b/tests/extern/kitty/screen_bridge.c
new file mode 100644
index 0000000..63a3583
--- /dev/null
+++ b/tests/extern/kitty/screen_bridge.c
@@ -0,0 +1,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_screen_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';
+}