@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.
- package/CMakeLists.txt +284 -0
- package/README.md +151 -9
- package/binding-candidates.js +40 -0
- package/index.d.ts +107 -0
- package/index.js +92 -48
- package/package.json +6 -2
- package/prebuilt/darwin-arm64-node137/ghostty_vt_node.node +0 -0
- package/prebuilt/darwin-arm64-node137/libghostty-vt.0.1.0.dylib +0 -0
- package/prebuilt/darwin-arm64-node137/libghostty-vt.dylib +0 -0
- package/prebuilt/darwin-arm64-node137/manifest.json +34 -0
- package/prebuilt/linux-x64-node137/ghostty_vt_node.node +0 -0
- package/prebuilt/linux-x64-node137/libghostty-vt.so +0 -0
- package/prebuilt/linux-x64-node137/libghostty-vt.so.0 +0 -0
- package/prebuilt/linux-x64-node137/libghostty-vt.so.0.1.0 +0 -0
- package/prebuilt/linux-x64-node137/manifest.json +38 -0
- package/prebuilt/win32-x64-node137/ghostty-vt.dll +0 -0
- package/prebuilt/win32-x64-node137/ghostty_vt_node.node +0 -0
- package/prebuilt/win32-x64-node137/manifest.json +30 -0
- package/scripts/binding-digest.mjs +60 -0
- package/scripts/build-or-use-prebuilt.mjs +60 -31
- package/scripts/check-prebuilts.mjs +113 -0
- package/scripts/clean-dir.cjs +32 -0
- package/scripts/host-path-scan.mjs +115 -0
- package/scripts/native-format.mjs +219 -0
- package/scripts/prebuilt-manifest.mjs +231 -0
- package/scripts/probe-build-provenance.mjs +288 -0
- package/scripts/verify-prebuilt.mjs +115 -0
- package/src/addon.cc +403 -23
- package/src/ghostty_bridge.c +344 -0
- package/src/ghostty_bridge.h +96 -0
- package/toolchain.json +3 -0
- package/prebuilt/darwin-arm64-node115/ghostty_vt_node.node +0 -0
- package/prebuilt/darwin-arm64-node115/libghostty-vt.0.1.0.dylib +0 -0
- package/prebuilt/darwin-arm64-node115/libghostty-vt.dylib +0 -0
- package/prebuilt/darwin-arm64-node127/ghostty_vt_node.node +0 -0
- package/prebuilt/darwin-arm64-node127/libghostty-vt.0.1.0.dylib +0 -0
- package/prebuilt/darwin-arm64-node127/libghostty-vt.dylib +0 -0
- package/prebuilt/darwin-arm64-node141/ghostty_vt_node.node +0 -0
- package/prebuilt/darwin-arm64-node141/libghostty-vt.0.1.0.dylib +0 -0
- package/prebuilt/darwin-arm64-node141/libghostty-vt.dylib +0 -0
- package/prebuilt/linux-x64-node115/ghostty_vt_node.node +0 -0
- package/prebuilt/linux-x64-node115/libghostty-vt.so +0 -0
- package/prebuilt/linux-x64-node115/libghostty-vt.so.0 +0 -0
- package/prebuilt/linux-x64-node115/libghostty-vt.so.0.1.0 +0 -0
- package/prebuilt/linux-x64-node127/ghostty_vt_node.node +0 -0
- package/prebuilt/linux-x64-node127/libghostty-vt.so +0 -0
- package/prebuilt/linux-x64-node127/libghostty-vt.so.0 +0 -0
- package/prebuilt/linux-x64-node127/libghostty-vt.so.0.1.0 +0 -0
- package/prebuilt/linux-x64-node141/ghostty_vt_node.node +0 -0
- package/prebuilt/linux-x64-node141/libghostty-vt.so +0 -0
- package/prebuilt/linux-x64-node141/libghostty-vt.so.0 +0 -0
- package/prebuilt/linux-x64-node141/libghostty-vt.so.0.1.0 +0 -0
- package/prebuilt/win32-x64-node127/ghostty-vt.dll +0 -0
- package/prebuilt/win32-x64-node127/ghostty_vt_node.node +0 -0
package/src/ghostty_bridge.c
CHANGED
|
@@ -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
|
}
|
package/src/ghostty_bridge.h
CHANGED
|
@@ -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
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|