Start work on allowing unlimited codepoints per cell

This is needed to properly support zero-width joiner based emoji
sequences.
This commit is contained in:
Kovid Goyal 2024-07-14 12:56:43 +05:30
parent 7a35cb2d8f
commit b50ba1ac73
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 150 additions and 0 deletions

View File

@ -220,6 +220,14 @@ typedef struct {
} GPUCell;
static_assert(sizeof(GPUCell) == 20, "Fix the ordering of GPUCell");
typedef union CharOrIndex {
struct {
char_type ch_is_index: 1;
char_type ch: sizeof(char_type) - 1;
};
char_type val;
} CharOrIndex;
typedef struct {
char_type ch;
hyperlink_id_type hyperlink_id;

116
kitty/text-cache.c Normal file
View File

@ -0,0 +1,116 @@
/*
* text-cache.c
* Copyright (C) 2024 Kovid Goyal <kovid at kovidgoyal.net>
*
* Distributed under terms of the GPL3 license.
*/
#include "data-types.h"
typedef struct Chars {
size_t count;
const char_type *chars;
} Chars;
#define NAME chars_map
#define KEY_TY Chars
#define VAL_TY CharOrIndex
static uint64_t hash_chars(Chars k);
static bool cmpr_chars(Chars a, Chars b);
#define HASH_FN hash_chars
#define CMPR_FN cmpr_chars
#include "kitty-verstable.h"
typedef struct TextCache {
struct { Chars *items; size_t count, capacity; } array;
chars_map map;
unsigned refcnt;
} TextCache;
static uint64_t hash_chars(Chars k) { return vt_hash_bytes(k.chars, sizeof(k.chars[0]) * k.count); }
static bool cmpr_chars(Chars a, Chars b) { return a.count == b.count && memcmp(a.chars, b.chars, sizeof(a.chars[0]) * a.count) == 0; }
#define TEXT_CACHE_IMPLEMENTATION
#include "text-cache.h"
TextCache*
tc_alloc(void) {
TextCache *ans = calloc(1, sizeof(TextCache));
if (!ans) return NULL;
ans->array.capacity = 256;
ans->array.items = malloc(ans->array.capacity * sizeof(ans->array.items[0]));
if (!ans->array.items) { free(ans); ans = NULL; return ans; }
vt_init(&ans->map);
ans->refcnt = 1;
return ans;
}
void
tc_clear(TextCache *ans) {
ans->array.count = 0;
vt_cleanup(&ans->map);
}
static void
free_text_cache(TextCache *self) {
vt_cleanup(&self->map);
for (size_t i = 0; i < self->array.count; i++) free((char_type*)self->array.items[i].chars);
free(self->array.items);
free(self);
}
TextCache*
tc_incref(TextCache *self) { if (self) { self->refcnt++; } return self; }
TextCache*
tc_decref(TextCache *self) {
if (self) {
if (self->refcnt < 2) free_text_cache(self);
else self->refcnt--;
}
return NULL;
}
void
tc_chars_at_index(const TextCache *self, CharOrIndex idx, ListOfChars *ans) {
if (idx.ch_is_index) {
if (self->array.count > idx.ch) {
ans->count = self->array.items[idx.ch].count;
ensure_space_for(ans, chars, char_type, ans->count, capacity, 8, false);
memcpy(ans->chars, self->array.items[idx.ch].chars, sizeof(ans->chars[0]) * ans->count);
} else {
ans->count = 0;
}
} else {
ans->count = 1;
ensure_space_for(ans, chars, char_type, 1, capacity, 8, false);
ans->chars[0] = idx.ch;
}
}
static CharOrIndex
copy_and_insert(TextCache *self, const Chars key) {
if (self->array.count >= (1llu << (8*sizeof(char_type) - 1)) - 1) fatal("Too many items in TextCache");
ensure_space_for(&(self->array), items, Chars, self->array.count + 1, capacity, 256, false);
char_type *copy = malloc(key.count * sizeof(key.chars[0]));
if (!copy) fatal("Out of memory");
memcpy(copy, key.chars, key.count * sizeof(key.chars[0]));
CharOrIndex ans;
ans.ch_is_index = 1; ans.ch = self->array.count;
Chars *k = self->array.items + self->array.count++;
k->count = key.count; k->chars = copy;
chars_map_itr i = vt_insert(&self->map, *k, ans);
if (vt_is_end(i)) fatal("Out of memory");
return ans;
}
CharOrIndex
tc_get_or_insert_chars(TextCache *self, const ListOfChars *chars) {
if (chars->count == 1) {
CharOrIndex ans = {0};
ans.ch = chars->chars[0];
return ans;
}
Chars key = {.count=chars->count, .chars=chars->chars};
chars_map_itr i = vt_get(&self->map, key);
if (vt_is_end(i)) return copy_and_insert(self, key);
return i.data->val;
}

26
kitty/text-cache.h Normal file
View File

@ -0,0 +1,26 @@
/*
* text-cache.h
* Copyright (C) 2024 Kovid Goyal <kovid at kovidgoyal.net>
*
* Distributed under terms of the GPL3 license.
*/
#pragma once
#include "data-types.h"
typedef struct ListOfChars {
char_type *chars;
size_t count, capacity;
} ListOfChars;
#ifndef TEXT_CACHE_IMPLEMENTATION
typedef struct {int x; } *TextCache;
#endif
TextCache* tc_alloc(void);
TextCache* tc_incref(TextCache *self);
TextCache* tc_decref(TextCache *self);
void tc_clear(TextCache *ans);
void tc_chars_at_index(const TextCache *self, CharOrIndex idx, ListOfChars *ans);
CharOrIndex tc_get_or_insert_chars(TextCache *self, const ListOfChars *chars);