mbswidth -> ncstrwidth() #985

This commit is contained in:
nick black 2020-09-15 01:39:42 -04:00
parent dab7247cdd
commit 4bb1f3fc85
12 changed files with 49 additions and 48 deletions

View File

@ -2,6 +2,7 @@ This document attempts to list user-visible changes and any major internal
rearrangements of Notcurses.
* 1.7.3 (not yet released)
* `mbswidth()` has been renamed `ncstrwidth()`.
* The long-promised/dreaded Great Widget Review, normalizing behavior across
all widgets, has been effected. Sorry, there was no getting around this
one. Pretty much all widgets have slightly changed, because pretty much all

View File

@ -114,7 +114,7 @@ typedef struct cell {
**bool cell_bg_default_p(const cell* cl);**
**int mbswidth(const char* text)**;
**int ncstrwidth(const char* text)**;
# DESCRIPTION

View File

@ -17,7 +17,7 @@ notcurses_metric - fixed-width numeric output with metric suffixes
#define PREFIXSTRLEN (PREFIXCOLUMNS + 1)
#define IPREFIXSTRLEN (IPREFIXCOLUMNS + 1)
#define BPREFIXSTRLEN (BPREFIXCOLUMNS + 1)
#define NCMETRICFWIDTH(x, cols) ((int)(strlen(x) - mbswidth(x) + (cols)))
#define NCMETRICFWIDTH(x, cols) ((int)(strlen(x) - ncstrwidth(x) + (cols)))
#define PREFIXFMT(x) NCMETRICFWIDTH((x), PREFIXCOLUMNS), (x)
#define IPREFIXFMT(x) NCMETRIXFWIDTH((x), IPREFIXCOLUMNS), (x)
#define BPREFIXFMT(x) NCMETRICFWIDTH((x), BPREFIXCOLUMNS), (x)

View File

@ -85,7 +85,7 @@ typedef enum {
// Returns the number of columns occupied by a multibyte (UTF-8) string, or
// -1 if a non-printable/illegal character is encountered.
API int mbswidth(const char* mbs);
API int ncstrwidth(const char* mbs);
// input functions like notcurses_getc() return ucs32-encoded char32_t. convert
// a series of char32_t to utf8. result must be at least 4 bytes per input
@ -2530,7 +2530,7 @@ API struct ncplane* nctablet_ncplane(struct nctablet* t);
#define BPREFIXSTRLEN (BPREFIXCOLUMNS + 1) // Does not include a '\0' (xxxx.xxUi), i == prefix
// Used as arguments to a variable field width (i.e. "%*s" -- these are the *).
// We need this convoluted grotesquery to properly handle 'µ'.
#define NCMETRICFWIDTH(x, cols) ((int)(strlen(x) - mbswidth(x) + (cols)))
#define NCMETRICFWIDTH(x, cols) ((int)(strlen(x) - ncstrwidth(x) + (cols)))
#define PREFIXFMT(x) NCMETRICFWIDTH((x), PREFIXCOLUMNS), (x)
#define IPREFIXFMT(x) NCMETRIXFWIDTH((x), IPREFIXCOLUMNS), (x)
#define BPREFIXFMT(x) NCMETRICFWIDTH((x), BPREFIXCOLUMNS), (x)

View File

@ -3508,8 +3508,8 @@ unicode7emoji2(struct ncplane* title, int y){
struct ncplane*
makegroup(struct ncplane* title, int y, const char* emoji, const char* name){
int cols = mbswidth(emoji);
if(cols < 0){ // take a wild guess on mbswidth() error from old libcs, sigh.
int cols = ncstrwidth(emoji);
if(cols < 0){ // take a wild guess on ncstrwidth() error from old libcs, sigh.
cols = strlen(emoji) * 3 / 5; // best by test
}
struct ncplane* n = mojiplane(title, y, 3 + cols / (planewidth - 12), name);

View File

@ -62,7 +62,7 @@ dup_menu_item(ncmenu_int_item* dst, const struct ncmenu_item* src){
}
sdup[n + mbbytes] = '\0';
dst->shortdesc = sdup;
dst->shortdesccols = mbswidth(dst->shortdesc);
dst->shortdesccols = ncstrwidth(dst->shortdesc);
return 0;
#undef CTLMOD
#undef ALTMOD
@ -94,7 +94,7 @@ dup_menu_section(ncmenu_int_section* dst, const struct ncmenu_section* src){
return -1;
}
gotitem = true;
int cols = mbswidth(dst->items[i].desc);
int cols = ncstrwidth(dst->items[i].desc);
if(dst->items[i].shortdesc){
cols += 2 + dst->items[i].shortdesccols; // two spaces minimum
}
@ -140,7 +140,7 @@ dup_menu_sections(ncmenu* ncm, const ncmenu_options* opts, int* totalwidth, int*
int i;
for(i = 0 ; i < opts->sectioncount ; ++i){
if(opts->sections[i].name){
int cols = mbswidth(opts->sections[i].name);
int cols = ncstrwidth(opts->sections[i].name);
if(rightaligned){ // FIXME handle more than one right-aligned section
ncm->sections[i].xoff = -(cols + 2);
}else{
@ -212,14 +212,14 @@ section_x(const ncmenu* ncm, int x){
if(x < pos){
break;
}
if(x < pos + mbswidth(ncm->sections[i].name)){
if(x < pos + ncstrwidth(ncm->sections[i].name)){
return i;
}
}else{
if(x < ncm->sections[i].xoff){
break;
}
if(x < ncm->sections[i].xoff + mbswidth(ncm->sections[i].name)){
if(x < ncm->sections[i].xoff + ncstrwidth(ncm->sections[i].name)){
return i;
}
}
@ -274,7 +274,7 @@ write_header(ncmenu* ncm){ ncm->ncp->channels = ncm->headerchannels;
}
cell_release(ncm->ncp, &cl);
}
xoff += mbswidth(ncm->sections[i].name);
xoff += ncstrwidth(ncm->sections[i].name);
}
}
while(xoff < dimx){

View File

@ -2356,7 +2356,7 @@ int notcurses_ucs32_to_utf8(const char32_t* ucs32, unsigned ucs32count,
return buflen;
}
int mbswidth(const char* mbs){
int ncstrwidth(const char* mbs){
int cols = 0; // number of columns consumed thus far
do{
int thesecols, thesebytes;

View File

@ -178,7 +178,7 @@ int ncreader_move_down(ncreader* n){
// only writing can enlarge the textarea. movement can pan, but not enlarge.
int ncreader_write_egc(ncreader* n, const char* egc){
const int cols = mbswidth(egc);
const int cols = ncstrwidth(egc);
if(cols < 0){
logerror(n->ncp->nc, "Fed illegal UTF-8 [%s]\n", egc);
return -1;

View File

@ -253,11 +253,11 @@ ncselector* ncselector_create(ncplane* n, const ncselector_options* opts){
goto freeitems;
}
ns->title = opts->title ? strdup(opts->title) : NULL;
ns->titlecols = opts->title ? mbswidth(opts->title) : 0;
ns->titlecols = opts->title ? ncstrwidth(opts->title) : 0;
ns->secondary = opts->secondary ? strdup(opts->secondary) : NULL;
ns->secondarycols = opts->secondary ? mbswidth(opts->secondary) : 0;
ns->secondarycols = opts->secondary ? ncstrwidth(opts->secondary) : 0;
ns->footer = opts->footer ? strdup(opts->footer) : NULL;
ns->footercols = opts->footer ? mbswidth(opts->footer) : 0;
ns->footercols = opts->footer ? ncstrwidth(opts->footer) : 0;
ns->selected = opts->defidx;
ns->longop = 0;
if( (ns->maxdisplay = opts->maxdisplay) ){
@ -286,12 +286,12 @@ ncselector* ncselector_create(ncplane* n, const ncselector_options* opts){
}
for(ns->itemcount = 0 ; ns->itemcount < itemcount ; ++ns->itemcount){
const struct ncselector_item* src = &opts->items[ns->itemcount];
int cols = mbswidth(src->option);
int cols = ncstrwidth(src->option);
ns->items[ns->itemcount].opcolumns = cols;
if(cols > ns->longop){
ns->longop = cols;
}
cols = mbswidth(src->desc);
cols = ncstrwidth(src->desc);
ns->items[ns->itemcount].desccolumns = cols;
if(cols > ns->longdesc){
ns->longdesc = cols;
@ -337,12 +337,12 @@ int ncselector_additem(ncselector* n, const struct ncselector_item* item){
n->items = items;
n->items[n->itemcount].option = strdup(item->option);
n->items[n->itemcount].desc = strdup(item->desc);
int cols = mbswidth(item->option);
int cols = ncstrwidth(item->option);
n->items[n->itemcount].opcolumns = cols;
if(cols > n->longop){
n->longop = cols;
}
cols = mbswidth(item->desc);
cols = ncstrwidth(item->desc);
n->items[n->itemcount].desccolumns = cols;
if(cols > n->longdesc){
n->longdesc = cols;
@ -376,11 +376,11 @@ int ncselector_delitem(ncselector* n, const char* item){
found = true;
--idx;
}else{
int cols = mbswidth(n->items[idx].option);
int cols = ncstrwidth(n->items[idx].option);
if(cols > maxop){
maxop = cols;
}
cols = mbswidth(n->items[idx].desc);
cols = ncstrwidth(n->items[idx].desc);
if(cols > maxdesc){
maxdesc = cols;
}
@ -841,11 +841,11 @@ ncmultiselector* ncmultiselector_create(ncplane* n, const ncmultiselector_option
}
ncmultiselector* ns = malloc(sizeof(*ns));
ns->title = opts->title ? strdup(opts->title) : NULL;
ns->titlecols = opts->title ? mbswidth(opts->title) : 0;
ns->titlecols = opts->title ? ncstrwidth(opts->title) : 0;
ns->secondary = opts->secondary ? strdup(opts->secondary) : NULL;
ns->secondarycols = opts->secondary ? mbswidth(opts->secondary) : 0;
ns->secondarycols = opts->secondary ? ncstrwidth(opts->secondary) : 0;
ns->footer = opts->footer ? strdup(opts->footer) : NULL;
ns->footercols = opts->footer ? mbswidth(opts->footer) : 0;
ns->footercols = opts->footer ? ncstrwidth(opts->footer) : 0;
ns->current = 0;
ns->startdisp = 0;
ns->longitem = 0;
@ -866,11 +866,11 @@ ncmultiselector* ncmultiselector_create(ncplane* n, const ncmultiselector_option
}
for(ns->itemcount = 0 ; ns->itemcount < itemcount ; ++ns->itemcount){
const struct ncmselector_item* src = &opts->items[ns->itemcount];
int cols = mbswidth(src->option);
int cols = ncstrwidth(src->option);
if(cols > ns->longitem){
ns->longitem = cols;
}
int cols2 = mbswidth(src->desc);
int cols2 = ncstrwidth(src->desc);
if(cols + cols2 > ns->longitem){
ns->longitem = cols + cols2;
}

View File

@ -42,21 +42,21 @@ TEST_CASE("Cell") {
}
SUBCASE("MultibyteWidth") {
CHECK(0 == mbswidth("")); // zero bytes, zero columns
CHECK(0 == mbswidth("\x7")); // single byte, non-printable
CHECK(1 == mbswidth(" ")); // single byte, one column
CHECK(5 == mbswidth("abcde")); // single byte, one column
CHECK(1 == mbswidth("µ")); // two bytes, one column
CHECK(1 <= mbswidth("\xf0\x9f\xa6\xb2")); // four bytes, two columns
CHECK(3 <= mbswidth("平仮名")); // nine bytes, six columns
CHECK(1 == mbswidth("\ufdfd")); // three bytes, ? columns, wcwidth() returns 1
CHECK(0 == ncstrwidth("")); // zero bytes, zero columns
CHECK(0 == ncstrwidth("\x7")); // single byte, non-printable
CHECK(1 == ncstrwidth(" ")); // single byte, one column
CHECK(5 == ncstrwidth("abcde")); // single byte, one column
CHECK(1 == ncstrwidth("µ")); // two bytes, one column
CHECK(1 <= ncstrwidth("\xf0\x9f\xa6\xb2")); // four bytes, two columns
CHECK(3 <= ncstrwidth("平仮名")); // nine bytes, six columns
CHECK(1 == ncstrwidth("\ufdfd")); // three bytes, ? columns, wcwidth() returns 1
}
// test combining characters and ZWJs
SUBCASE("MultiglyphWidth") {
CHECK(2 == mbswidth("\U0001F471"));
CHECK(2 == mbswidth("\U0001F471\u200D"));
CHECK(3 == mbswidth("\U0001F471\u200D\u2640")); // *not* a single EGC!
CHECK(2 == ncstrwidth("\U0001F471"));
CHECK(2 == ncstrwidth("\U0001F471\u200D"));
CHECK(3 == ncstrwidth("\U0001F471\u200D\u2640")); // *not* a single EGC!
}
SUBCASE("SetItalic") {

View File

@ -360,7 +360,7 @@ TEST_CASE("NCPlane") {
REQUIRE(0 < u2);
REQUIRE(strlen(w1) == u1);
REQUIRE(strlen(w2) == u2);
CHECK(mbswidth(w1) == 1 + cell_double_wide_p(&c1));
CHECK(ncstrwidth(w1) == 1 + cell_double_wide_p(&c1));
CHECK_FALSE(cell_double_wide_p(&c2));
cell_release(n_, &c1);
cell_release(n_, &c2);

View File

@ -126,13 +126,13 @@ TEST_CASE("Wide") {
ncplane_at_yx_cell(n_, 0, 0, &c);
CHECK(0 == strcmp(cell_extended_gcluster(n_, &c), FROG));
ncplane_at_yx_cell(n_, 0, 1, &c);
CHECK(mbswidth(FROG) == 1 + cell_double_wide_p(&c)); // should be wide
CHECK(ncstrwidth(FROG) == 1 + cell_double_wide_p(&c)); // should be wide
ncplane_at_yx_cell(n_, 0, 2, &c);
CHECK(0 == strlen(cell_extended_gcluster(n_, &c))); // should be nothing
ncplane_at_yx_cell(n_, 1, 0, &c);
CHECK(0 == strcmp(cell_extended_gcluster(n_, &c), FROG));
ncplane_at_yx_cell(n_, 1, 1, &c);
CHECK(mbswidth(FROG) == 1 + cell_double_wide_p(&c)); //should be wide
CHECK(ncstrwidth(FROG) == 1 + cell_double_wide_p(&c)); //should be wide
ncplane_at_yx_cell(n_, 0, 2, &c);
CHECK(0 == strlen(cell_extended_gcluster(n_, &c)));
CHECK(0 == notcurses_render(nc_)); // should be nothing
@ -160,7 +160,7 @@ TEST_CASE("Wide") {
ncplane_at_yx_cell(n_, 0, 1, &c);
CHECK(0 == strcmp(cell_extended_gcluster(n_, &c), SNAKE));
ncplane_at_yx_cell(n_, 0, 2, &c);
CHECK(mbswidth(SNAKE) == 1 + cell_double_wide_p(&c)); // should be wide
CHECK(ncstrwidth(SNAKE) == 1 + cell_double_wide_p(&c)); // should be wide
CHECK(0 == notcurses_render(nc_));
}
@ -181,7 +181,7 @@ TEST_CASE("Wide") {
CHECK(3 == x);
cell c = CELL_TRIVIAL_INITIALIZER;
ncplane_at_yx_cell(n_, 0, 0, &c);
if(mbswidth(wbashedl) > 1){
if(ncstrwidth(wbashedl) > 1){
CHECK(0 == c.gcluster); // should be nothing
}
ncplane_at_yx_cell(n_, 0, 1, &c);
@ -189,7 +189,7 @@ TEST_CASE("Wide") {
ncplane_at_yx_cell(n_, 0, 2, &c);
CHECK(0 == strcmp(cc, cell_extended_gcluster(n_, &c))); // should be 'X'
ncplane_at_yx_cell(n_, 0, 3, &c);
if(mbswidth(wbashedr) > 1){
if(ncstrwidth(wbashedr) > 1){
CHECK(0 == strlen(cell_extended_gcluster(n_, &c))); // should be nothing
}
CHECK(0 == notcurses_render(nc_));
@ -213,13 +213,13 @@ TEST_CASE("Wide") {
ncplane_at_yx_cell(n_, 0, 0, &c);
CHECK(0 == strcmp(cell_extended_gcluster(n_, &c), SNAKE));
ncplane_at_yx_cell(n_, 0, 1, &c);
CHECK(mbswidth(SNAKE) == 1 + cell_double_wide_p(&c));
CHECK(ncstrwidth(SNAKE) == 1 + cell_double_wide_p(&c));
ncplane_at_yx_cell(n_, 0, 2, &c);
CHECK(0 == strcmp(cc, cell_extended_gcluster(n_, &c))); // should be 'X'
ncplane_at_yx_cell(n_, 0, 3, &c);
CHECK(0 == strcmp(cell_extended_gcluster(n_, &c), SCORPION));
ncplane_at_yx_cell(n_, 0, 4, &c);
CHECK(mbswidth(SCORPION) == 1 + cell_double_wide_p(&c));
CHECK(ncstrwidth(SCORPION) == 1 + cell_double_wide_p(&c));
CHECK(0 == notcurses_render(nc_));
}
@ -229,7 +229,7 @@ TEST_CASE("Wide") {
int dimx, dimy;
ncplane_dim_yx(n_, &dimy, &dimx);
CHECK(0 == ncplane_rounded_box_sized(ncp, 0, 0, 3, 4, 0));
CHECK(mbswidth(SCORPION) == ncplane_putegc_yx(ncp, 1, 1, SCORPION, nullptr));
CHECK(ncstrwidth(SCORPION) == ncplane_putegc_yx(ncp, 1, 1, SCORPION, nullptr));
CHECK(0 == notcurses_render(nc_));
cell c = CELL_TRIVIAL_INITIALIZER;
CHECK(0 < ncplane_at_yx_cell(ncp, 1, 0, &c));