@adhdev/ghostty-vt-node 1.0.78 → 1.0.82-rc.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/CMakeLists.txt +284 -0
  2. package/README.md +151 -9
  3. package/binding-candidates.js +40 -0
  4. package/index.d.ts +107 -0
  5. package/index.js +92 -48
  6. package/package.json +6 -2
  7. package/prebuilt/darwin-arm64-node137/ghostty_vt_node.node +0 -0
  8. package/prebuilt/darwin-arm64-node137/libghostty-vt.0.1.0.dylib +0 -0
  9. package/prebuilt/darwin-arm64-node137/libghostty-vt.dylib +0 -0
  10. package/prebuilt/darwin-arm64-node137/manifest.json +34 -0
  11. package/prebuilt/linux-x64-node137/ghostty_vt_node.node +0 -0
  12. package/prebuilt/linux-x64-node137/libghostty-vt.so +0 -0
  13. package/prebuilt/linux-x64-node137/libghostty-vt.so.0 +0 -0
  14. package/prebuilt/linux-x64-node137/libghostty-vt.so.0.1.0 +0 -0
  15. package/prebuilt/linux-x64-node137/manifest.json +38 -0
  16. package/prebuilt/win32-x64-node137/ghostty-vt.dll +0 -0
  17. package/prebuilt/win32-x64-node137/ghostty_vt_node.node +0 -0
  18. package/prebuilt/win32-x64-node137/manifest.json +30 -0
  19. package/scripts/binding-digest.mjs +60 -0
  20. package/scripts/build-or-use-prebuilt.mjs +60 -31
  21. package/scripts/check-prebuilts.mjs +113 -0
  22. package/scripts/clean-dir.cjs +32 -0
  23. package/scripts/host-path-scan.mjs +115 -0
  24. package/scripts/native-format.mjs +219 -0
  25. package/scripts/prebuilt-manifest.mjs +231 -0
  26. package/scripts/probe-build-provenance.mjs +288 -0
  27. package/scripts/verify-prebuilt.mjs +115 -0
  28. package/src/addon.cc +403 -23
  29. package/src/ghostty_bridge.c +344 -0
  30. package/src/ghostty_bridge.h +96 -0
  31. package/toolchain.json +3 -0
  32. package/prebuilt/darwin-arm64-node115/ghostty_vt_node.node +0 -0
  33. package/prebuilt/darwin-arm64-node115/libghostty-vt.0.1.0.dylib +0 -0
  34. package/prebuilt/darwin-arm64-node115/libghostty-vt.dylib +0 -0
  35. package/prebuilt/darwin-arm64-node127/ghostty_vt_node.node +0 -0
  36. package/prebuilt/darwin-arm64-node127/libghostty-vt.0.1.0.dylib +0 -0
  37. package/prebuilt/darwin-arm64-node127/libghostty-vt.dylib +0 -0
  38. package/prebuilt/darwin-arm64-node141/ghostty_vt_node.node +0 -0
  39. package/prebuilt/darwin-arm64-node141/libghostty-vt.0.1.0.dylib +0 -0
  40. package/prebuilt/darwin-arm64-node141/libghostty-vt.dylib +0 -0
  41. package/prebuilt/linux-x64-node115/ghostty_vt_node.node +0 -0
  42. package/prebuilt/linux-x64-node115/libghostty-vt.so +0 -0
  43. package/prebuilt/linux-x64-node115/libghostty-vt.so.0 +0 -0
  44. package/prebuilt/linux-x64-node115/libghostty-vt.so.0.1.0 +0 -0
  45. package/prebuilt/linux-x64-node127/ghostty_vt_node.node +0 -0
  46. package/prebuilt/linux-x64-node127/libghostty-vt.so +0 -0
  47. package/prebuilt/linux-x64-node127/libghostty-vt.so.0 +0 -0
  48. package/prebuilt/linux-x64-node127/libghostty-vt.so.0.1.0 +0 -0
  49. package/prebuilt/linux-x64-node141/ghostty_vt_node.node +0 -0
  50. package/prebuilt/linux-x64-node141/libghostty-vt.so +0 -0
  51. package/prebuilt/linux-x64-node141/libghostty-vt.so.0 +0 -0
  52. package/prebuilt/linux-x64-node141/libghostty-vt.so.0.1.0 +0 -0
  53. package/prebuilt/win32-x64-node127/ghostty-vt.dll +0 -0
  54. package/prebuilt/win32-x64-node127/ghostty_vt_node.node +0 -0
