diff --git a/CMakeLists.txt b/CMakeLists.txt index 8006a6861..73a499e14 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 ) diff --git a/NEWS.md b/NEWS.md index 09099611e..d56fe1eb3 100644 --- a/NEWS.md +++ b/NEWS.md @@ -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. diff --git a/README.md b/README.md index 4399bd3a9..c816d2cdb 100644 --- a/README.md +++ b/README.md @@ -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+ diff --git a/src/lib/direct.cpp b/src/lib/direct.cpp index 2fa093d61..356850915 100644 --- a/src/lib/direct.cpp +++ b/src/lib/direct.cpp @@ -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; } diff --git a/src/lib/internal.h b/src/lib/internal.h index edf634a10..ebff18a7d 100644 --- a/src/lib/internal.h +++ b/src/lib/internal.h @@ -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 diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c index dad133cf9..eab02cae9 100644 --- a/src/lib/notcurses.c +++ b/src/lib/notcurses.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -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 diff --git a/tests/ncplane.cpp b/tests/ncplane.cpp index 7c74035d0..6fd3e7b5a 100644 --- a/tests/ncplane.cpp +++ b/tests/ncplane.cpp @@ -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