notcurses_puttext: use libunistring for wordbreaking #772

This commit is contained in:
nick black 2020-07-22 03:30:02 -04:00 committed by Nick Black
parent 0ba1512d68
commit 604747c8f2
7 changed files with 38 additions and 16 deletions

View File

@ -79,18 +79,24 @@ elseif(${USE_OIIO})
pkg_check_modules(OIIO REQUIRED OpenImageIO>=2.1)
endif()
find_library(MATH_LIBRARIES m)
# don't cache this, or installing it requires clearing the cache to be found
if(${USE_DOCTEST})
find_package(doctest 2.3.5 REQUIRED)
endif()
# don't cache these, or installing them requires clearing the cache to be found.
# this is going to be true for anything lacking pkg-config/CMake support.
unset(HAVE_QRCODEGEN_H CACHE)
check_include_file("qrcodegen/qrcodegen.h" HAVE_QRCODEGEN_H)
check_include_file("uniwbrk.h" HAVE_UNISTRING_H)
if(NOT "${HAVE_UNISTRING_H}")
message(FATAL_ERROR "Couldn't find uniwbrk.h from GNU libunistring")
endif()
if("${USE_QRCODEGEN}")
check_include_file("qrcodegen/qrcodegen.h" HAVE_QRCODEGEN_H)
if(NOT "${HAVE_QRCODEGEN_H}")
message(FATAL_ERROR "USE_QRCODEGEN is active, but couldn't find qrcodegen.h")
endif()
endif()
find_library(LIBRT rt)
if(${USE_DOCTEST})
find_package(doctest 2.3.5 REQUIRED)
endif()
# libnotcurses (core shared library and static library)
file(GLOB NCSRCS CONFIGURE_DEPENDS src/lib/*.c src/lib/*.cpp)
@ -129,6 +135,7 @@ target_link_libraries(notcurses
PRIVATE
"${TERMINFO_LIBRARIES}"
"${LIBRT}"
unistring
PUBLIC
Threads::Threads
)
@ -136,6 +143,7 @@ target_link_libraries(notcurses-static
PRIVATE
"${TERMINFO_STATIC_LIBRARIES}"
"${LIBRT}"
unistring
PUBLIC
Threads::Threads
)

View File

@ -1,6 +1,9 @@
This document attempts to list user-visible changes and any major internal
rearrangements of Notcurses.
* 1.6.7 (not yet released)
* GNU libunistring is now required to build/load Notcurses.
* 1.6.6 (2020-07-19)
* `notcurses-pydemo` is now only installed alongside the Python module,
using setuptools. CMake no longer installs it.

View File

@ -114,6 +114,7 @@ that fine library.
* (build) A C11 and a C++17 compiler
* (build) CMake 3.14.0+
* (build+runtime) From NCURSES: terminfo 6.1+
* (build+runtime) GNU libunistring 0.9.10+
* (OPTIONAL) (build+runtime) From QR-Code-generator: [libqrcodegen](https://github.com/nayuki/QR-Code-generator) 1.5.0+
* (OPTIONAL) (build+runtime) From [FFmpeg](https://www.ffmpeg.org/): libswscale 5.0+, libavformat 57.0+, libavutil 56.0+
* (OPTIONAL) (build+runtime) [OpenImageIO](https://github.com/OpenImageIO/oiio) 2.15.0+

View File

@ -341,7 +341,7 @@ nc_err_e ncdirect_render_image(ncdirect* n, const char* file, ncalign_e align,
struct ncplane* faken = ncplane_create(nullptr, nullptr,
disprows / encoding_y_scale(bset),
dispcols / encoding_x_scale(bset),
0, 0, nullptr);
0, 0, nullptr, nullptr);
if(faken == nullptr){
return NCERR_NOMEM;
}

View File

@ -80,6 +80,7 @@ typedef struct ncplane {
cell basecell; // cell written anywhere that fb[i].gcluster == 0
struct notcurses* nc; // notcurses object of which we are a part
bool scrolling; // is scrolling enabled? always disabled by default
char* name; // used only for debugging
} ncplane;
#include "blitset.h"
@ -782,7 +783,7 @@ calc_gradient_channels(uint64_t* channels, uint64_t ul, uint64_t ur,
// ncvisual_render(), and thus calls these low-level internal functions.
// they are not for general use -- check ncplane_new() and ncplane_destroy().
ncplane* ncplane_create(notcurses* nc, ncplane* n, int rows, int cols,
int yoff, int xoff, void* opaque);
int yoff, int xoff, void* opaque, const char* name);
void free_plane(ncplane* p);
// heap-allocated formatted output

View File

@ -14,6 +14,7 @@
#include <stdlib.h>
#include <signal.h>
#include <locale.h>
#include <uniwbrk.h>
#include <langinfo.h>
#include <stdatomic.h>
#include <sys/ioctl.h>
@ -265,6 +266,7 @@ void free_plane(ncplane* p){
p->nc->stats.fbbytes -= sizeof(*p->fb) * p->leny * p->lenx;
}
egcpool_dump(&p->pool);
free(p->name);
free(p->fb);
free(p);
}
@ -281,7 +283,7 @@ void free_plane(ncplane* p){
// ncplane created by ncdirect for rendering visuals. in that case (and only in
// that case), nc is NULL.
ncplane* ncplane_create(notcurses* nc, ncplane* n, int rows, int cols,
int yoff, int xoff, void* opaque){
int yoff, int xoff, void* opaque, const char* name){
if(rows <= 0 || cols <= 0){
return NULL;
}
@ -299,6 +301,7 @@ ncplane* ncplane_create(notcurses* nc, ncplane* n, int rows, int cols,
p->x = p->y = 0;
p->logrow = 0;
p->blist = NULL;
p->name = name ? strdup(name) : NULL;
if( (p->boundto = n) ){
p->absx = xoff + n->absx;
p->absy = yoff + n->absy;
@ -339,7 +342,8 @@ ncplane* ncplane_create(notcurses* nc, ncplane* n, int rows, int cols,
static ncplane*
create_initial_ncplane(notcurses* nc, int dimy, int dimx){
nc->stdplane = ncplane_create(nc, NULL, dimy - (nc->margin_t + nc->margin_b),
dimx - (nc->margin_l + nc->margin_r), 0, 0, NULL);
dimx - (nc->margin_l + nc->margin_r), 0, 0, NULL,
"std");
return nc->stdplane;
}
@ -352,16 +356,17 @@ const ncplane* notcurses_stdplane_const(const notcurses* nc){
}
ncplane* ncplane_new(notcurses* nc, int rows, int cols, int yoff, int xoff, void* opaque){
return ncplane_create(nc, NULL, rows, cols, yoff, xoff, opaque);
return ncplane_create(nc, NULL, rows, cols, yoff, xoff, opaque, NULL);
}
ncplane* ncplane_bound(ncplane* n, int rows, int cols, int yoff, int xoff, void* opaque){
return ncplane_create(n->nc, n, rows, cols, yoff, xoff, opaque);
return ncplane_create(n->nc, n, rows, cols, yoff, xoff, opaque, NULL);
}
ncplane* ncplane_aligned(ncplane* n, int rows, int cols, int yoff,
ncalign_e align, void* opaque){
return ncplane_create(n->nc, n, rows, cols, yoff, ncplane_align(n, align, cols), opaque);
return ncplane_create(n->nc, n, rows, cols, yoff,
ncplane_align(n, align, cols), opaque, NULL);
}
void ncplane_home(ncplane* n){
@ -408,7 +413,8 @@ ncplane* ncplane_dup(const ncplane* n, void* opaque){
const struct notcurses* nc = ncplane_notcurses_const(n);
const int placey = n->absy - nc->margin_t;
const int placex = n->absx - nc->margin_l;
ncplane* newn = ncplane_create(n->nc, n->boundto, dimy, dimx, placey, placex, opaque);
ncplane* newn = ncplane_create(n->nc, n->boundto, dimy, dimx,
placey, placex, opaque, n->name);
if(newn){
if(egcpool_dup(&newn->pool, &n->pool)){
ncplane_destroy(newn);
@ -1595,10 +1601,10 @@ int ncplane_hline_interp(ncplane* n, const cell* c, int len,
return ret;
}
// FIXME there are more advanced means of wordbreaking within unicode; use them
static bool
iswordbreak(wchar_t w){
return iswspace(w);
iswordbreak(wchar_t wchar){
int w = uc_wordbreak_property(wchar);
return (w == WBP_OTHER || w == WBP_NEWLINE || w == WBP_CR || w == WBP_LF);
}
static bool
@ -1623,6 +1629,7 @@ overlong_word(const char* text, int dimx){
return false;
}
// FIXME probably best to use u8_wordbreaks() and get all wordbreaks at once...
int ncplane_puttext(ncplane* n, int y, ncalign_e align, const char* text, size_t* bytes){
int totalcols = 0;
// save the beginning for diagnostic

View File

@ -498,6 +498,7 @@ TEST_CASE("NCPlane") {
ncplane_cursor_yx(n_, &y, &x);
REQUIRE(1 == y);
REQUIRE(dimx == x);
// this ought not print anything, since we're at the end of the row
REQUIRE(0 == ncplane_putstr(n_, STR3));
REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0));
REQUIRE(0 < ncplane_at_cursor_cell(n_, &testcell)); // want first char of STR1
@ -534,6 +535,7 @@ TEST_CASE("NCPlane") {
ncplane_cursor_yx(n_, &y, &x);
REQUIRE(1 == y);
REQUIRE(dimx == x);
// this ought not print anything, since we're at the end of the row
REQUIRE(0 == ncplane_putstr(n_, STR3));
REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0));
REQUIRE(0 < ncplane_at_cursor_cell(n_, &testcell)); // want first char of STR1