@@ -2,10 +2,16 @@
2
2
 
3
3
  #include <ghostty/vt.h>
4
4
 
5
+ #include <stdlib.h>
6
+ #include <string.h>
7
+
5
8
  struct AdhdevGhosttyTerminal {
6
9
  GhosttyTerminal handle;
7
10
  uint16_t cols;
8
11
  uint16_t rows;
12
+ // Bumped on every mutation (write/resize/scroll) so a reader can tell
13
+ // whether two reads describe the same terminal state.
14
+ uint64_t revision;
9
15
  };
10
16
 
11
17
  static const uint32_t kCellWidthPx = 8;
@@ -24,6 +30,7 @@ int adhdev_ghostty_terminal_create(
24
30
  terminal->cols = cols;
25
31
  terminal->rows = rows;
26
32
  terminal->handle = NULL;
33
+ terminal->revision = 0;
27
34
 
28
35
  GhosttyTerminalOptions options = {
29
36
  .cols = cols,
@@ -46,6 +53,7 @@ int adhdev_ghostty_terminal_write(
46
53
  const uint8_t* data,
47
54
  size_t len) {
48
55
  if (!terminal || !terminal->handle || (!data && len > 0)) return GHOSTTY_INVALID_VALUE;
56
+ terminal->revision++;
49
57
  ghostty_terminal_vt_write(terminal->handle, data, len);
50
58
  return GHOSTTY_SUCCESS;
51
59
  }
@@ -55,6 +63,7 @@ int adhdev_ghostty_terminal_resize(
55
63
  uint16_t cols,
56
64
  uint16_t rows) {
57
65
  if (!terminal || !terminal->handle || cols == 0 || rows == 0) return GHOSTTY_INVALID_VALUE;
66
+ terminal->revision++;
58
67
  terminal->cols = cols;
59
68
  terminal->rows = rows;
60
69
  (void)kCellWidthPx;
@@ -146,6 +155,339 @@ int adhdev_ghostty_terminal_cursor_position(
146
155
  return GHOSTTY_SUCCESS;
147
156
  }
148
157
 
158
+ // Growable byte buffer for the deep copies below. Everything handed out of
159
+ // this file is plain malloc memory owned by the caller; no GridRef or page
160
+ // pointer outlives the call that resolved it.
161
+ typedef struct {
162
+ char* data;
163
+ size_t len;
164
+ size_t cap;
165
+ } ByteBuffer;
166
+
167
+ static int byte_buffer_reserve(ByteBuffer* buffer, size_t extra) {
168
+ if (buffer->len + extra <= buffer->cap) return GHOSTTY_SUCCESS;
169
+ size_t cap = buffer->cap ? buffer->cap : 64;
170
+ while (cap < buffer->len + extra) cap *= 2;
171
+ char* data = (char*)realloc(buffer->data, cap);
172
+ if (!data) return GHOSTTY_OUT_OF_MEMORY;
173
+ buffer->data = data;
174
+ buffer->cap = cap;
175
+ return GHOSTTY_SUCCESS;
176
+ }
177
+
178
+ static int byte_buffer_append_codepoint(ByteBuffer* buffer, uint32_t cp) {
179
+ // Surrogates and out-of-range values cannot be encoded as UTF-8.
180
+ if ((cp >= 0xD800 && cp <= 0xDFFF) || cp > 0x10FFFF) cp = 0xFFFD;
181
+ int result = byte_buffer_reserve(buffer, 4);
182
+ if (result != GHOSTTY_SUCCESS) return result;
183
+ char* out = buffer->data + buffer->len;
184
+ if (cp < 0x80) {
185
+ out[0] = (char)cp;
186
+ buffer->len += 1;
187
+ } else if (cp < 0x800) {
188
+ out[0] = (char)(0xC0 | (cp >> 6));
189
+ out[1] = (char)(0x80 | (cp & 0x3F));
190
+ buffer->len += 2;
191
+ } else if (cp < 0x10000) {
192
+ out[0] = (char)(0xE0 | (cp >> 12));
193
+ out[1] = (char)(0x80 | ((cp >> 6) & 0x3F));
194
+ out[2] = (char)(0x80 | (cp & 0x3F));
195
+ buffer->len += 3;
196
+ } else {
197
+ out[0] = (char)(0xF0 | (cp >> 18));
198
+ out[1] = (char)(0x80 | ((cp >> 12) & 0x3F));
199
+ out[2] = (char)(0x80 | ((cp >> 6) & 0x3F));
200
+ out[3] = (char)(0x80 | (cp & 0x3F));
201
+ buffer->len += 4;
202
+ }
203
+ return GHOSTTY_SUCCESS;
204
+ }
205
+
206
+ static int resolve_ref(GhosttyTerminal handle, GhosttyPointTag tag, uint16_t x, uint16_t y, GhosttyGridRef* out_ref) {
207
+ GhosttyPoint point;
208
+ memset(&point, 0, sizeof(point));
209
+ point.tag = tag;
210
+ point.value.coordinate.x = x;
211
+ point.value.coordinate.y = y;
212
+ *out_ref = GHOSTTY_INIT_SIZED(GhosttyGridRef);
213
+ return ghostty_terminal_grid_ref(handle, point, out_ref);
214
+ }
215
+
216
+ void adhdev_ghostty_row_data_release(AdhdevGhosttyRowData* row) {
217
+ if (!row) return;
218
+ free(row->text);
219
+ free(row->cells);
220
+ free(row->cell_text);
221
+ memset(row, 0, sizeof(*row));
222
+ }
223
+
224
+ // Reads physical row `y` of `tag` cell by cell. Row text keeps an empty cell
225
+ // that sits before real content as U+0020 (so cursor-forward gaps survive) and
226
+ // drops only the trailing run of content-less cells; spacer cells contribute
227
+ // nothing because their glyph belongs to the wide cell that owns them.
228
+ static int read_row_internal(
229
+ GhosttyTerminal handle,
230
+ GhosttyPointTag tag,
231
+ uint16_t y,
232
+ uint16_t cols,
233
+ int include_cells,
234
+ AdhdevGhosttyRowData* out_row) {
235
+ memset(out_row, 0, sizeof(*out_row));
236
+ out_row->row = y;
237
+
238
+ GhosttyGridRef ref;
239
+ int result = resolve_ref(handle, tag, 0, y, &ref);
240
+ if (result != GHOSTTY_SUCCESS) return result;
241
+
242
+ GhosttyRow row_value = 0;
243
+ result = ghostty_grid_ref_row(&ref, &row_value);
244
+ if (result != GHOSTTY_SUCCESS) return result;
245
+ bool wrapped = false;
246
+ bool wrap_continuation = false;
247
+ result = ghostty_row_get(row_value, GHOSTTY_ROW_DATA_WRAP, &wrapped);
248
+ if (result != GHOSTTY_SUCCESS) return result;
249
+ result = ghostty_row_get(row_value, GHOSTTY_ROW_DATA_WRAP_CONTINUATION, &wrap_continuation);
250
+ if (result != GHOSTTY_SUCCESS) return result;
251
+ out_row->wrapped = wrapped;
252
+ out_row->wrap_continuation = wrap_continuation;
253
+
254
+ ByteBuffer text = {0};
255
+ ByteBuffer cell_text = {0};
256
+ AdhdevGhosttyCellInfo* cells = NULL;
257
+ uint32_t inline_codepoints[16];
258
+ uint32_t* codepoints = inline_codepoints;
259
+ size_t codepoint_cap = sizeof(inline_codepoints) / sizeof(inline_codepoints[0]);
260
+ size_t content_end = 0;
261
+
262
+ if (include_cells) {
263
+ cells = (AdhdevGhosttyCellInfo*)calloc(cols ? cols : 1, sizeof(AdhdevGhosttyCellInfo));
264
+ if (!cells) {
265
+ result = GHOSTTY_OUT_OF_MEMORY;
266
+ goto fail;
267
+ }
268
+ }
269
+
270
+ for (uint16_t x = 0; x < cols; x++) {
271
+ result = resolve_ref(handle, tag, x, y, &ref);
272
+ if (result != GHOSTTY_SUCCESS) goto fail;
273
+
274
+ GhosttyCell cell = 0;
275
+ result = ghostty_grid_ref_cell(&ref, &cell);
276
+ if (result != GHOSTTY_SUCCESS) goto fail;
277
+ GhosttyCellWide wide = GHOSTTY_CELL_WIDE_NARROW;
278
+ result = ghostty_cell_get(cell, GHOSTTY_CELL_DATA_WIDE, &wide);
279
+ if (result != GHOSTTY_SUCCESS) goto fail;
280
+
281
+ size_t count = 0;
282
+ result = ghostty_grid_ref_graphemes(&ref, codepoints, codepoint_cap, &count);
283
+ if (result == GHOSTTY_OUT_OF_SPACE) {
284
+ // Never truncate a grapheme cluster: grow to the reported length.
285
+ uint32_t* grown = (uint32_t*)malloc(count * sizeof(uint32_t));
286
+ if (!grown) {
287
+ result = GHOSTTY_OUT_OF_MEMORY;
288
+ goto fail;
289
+ }
290
+ if (codepoints != inline_codepoints) free(codepoints);
291
+ codepoints = grown;
292
+ codepoint_cap = count;
293
+ result = ghostty_grid_ref_graphemes(&ref, codepoints, codepoint_cap, &count);
294
+ }
295
+ if (result != GHOSTTY_SUCCESS) goto fail;
296
+
297
+ const bool spacer = wide == GHOSTTY_CELL_WIDE_SPACER_TAIL || wide == GHOSTTY_CELL_WIDE_SPACER_HEAD;
298
+ if (cells) {
299
+ cells[x].wide = (uint8_t)wide;
300
+ cells[x].text_offset = (uint32_t)cell_text.len;
301
+ }
302
+ if (spacer) {
303
+ if (cells) cells[x].text_len = 0;
304
+ continue;
305
+ }
306
+ if (count == 0) {
307
+ if (cells) cells[x].text_len = 0;
308
+ result = byte_buffer_reserve(&text, 1);
309
+ if (result != GHOSTTY_SUCCESS) goto fail;
310
+ text.data[text.len++] = ' ';
311
+ continue;
312
+ }
313
+ for (size_t i = 0; i < count; i++) {
314
+ result = byte_buffer_append_codepoint(&text, codepoints[i]);
315
+ if (result != GHOSTTY_SUCCESS) goto fail;
316
+ if (cells) {
317
+ result = byte_buffer_append_codepoint(&cell_text, codepoints[i]);
318
+ if (result != GHOSTTY_SUCCESS) goto fail;
319
+ }
320
+ }
321
+ content_end = text.len;
322
+ if (cells) cells[x].text_len = (uint32_t)(cell_text.len - cells[x].text_offset);
323
+ }
324
+
325
+ if (codepoints != inline_codepoints) free(codepoints);
326
+ out_row->text = text.data;
327
+ out_row->text_len = content_end;
328
+ out_row->cells = cells;
329
+ out_row->cell_count = cells ? cols : 0;
330
+ out_row->cell_text = cell_text.data;
331
+ out_row->cell_text_len = cell_text.len;
332
+ return GHOSTTY_SUCCESS;
333
+
334
+ fail:
335
+ if (codepoints != inline_codepoints) free(codepoints);
336
+ free(text.data);
337
+ free(cell_text.data);
338
+ free(cells);
339
+ memset(out_row, 0, sizeof(*out_row));
340
+ return result;
341
+ }
342
+
343
+ static int read_dims(GhosttyTerminal handle, uint16_t* out_cols, uint16_t* out_rows) {
344
+ int result = ghostty_terminal_get(handle, GHOSTTY_TERMINAL_DATA_COLS, out_cols);
345
+ if (result != GHOSTTY_SUCCESS) return result;
346
+ return ghostty_terminal_get(handle, GHOSTTY_TERMINAL_DATA_ROWS, out_rows);
347
+ }
348
+
349
+ void adhdev_ghostty_viewport_free(AdhdevGhosttyViewport* viewport) {
350
+ if (!viewport) return;
351
+ if (viewport->lines) {
352
+ for (size_t i = 0; i < viewport->line_count; i++) {
353
+ adhdev_ghostty_row_data_release(&viewport->lines[i]);
354
+ }
355
+ free(viewport->lines);
356
+ }
357
+ free(viewport);
358
+ }
359
+
360
+ int adhdev_ghostty_terminal_get_viewport(
361
+ AdhdevGhosttyTerminal* terminal,
362
+ int include_rows,
363
+ int include_cells,
364
+ AdhdevGhosttyViewport** out_viewport) {
365
+ if (!terminal || !terminal->handle || !out_viewport) return GHOSTTY_INVALID_VALUE;
366
+ if (include_rows < ADHDEV_GHOSTTY_ROWS_NONE || include_rows > ADHDEV_GHOSTTY_ROWS_ALL) return GHOSTTY_INVALID_VALUE;
367
+ *out_viewport = NULL;
368
+
369
+ AdhdevGhosttyViewport* viewport = (AdhdevGhosttyViewport*)calloc(1, sizeof(AdhdevGhosttyViewport));
370
+ if (!viewport) return GHOSTTY_OUT_OF_MEMORY;
371
+ viewport->revision = terminal->revision;
372
+
373
+ GhosttyTerminal handle = terminal->handle;
374
+ int result = read_dims(handle, &viewport->cols, &viewport->rows);
375
+ if (result != GHOSTTY_SUCCESS) goto fail;
376
+ result = ghostty_terminal_get(handle, GHOSTTY_TERMINAL_DATA_CURSOR_X, &viewport->cursor_col);
377
+ if (result != GHOSTTY_SUCCESS) goto fail;
378
+ result = ghostty_terminal_get(handle, GHOSTTY_TERMINAL_DATA_CURSOR_Y, &viewport->cursor_row);
379
+ if (result != GHOSTTY_SUCCESS) goto fail;
380
+ bool pending_wrap = false;
381
+ bool cursor_visible = false;
382
+ result = ghostty_terminal_get(handle, GHOSTTY_TERMINAL_DATA_CURSOR_PENDING_WRAP, &pending_wrap);
383
+ if (result != GHOSTTY_SUCCESS) goto fail;
384
+ result = ghostty_terminal_get(handle, GHOSTTY_TERMINAL_DATA_CURSOR_VISIBLE, &cursor_visible);
385
+ if (result != GHOSTTY_SUCCESS) goto fail;
386
+ viewport->cursor_pending_wrap = pending_wrap;
387
+ viewport->cursor_visible = cursor_visible;
388
+ GhosttyTerminalScreen active_screen = GHOSTTY_TERMINAL_SCREEN_PRIMARY;
389
+ result = ghostty_terminal_get(handle, GHOSTTY_TERMINAL_DATA_ACTIVE_SCREEN, &active_screen);
390
+ if (result != GHOSTTY_SUCCESS) goto fail;
391
+ viewport->active_screen = active_screen == GHOSTTY_TERMINAL_SCREEN_ALTERNATE ? 1 : 0;
392
+ GhosttyTerminalScrollbar scrollbar;
393
+ memset(&scrollbar, 0, sizeof(scrollbar));
394
+ result = ghostty_terminal_get(handle, GHOSTTY_TERMINAL_DATA_SCROLLBAR, &scrollbar);
395
+ if (result != GHOSTTY_SUCCESS) goto fail;
396
+ viewport->scrollbar_total = scrollbar.total;
397
+ viewport->scrollbar_offset = scrollbar.offset;
398
+ viewport->scrollbar_len = scrollbar.len;
399
+
400
+ if (include_rows == ADHDEV_GHOSTTY_ROWS_NONE) {
401
+ *out_viewport = viewport;
402
+ return GHOSTTY_SUCCESS;
403
+ }
404
+
405
+ const uint16_t first = include_rows == ADHDEV_GHOSTTY_ROWS_ALL ? 0 : viewport->cursor_row;
406
+ const size_t count = include_rows == ADHDEV_GHOSTTY_ROWS_ALL ? viewport->rows : 1;
407
+ viewport->lines = (AdhdevGhosttyRowData*)calloc(count, sizeof(AdhdevGhosttyRowData));
408
+ if (!viewport->lines) {
409
+ result = GHOSTTY_OUT_OF_MEMORY;
410
+ goto fail;
411
+ }
412
+ for (size_t i = 0; i < count; i++) {
413
+ result = read_row_internal(
414
+ handle,
415
+ GHOSTTY_POINT_TAG_ACTIVE,
416
+ (uint16_t)(first + i),
417
+ viewport->cols,
418
+ include_cells,
419
+ &viewport->lines[i]);
420
+ if (result != GHOSTTY_SUCCESS) goto fail;
421
+ viewport->line_count = i + 1;
422
+ }
423
+
424
+ *out_viewport = viewport;
425
+ return GHOSTTY_SUCCESS;
426
+
427
+ fail:
428
+ adhdev_ghostty_viewport_free(viewport);
429
+ return result;
430
+ }
431
+
432
+ int adhdev_ghostty_terminal_read_row(
433
+ AdhdevGhosttyTerminal* terminal,
434
+ int space,
435
+ uint16_t row,
436
+ int include_cells,
437
+ AdhdevGhosttyRowData* out_row,
438
+ uint64_t* out_revision) {
439
+ if (!terminal || !terminal->handle || !out_row || !out_revision) return GHOSTTY_INVALID_VALUE;
440
+ GhosttyPointTag tag;
441
+ if (space == ADHDEV_GHOSTTY_SPACE_ACTIVE) {
442
+ tag = GHOSTTY_POINT_TAG_ACTIVE;
443
+ } else if (space == ADHDEV_GHOSTTY_SPACE_VIEWPORT) {
444
+ tag = GHOSTTY_POINT_TAG_VIEWPORT;
445
+ } else {
446
+ return GHOSTTY_INVALID_VALUE;
447
+ }
448
+
449
+ uint16_t cols = 0;
450
+ uint16_t rows = 0;
451
+ int result = read_dims(terminal->handle, &cols, &rows);
452
+ if (result != GHOSTTY_SUCCESS) return result;
453
+ if (row >= rows) return ADHDEV_GHOSTTY_ROW_OUT_OF_RANGE;
454
+
455
+ result = read_row_internal(terminal->handle, tag, row, cols, include_cells, out_row);
456
+ if (result != GHOSTTY_SUCCESS) return result;
457
+ *out_revision = terminal->revision;
458
+ return GHOSTTY_SUCCESS;
459
+ }
460
+
461
+ int adhdev_ghostty_terminal_scroll_viewport(
462
+ AdhdevGhosttyTerminal* terminal,
463
+ int behavior,
464
+ int64_t delta) {
465
+ if (!terminal || !terminal->handle) return GHOSTTY_INVALID_VALUE;
466
+ GhosttyTerminalScrollViewport scroll;
467
+ memset(&scroll, 0, sizeof(scroll));
468
+ switch (behavior) {
469
+ case ADHDEV_GHOSTTY_SCROLL_TOP:
470
+ scroll.tag = GHOSTTY_SCROLL_VIEWPORT_TOP;
471
+ break;
472
+ case ADHDEV_GHOSTTY_SCROLL_BOTTOM:
473
+ scroll.tag = GHOSTTY_SCROLL_VIEWPORT_BOTTOM;
474
+ break;
475
+ case ADHDEV_GHOSTTY_SCROLL_DELTA:
476
+ scroll.tag = GHOSTTY_SCROLL_VIEWPORT_DELTA;
477
+ scroll.value.delta = (intptr_t)delta;
478
+ break;
479
+ default:
480
+ return GHOSTTY_INVALID_VALUE;
481
+ }
482
+ terminal->revision++;
483
+ ghostty_terminal_scroll_viewport(terminal->handle, scroll);
484
+ return GHOSTTY_SUCCESS;
485
+ }
486
+
487
+ uint64_t adhdev_ghostty_terminal_revision(AdhdevGhosttyTerminal* terminal) {
488
+ return terminal ? terminal->revision : 0;
489
+ }
490
+
149
491
  void adhdev_ghostty_terminal_free_text(char* text, size_t len) {
150
492
  if (!text) return;
151
493
  ghostty_free(NULL, (uint8_t*)text, len);
@@ -170,6 +512,8 @@ const char* adhdev_ghostty_result_message(int result) {
170
512
  return "invalid value";
171
513
  case GHOSTTY_OUT_OF_SPACE:
172
514
  return "out of space";
515
+ case ADHDEV_GHOSTTY_ROW_OUT_OF_RANGE:
516
+ return "row out of range";
173
517
  default:
174
518
  return "unknown error";
175
519
  }
@@ -1,6 +1,7 @@
1
1
  #ifndef ADHDEV_GHOSTTY_BRIDGE_H
2
2
  #define ADHDEV_GHOSTTY_BRIDGE_H
3
3
 
4
+ #include <stdbool.h>
4
5
  #include <stddef.h>
5
6
  #include <stdint.h>
6
7
 
@@ -11,7 +12,71 @@ extern "C" {
11
12
  typedef struct AdhdevGhosttyTerminal AdhdevGhosttyTerminal;
12
13
 
13
14
  #define ADHDEV_GHOSTTY_SUCCESS 0
15
+ #define ADHDEV_GHOSTTY_OUT_OF_MEMORY -1
14
16
  #define ADHDEV_GHOSTTY_INVALID_VALUE -2
17
+ // Bridge-level results (not produced by libghostty itself).
18
+ #define ADHDEV_GHOSTTY_ROW_OUT_OF_RANGE -100
19
+
20
+ // Version of the JS-visible binding surface. 1 = write/resize/formatPlainText/
21
+ // formatVT/getCursorPosition/dispose. 2 = adds getViewport/readRow/
22
+ // scrollViewport and the module-level getBindingInfo.
23
+ #define ADHDEV_GHOSTTY_API_LEVEL 2
24
+
25
+ // Coordinate space of a row index. ACTIVE is the rows x cols area the cursor
26
+ // moves in (what CURSOR_Y is relative to). VIEWPORT is the visible area, which
27
+ // differs from ACTIVE only while the viewport is scrolled into history.
28
+ #define ADHDEV_GHOSTTY_SPACE_ACTIVE 0
29
+ #define ADHDEV_GHOSTTY_SPACE_VIEWPORT 1
30
+
31
+ #define ADHDEV_GHOSTTY_ROWS_NONE 0
32
+ #define ADHDEV_GHOSTTY_ROWS_CURSOR 1
33
+ #define ADHDEV_GHOSTTY_ROWS_ALL 2
34
+
35
+ #define ADHDEV_GHOSTTY_SCROLL_TOP 0
36
+ #define ADHDEV_GHOSTTY_SCROLL_BOTTOM 1
37
+ #define ADHDEV_GHOSTTY_SCROLL_DELTA 2
38
+
39
+ // Matches GhosttyCellWide.
40
+ #define ADHDEV_GHOSTTY_WIDE_NARROW 0
41
+ #define ADHDEV_GHOSTTY_WIDE_WIDE 1
42
+ #define ADHDEV_GHOSTTY_WIDE_SPACER_TAIL 2
43
+ #define ADHDEV_GHOSTTY_WIDE_SPACER_HEAD 3
44
+
45
+ typedef struct {
46
+ uint8_t wide; // ADHDEV_GHOSTTY_WIDE_*
47
+ uint32_t text_offset; // byte offset into AdhdevGhosttyRowData.cell_text
48
+ uint32_t text_len; // UTF-8 bytes; 0 for empty cells and spacers
49
+ } AdhdevGhosttyCellInfo;
50
+
51
+ // One physical row, deep-copied out of the terminal. Owns its buffers; release
52
+ // with adhdev_ghostty_row_data_release().
53
+ typedef struct {
54
+ uint16_t row;
55
+ bool wrapped; // soft-wraps into the next physical row
56
+ bool wrap_continuation; // continues a soft-wrap from the previous row
57
+ char* text; // UTF-8, trailing content-less cells omitted
58
+ size_t text_len;
59
+ AdhdevGhosttyCellInfo* cells; // exactly cols entries, or NULL
60
+ size_t cell_count;
61
+ char* cell_text; // concatenated per-cell UTF-8
62
+ size_t cell_text_len;
63
+ } AdhdevGhosttyRowData;
64
+
65
+ typedef struct {
66
+ uint64_t revision;
67
+ uint16_t cols;
68
+ uint16_t rows;
69
+ uint16_t cursor_col;
70
+ uint16_t cursor_row; // ACTIVE space
71
+ bool cursor_pending_wrap;
72
+ bool cursor_visible;
73
+ uint8_t active_screen; // 0 = primary, 1 = alternate
74
+ uint64_t scrollbar_total;
75
+ uint64_t scrollbar_offset;
76
+ uint64_t scrollbar_len;
77
+ AdhdevGhosttyRowData* lines; // ACTIVE rows, or NULL
78
+ size_t line_count;
79
+ } AdhdevGhosttyViewport;
15
80
 
16
81
  int adhdev_ghostty_terminal_create(
17
82
  uint16_t cols,
@@ -45,6 +110,37 @@ int adhdev_ghostty_terminal_cursor_position(
45
110
  uint16_t* out_col,
46
111
  uint16_t* out_row);
47
112
 
113
+ // Reads metadata and (optionally) rows in one native call so they describe the
114
+ // same terminal state. include_rows is ADHDEV_GHOSTTY_ROWS_*. On success the
115
+ // caller owns *out_viewport and frees it with adhdev_ghostty_viewport_free().
116
+ int adhdev_ghostty_terminal_get_viewport(
117
+ AdhdevGhosttyTerminal* terminal,
118
+ int include_rows,
119
+ int include_cells,
120
+ AdhdevGhosttyViewport** out_viewport);
121
+
122
+ void adhdev_ghostty_viewport_free(AdhdevGhosttyViewport* viewport);
123
+
124
+ // Reads one row in the given ADHDEV_GHOSTTY_SPACE_*. Returns
125
+ // ADHDEV_GHOSTTY_ROW_OUT_OF_RANGE when row >= the native row count. On success
126
+ // *out_row owns buffers to release with adhdev_ghostty_row_data_release().
127
+ int adhdev_ghostty_terminal_read_row(
128
+ AdhdevGhosttyTerminal* terminal,
129
+ int space,
130
+ uint16_t row,
131
+ int include_cells,
132
+ AdhdevGhosttyRowData* out_row,
133
+ uint64_t* out_revision);
134
+
135
+ void adhdev_ghostty_row_data_release(AdhdevGhosttyRowData* row);
136
+
137
+ int adhdev_ghostty_terminal_scroll_viewport(
138
+ AdhdevGhosttyTerminal* terminal,
139
+ int behavior,
140
+ int64_t delta);
141
+
142
+ uint64_t adhdev_ghostty_terminal_revision(AdhdevGhosttyTerminal* terminal);
143
+
48
144
  void adhdev_ghostty_terminal_free_text(char* text, size_t len);
49
145
  void adhdev_ghostty_terminal_destroy(AdhdevGhosttyTerminal* terminal);
50
146
  const char* adhdev_ghostty_result_message(int result);
package/toolchain.json ADDED
@@ -0,0 +1,3 @@
1
+ {
2
+ "zig": "0.15.2"
3
+ }