Commit88a40fb3Recorded1 Apr 2026Repositorysigil-tui

Replace sigil-internal.h with public sigil/sigil.h

Changed
 native/grid.c | 677 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1 file changed, 677 deletions(-)
Diff
native/grid.cmodified
@@ -1,677 +0,0 @@
−1
/*
−2
* Native grid implementation for (sigil tui grid)
−3
*
−4
* Provides a high-performance character grid for terminal UI rendering.
−5
* Each cell stores a character, foreground color, background color, and
−6
* text attributes as flat C arrays, avoiding per-cell heap allocation.
−7
*/
−8
−9
#include "sigil-internal.h"
−10
#include <stdio.h>
−11
#include <stdlib.h>
−12
#include <string.h>
−13
−14
/* ============================================================
−15
* Cell layout: 4 int32_t values per cell
−16
* [0] = character (Unicode codepoint)
−17
* [1] = foreground color
−18
* [2] = background color
−19
* [3] = text attributes (bitmask)
−20
* ============================================================ */
−21
−22
#define CELL_FIELDS 4
−23
#define CELL_CHAR 0
−24
#define CELL_FG 1
−25
#define CELL_BG 2
−26
#define CELL_ATTRS 3
−27
−28
/* Attribute flags */
−29
#define ATTR_NONE 0
−30
#define ATTR_BOLD 1
−31
#define ATTR_DIM 2
−32
#define ATTR_ITALIC 4
−33
#define ATTR_UNDERLINE 8
−34
#define ATTR_INVERSE 16
−35
#define ATTR_STRIKETHROUGH 32
−36
−37
/* Default cell values */
−38
#define DEFAULT_CHAR ' '
−39
#define DEFAULT_COLOR (-1)
−40
#define DEFAULT_ATTRS 0
−41
−42
typedef struct {
−43
int width;
−44
int height;
−45
int32_t *cells; /* Flat array: width * height * CELL_FIELDS */
−46
} Grid;
−47
−48
static Value grid_type_tag = SIGIL_UNDEFINED;
−49
−50
static void grid_finalizer(void *data)
−51
{
−52
Grid *g = (Grid *)data;
−53
if (g) {
−54
free(g->cells);
−55
free(g);
−56
}
−57
}
−58
−59
static int is_grid(Value v)
−60
{
−61
if (!sigil_is_foreign(v)) return 0;
−62
return sigil_foreign_type(v) == grid_type_tag;
−63
}
−64
−65
static Grid *as_grid(Value v)
−66
{
−67
return (Grid *)sigil_foreign_data(v);
−68
}
−69
−70
/* Get cell pointer for (col, row) */
−71
static inline int32_t *cell_at(Grid *g, int col, int row)
−72
{
−73
return &g->cells[(row * g->width + col) * CELL_FIELDS];
−74
}
−75
−76
/* Initialize a cell to defaults */
−77
static inline void cell_clear(int32_t *cell)
−78
{
−79
cell[CELL_CHAR] = DEFAULT_CHAR;
−80
cell[CELL_FG] = DEFAULT_COLOR;
−81
cell[CELL_BG] = DEFAULT_COLOR;
−82
cell[CELL_ATTRS] = DEFAULT_ATTRS;
−83
}
−84
−85
/* ============================================================
−86
* Grid operations
−87
* ============================================================ */
−88
−89
/*
−90
* %make-grid width height -> grid
−91
*/
−92
static Value native_make_grid(SigilVM *vm, int argc, Value *args)
−93
{
−94
(void)argc;
−95
−96
int w = (int)sigil_as_fixnum(args[0]);
−97
int h = (int)sigil_as_fixnum(args[1]);
−98
−99
if (w <= 0 || h <= 0) {
−100
sigil__vm_error(vm, SIGIL_ERR_TYPE,
−101
"make-grid: dimensions must be positive");
−102
return SIGIL_UNDEFINED;
−103
}
−104
−105
Grid *g = malloc(sizeof(Grid));
−106
if (!g) return SIGIL_FALSE;
−107
−108
size_t size = (size_t)w * h * CELL_FIELDS;
−109
g->cells = malloc(size * sizeof(int32_t));
−110
if (!g->cells) {
−111
free(g);
−112
return SIGIL_FALSE;
−113
}
−114
−115
g->width = w;
−116
g->height = h;
−117
−118
/* Initialize all cells to defaults */
−119
for (size_t i = 0; i < (size_t)w * h; i++) {
−120
int32_t *cell = &g->cells[i * CELL_FIELDS];
−121
cell_clear(cell);
−122
}
−123
−124
return sigil_make_foreign(vm, grid_type_tag, g, grid_finalizer,
−125
sizeof(Grid) + size * sizeof(int32_t));
−126
}
−127
−128
/*
−129
* %grid-width grid -> integer
−130
*/
−131
static Value native_grid_width(SigilVM *vm, int argc, Value *args)
−132
{
−133
(void)vm; (void)argc;
−134
return sigil_fixnum(as_grid(args[0])->width);
−135
}
−136
−137
/*
−138
* %grid-height grid -> integer
−139
*/
−140
static Value native_grid_height(SigilVM *vm, int argc, Value *args)
−141
{
−142
(void)vm; (void)argc;
−143
return sigil_fixnum(as_grid(args[0])->height);
−144
}
−145
−146
/* Helper: allocate a 4-element Scheme vector for cell data */
−147
static Value make_cell_vector(SigilVM *vm, int32_t *cell)
−148
{
−149
SigilVector *vec = sigil__gc_alloc(vm, SIGIL_OBJ_VECTOR,
−150
sizeof(SigilVector) + 4 * sizeof(Value));
−151
vec->length = 4;
−152
vec->elements[0] = sigil_char((uint32_t)cell[CELL_CHAR]);
−153
vec->elements[1] = sigil_fixnum(cell[CELL_FG]);
−154
vec->elements[2] = sigil_fixnum(cell[CELL_BG]);
−155
vec->elements[3] = sigil_fixnum(cell[CELL_ATTRS]);
−156
return sigil_ptr(vec);
−157
}
−158
−159
/*
−160
* %grid-ref grid col row -> vector #(char fg bg attrs)
−161
*
−162
* Returns a fresh vector for compatibility with existing code.
−163
*/
−164
static Value native_grid_ref(SigilVM *vm, int argc, Value *args)
−165
{
−166
(void)argc;
−167
−168
Grid *g = as_grid(args[0]);
−169
int col = (int)sigil_as_fixnum(args[1]);
−170
int row = (int)sigil_as_fixnum(args[2]);
−171
−172
if (col < 0 || col >= g->width || row < 0 || row >= g->height) {
−173
sigil__vm_error(vm, SIGIL_ERR_TYPE,
−174
"grid-ref: index out of bounds");
−175
return SIGIL_UNDEFINED;
−176
}
−177
−178
return make_cell_vector(vm, cell_at(g, col, row));
−179
}
−180
−181
/*
−182
* %grid-set! grid col row ch fg bg attrs -> void
−183
*/
−184
static Value native_grid_set(SigilVM *vm, int argc, Value *args)
−185
{
−186
(void)argc;
−187
−188
Grid *g = as_grid(args[0]);
−189
int col = (int)sigil_as_fixnum(args[1]);
−190
int row = (int)sigil_as_fixnum(args[2]);
−191
−192
if (col < 0 || col >= g->width || row < 0 || row >= g->height) {
−193
/* Silently ignore out-of-bounds writes (truncation) */
−194
(void)vm;
−195
return SIGIL_UNDEFINED;
−196
}
−197
−198
int32_t *cell = cell_at(g, col, row);
−199
cell[CELL_CHAR] = (int32_t)sigil_as_char(args[3]);
−200
cell[CELL_FG] = (int32_t)sigil_as_fixnum(args[4]);
−201
cell[CELL_BG] = (int32_t)sigil_as_fixnum(args[5]);
−202
cell[CELL_ATTRS] = (int32_t)sigil_as_fixnum(args[6]);
−203
−204
return SIGIL_UNDEFINED;
−205
}
−206
−207
/*
−208
* %grid-clear! grid -> void
−209
*/
−210
static Value native_grid_clear(SigilVM *vm, int argc, Value *args)
−211
{
−212
(void)vm; (void)argc;
−213
−214
Grid *g = as_grid(args[0]);
−215
size_t count = (size_t)g->width * g->height;
−216
−217
for (size_t i = 0; i < count; i++) {
−218
int32_t *cell = &g->cells[i * CELL_FIELDS];
−219
cell_clear(cell);
−220
}
−221
−222
return SIGIL_UNDEFINED;
−223
}
−224
−225
/*
−226
* %grid-write-string! grid col row str fg bg attrs -> void
−227
*
−228
* Write a string to the grid at (col, row), truncating at the grid edge.
−229
*/
−230
static Value native_grid_write_string(SigilVM *vm, int argc, Value *args)
−231
{
−232
(void)vm; (void)argc;
−233
−234
Grid *g = as_grid(args[0]);
−235
int col = (int)sigil_as_fixnum(args[1]);
−236
int row = (int)sigil_as_fixnum(args[2]);
−237
/* args[3] = string */
−238
int32_t fg = (int32_t)sigil_as_fixnum(args[4]);
−239
int32_t bg = (int32_t)sigil_as_fixnum(args[5]);
−240
int32_t attrs = (int32_t)sigil_as_fixnum(args[6]);
−241
−242
if (row < 0 || row >= g->height || col >= g->width) {
−243
return SIGIL_UNDEFINED;
−244
}
−245
−246
SigilString *str = (SigilString *)sigil_as_ptr(args[3]);
−247
const char *data = str->data;
−248
size_t byte_len = str->byte_length;
−249
int w = g->width;
−250
int c = col;
−251
size_t pos = 0;
−252
−253
while (pos < byte_len && c < w) {
−254
/* Decode UTF-8 codepoint */
−255
uint32_t cp;
−256
uint8_t b = (uint8_t)data[pos];
−257
if (b < 0x80) {
−258
cp = b;
−259
pos += 1;
−260
} else if ((b & 0xE0) == 0xC0) {
−261
cp = (b & 0x1F) << 6;
−262
if (pos + 1 < byte_len) cp |= ((uint8_t)data[pos + 1] & 0x3F);
−263
pos += 2;
−264
} else if ((b & 0xF0) == 0xE0) {
−265
cp = (b & 0x0F) << 12;
−266
if (pos + 1 < byte_len) cp |= ((uint8_t)data[pos + 1] & 0x3F) << 6;
−267
if (pos + 2 < byte_len) cp |= ((uint8_t)data[pos + 2] & 0x3F);
−268
pos += 3;
−269
} else if ((b & 0xF8) == 0xF0) {
−270
cp = (b & 0x07) << 18;
−271
if (pos + 1 < byte_len) cp |= ((uint8_t)data[pos + 1] & 0x3F) << 12;
−272
if (pos + 2 < byte_len) cp |= ((uint8_t)data[pos + 2] & 0x3F) << 6;
−273
if (pos + 3 < byte_len) cp |= ((uint8_t)data[pos + 3] & 0x3F);
−274
pos += 4;
−275
} else {
−276
cp = '?';
−277
pos += 1;
−278
}
−279
−280
if (c >= 0) {
−281
int32_t *cell = cell_at(g, c, row);
−282
cell[CELL_CHAR] = (int32_t)cp;
−283
cell[CELL_FG] = fg;
−284
cell[CELL_BG] = bg;
−285
cell[CELL_ATTRS] = attrs;
−286
}
−287
c++;
−288
}
−289
−290
return SIGIL_UNDEFINED;
−291
}
−292
−293
/*
−294
* %grid-fill-rect! grid x y w h ch fg bg attrs -> void
−295
*/
−296
static Value native_grid_fill_rect(SigilVM *vm, int argc, Value *args)
−297
{
−298
(void)vm; (void)argc;
−299
−300
Grid *g = as_grid(args[0]);
−301
int x = (int)sigil_as_fixnum(args[1]);
−302
int y = (int)sigil_as_fixnum(args[2]);
−303
int w = (int)sigil_as_fixnum(args[3]);
−304
int h = (int)sigil_as_fixnum(args[4]);
−305
int32_t ch = (int32_t)sigil_as_char(args[5]);
−306
int32_t fg = (int32_t)sigil_as_fixnum(args[6]);
−307
int32_t bg = (int32_t)sigil_as_fixnum(args[7]);
−308
int32_t attrs = (int32_t)sigil_as_fixnum(args[8]);
−309
−310
int gw = g->width;
−311
int gh = g->height;
−312
−313
for (int r = y; r < y + h && r < gh; r++) {
−314
if (r < 0) continue;
−315
for (int c = x; c < x + w && c < gw; c++) {
−316
if (c < 0) continue;
−317
int32_t *cell = cell_at(g, c, r);
−318
cell[CELL_CHAR] = ch;
−319
cell[CELL_FG] = fg;
−320
cell[CELL_BG] = bg;
−321
cell[CELL_ATTRS] = attrs;
−322
}
−323
}
−324
−325
return SIGIL_UNDEFINED;
−326
}
−327
−328
/*
−329
* %grid-copy grid -> grid
−330
*
−331
* Create a deep copy of a grid.
−332
*/
−333
static Value native_grid_copy(SigilVM *vm, int argc, Value *args)
−334
{
−335
(void)argc;
−336
−337
Grid *src = as_grid(args[0]);
−338
Grid *dst = malloc(sizeof(Grid));
−339
if (!dst) return SIGIL_FALSE;
−340
−341
size_t size = (size_t)src->width * src->height * CELL_FIELDS;
−342
dst->cells = malloc(size * sizeof(int32_t));
−343
if (!dst->cells) {
−344
free(dst);
−345
return SIGIL_FALSE;
−346
}
−347
−348
dst->width = src->width;
−349
dst->height = src->height;
−350
memcpy(dst->cells, src->cells, size * sizeof(int32_t));
−351
−352
return sigil_make_foreign(vm, grid_type_tag, dst, grid_finalizer,
−353
sizeof(Grid) + size * sizeof(int32_t));
−354
}
−355
−356
/* ============================================================
−357
* Grid diffing — the performance-critical hot path
−358
*
−359
* Scans cell-by-cell, emitting minimal ANSI escape sequences to
−360
* update only changed cells. Returns a string to write atomically
−361
* via terminal-write-raw.
−362
* ============================================================ */
−363
−364
/* Dynamic buffer for building diff output */
−365
typedef struct {
−366
char *data;
−367
size_t len;
−368
size_t cap;
−369
} DiffBuf;
−370
−371
static void buf_init(DiffBuf *buf)
−372
{
−373
buf->cap = 4096;
−374
buf->data = malloc(buf->cap);
−375
buf->len = 0;
−376
}
−377
−378
static void buf_ensure(DiffBuf *buf, size_t need)
−379
{
−380
if (buf->len + need > buf->cap) {
−381
while (buf->len + need > buf->cap) {
−382
buf->cap *= 2;
−383
}
−384
buf->data = realloc(buf->data, buf->cap);
−385
}
−386
}
−387
−388
static void buf_append(DiffBuf *buf, const char *str, size_t len)
−389
{
−390
buf_ensure(buf, len);
−391
memcpy(buf->data + buf->len, str, len);
−392
buf->len += len;
−393
}
−394
−395
static void buf_append_str(DiffBuf *buf, const char *str)
−396
{
−397
buf_append(buf, str, strlen(str));
−398
}
−399
−400
static void buf_append_int(DiffBuf *buf, int n)
−401
{
−402
char tmp[16];
−403
int len = snprintf(tmp, sizeof(tmp), "%d", n);
−404
buf_append(buf, tmp, len);
−405
}
−406
−407
static void buf_append_char_utf8(DiffBuf *buf, uint32_t cp)
−408
{
−409
char tmp[4];
−410
int len;
−411
if (cp < 0x80) {
−412
tmp[0] = (char)cp;
−413
len = 1;
−414
} else if (cp < 0x800) {
−415
tmp[0] = (char)(0xC0 | (cp >> 6));
−416
tmp[1] = (char)(0x80 | (cp & 0x3F));
−417
len = 2;
−418
} else if (cp < 0x10000) {
−419
tmp[0] = (char)(0xE0 | (cp >> 12));
−420
tmp[1] = (char)(0x80 | ((cp >> 6) & 0x3F));
−421
tmp[2] = (char)(0x80 | (cp & 0x3F));
−422
len = 3;
−423
} else {
−424
tmp[0] = (char)(0xF0 | (cp >> 18));
−425
tmp[1] = (char)(0x80 | ((cp >> 12) & 0x3F));
−426
tmp[2] = (char)(0x80 | ((cp >> 6) & 0x3F));
−427
tmp[3] = (char)(0x80 | (cp & 0x3F));
−428
len = 4;
−429
}
−430
buf_append(buf, tmp, len);
−431
}
−432
−433
/* Emit foreground color SGR to buffer */
−434
static void emit_fg(DiffBuf *buf, int32_t color)
−435
{
−436
if (color == -1) {
−437
buf_append_str(buf, "39");
−438
} else if (color >= 0 && color <= 7) {
−439
buf_append_int(buf, color + 30);
−440
} else if (color >= 8 && color <= 15) {
−441
buf_append_int(buf, color + 82); /* 90-97 */
−442
} else if (color >= 16 && color <= 255) {
−443
buf_append_str(buf, "38;5;");
−444
buf_append_int(buf, color);
−445
} else {
−446
/* Truecolor: decode packed RGB */
−447
int v = color - 65536; /* undo +1 offset from color-rgb */
−448
int r = v / 65536;
−449
int rem = v % 65536;
−450
int g = rem / 256;
−451
int b = rem % 256;
−452
buf_append_str(buf, "38;2;");
−453
buf_append_int(buf, r);
−454
buf_append(buf, ";", 1);
−455
buf_append_int(buf, g);
−456
buf_append(buf, ";", 1);
−457
buf_append_int(buf, b);
−458
}
−459
}
−460
−461
/* Emit background color SGR to buffer */
−462
static void emit_bg(DiffBuf *buf, int32_t color)
−463
{
−464
if (color == -1) {
−465
buf_append_str(buf, "49");
−466
} else if (color >= 0 && color <= 7) {
−467
buf_append_int(buf, color + 40);
−468
} else if (color >= 8 && color <= 15) {
−469
buf_append_int(buf, color + 92); /* 100-107 */
−470
} else if (color >= 16 && color <= 255) {
−471
buf_append_str(buf, "48;5;");
−472
buf_append_int(buf, color);
−473
} else {
−474
int v = color - 65536;
−475
int r = v / 65536;
−476
int rem = v % 65536;
−477
int g = rem / 256;
−478
int b = rem % 256;
−479
buf_append_str(buf, "48;2;");
−480
buf_append_int(buf, r);
−481
buf_append(buf, ";", 1);
−482
buf_append_int(buf, g);
−483
buf_append(buf, ";", 1);
−484
buf_append_int(buf, b);
−485
}
−486
}
−487
−488
/* Emit attribute codes to buffer */
−489
static void emit_attrs(DiffBuf *buf, int32_t attrs)
−490
{
−491
if (attrs & ATTR_BOLD) buf_append_str(buf, ";1");
−492
if (attrs & ATTR_DIM) buf_append_str(buf, ";2");
−493
if (attrs & ATTR_ITALIC) buf_append_str(buf, ";3");
−494
if (attrs & ATTR_UNDERLINE) buf_append_str(buf, ";4");
−495
if (attrs & ATTR_INVERSE) buf_append_str(buf, ";7");
−496
if (attrs & ATTR_STRIKETHROUGH) buf_append_str(buf, ";9");
−497
}
−498
−499
/* Emit full SGR for a cell */

Showing the first 500 of 678 diff lines for this file. This diff is INCOMPLETE; read the file or clone the repository for the rest.