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 #ifndef NOTCURSES_EGCPOOL
#define NOTCURSES_EGCPOOL #define NOTCURSES_EGCPOOL
#include <wchar.h>
#include <stddef.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -29,15 +30,36 @@ egcpool_init(egcpool* p){
int egcpool_grow(egcpool* pool, size_t len); 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 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; wchar_t wc;
int r = mbtowc(&wc, gcluster, MB_CUR_MAX); int r;
if(r <= 0){ do{
return 0; // will cascade into error in egcpool_stash() r = mbtowc(&wc, gcluster, MB_CUR_MAX);
} if(r < 0){
return r; 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? // 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 // 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 // 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 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 static inline int
egcpool_stash(egcpool* pool, const char* egc, size_t* ulen){ egcpool_stash(egcpool* pool, const char* egc, size_t* ulen, int* cols){
size_t len = utf8_gce_len(egc) + 1; // count the NUL terminator 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 if(len <= 2){ // should never be empty, nor a single byte + NUL
return -1; return -1;
} }

View File

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