egcpool: copy in nonspacing characters of an EGC #32

This commit is contained in:
nick black 2019-11-25 13:36:52 -05:00 committed by Nick Black
parent 6f92ae92ab
commit 9744ca0d4c
2 changed files with 47 additions and 17 deletions

View File

@ -1,6 +1,7 @@
#ifndef NOTCURSES_EGCPOOL
#define NOTCURSES_EGCPOOL
#include <wchar.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
@ -29,15 +30,36 @@ egcpool_init(egcpool* p){
int egcpool_grow(egcpool* pool, size_t len);
// FIXME needs to loop on wcwidth() == 0
// Eat an EGC from the UTF-8 string input. This consists of extracting a
// multibyte via mbtowc, then continuing to extract any which have zero
// width until hitting another spacing character or a NUL terminator. Writes
// the number of columns occupied to '*colcount'. Returns the number of bytes
// consumed, not including any NUL terminator. Note that neither the number
// of bytes nor columns is necessarily equivalent to the number of decoded code
// points. Such are the ways of Unicode.
static inline size_t
utf8_gce_len(const char* gcluster){
utf8_gce_len(const char* gcluster, int* colcount){
size_t ret = 0;
*colcount = 0;
wchar_t wc;
int r = mbtowc(&wc, gcluster, MB_CUR_MAX);
if(r <= 0){
return 0; // will cascade into error in egcpool_stash()
}
return r;
int r;
do{
r = mbtowc(&wc, gcluster, MB_CUR_MAX);
if(r < 0){
return -1;
}else if(r){
int cols = wcwidth(wc);
if(cols){
if(*colcount){ // this must be starting a new EGC, exit and do not claim
break;
}
*colcount += cols;
}
ret += r;
gcluster += r;
}
}while(r);
return ret;
}
// if we're inserting a EGC of |len| bytes, ought we proactively realloc?
@ -57,10 +79,11 @@ egcpool_alloc_justified(const egcpool* pool, size_t len){
// stash away the provided UTF8, NUL-terminated grapheme cluster. the cluster
// should not be less than 2 bytes (such a cluster should be directly stored in
// the cell). returns -1 on error, and otherwise a non-negative 24-bit offset.
// The number of bytes copied is stored to |*ulen|.
// The number of bytes copied is stored to '*ulen'. The number of presentation
// columns is stored to '*cols'.
static inline int
egcpool_stash(egcpool* pool, const char* egc, size_t* ulen){
size_t len = utf8_gce_len(egc) + 1; // count the NUL terminator
egcpool_stash(egcpool* pool, const char* egc, size_t* ulen, int* cols){
size_t len = utf8_gce_len(egc, cols) + 1; // count the NUL terminator
if(len <= 2){ // should never be empty, nor a single byte + NUL
return -1;
}

View File

@ -602,15 +602,19 @@ term_putc(const notcurses* nc, const ncplane* n, const cell* c){
}
static void
advance_cursor(ncplane* n){
advance_cursor(ncplane* n, int cols){
if(n->y == n->leny){
if(n->x == n->lenx){
return; // stuck!
}
}
if(++n->x == n->lenx){
n->x = 0;
++n->y;
if((n->x += cols) >= n->lenx){
if(n->y == n->leny){
n->x = n->lenx;
}else{
n->x -= n->lenx;
++n->y;
}
}
}
@ -683,7 +687,9 @@ cell_duplicate(ncplane* n, cell* targ, const cell* c){
return !!c->gcluster;
}
size_t ulen;
int eoffset = egcpool_stash(&n->pool, extended_gcluster(n, c), &ulen);
int cols;
// FIXME insert colcount into cell...
int eoffset = egcpool_stash(&n->pool, extended_gcluster(n, c), &ulen, &cols);
if(eoffset < 0){
return -1;
}
@ -697,7 +703,7 @@ int ncplane_putc(ncplane* n, const cell* c){
}
cell* targ = &n->fb[fbcellidx(n, n->y, n->x)];
int ret = cell_duplicate(n, targ, c);
advance_cursor(n);
advance_cursor(n, 1); // FIXME
return ret;
}
@ -732,7 +738,8 @@ int cell_load(ncplane* n, cell* c, const char* gcluster){
return !!c->gcluster;
}
size_t ulen;
int eoffset = egcpool_stash(&n->pool, gcluster, &ulen);
int cols;
int eoffset = egcpool_stash(&n->pool, gcluster, &ulen, &cols);
if(eoffset < 0){
return -1;
}