mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-20 15:35:03 +02:00
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:
@@ -224,6 +224,14 @@ typedef struct {
|
|||||||
} GPUCell;
|
} GPUCell;
|
||||||
static_assert(sizeof(GPUCell) == 20, "Fix the ordering of 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 {
|
typedef struct {
|
||||||
char_type ch;
|
char_type ch;
|
||||||
hyperlink_id_type hyperlink_id;
|
hyperlink_id_type hyperlink_id;
|
||||||
|
|||||||
116
kitty/text-cache.c
Normal file
116
kitty/text-cache.c
Normal 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
26
kitty/text-cache.h
Normal 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);
|
||||||
Reference in New Issue
Block a user