From c3e5e47a2aa4cd3b31b403e403199c4d7af97517 Mon Sep 17 00:00:00 2001 From: nick black Date: Sun, 13 Sep 2020 13:53:11 -0400 Subject: [PATCH] ncreader: conform to the New Way #627 --- NEWS.md | 8 +++- USAGE.md | 16 +++---- doc/man/man3/notcurses_reader.3.md | 12 ++--- include/ncpp/Reader.hh | 20 ++++----- include/notcurses/notcurses.h | 14 ++---- python/src/notcurses/build_notcurses.py | 7 +-- src/demo/zoo.c | 13 +++--- src/lib/reader.c | 60 +++++++++---------------- src/poc/reader.cpp | 14 +++--- tests/reader.cpp | 27 ++--------- 10 files changed, 67 insertions(+), 124 deletions(-) diff --git a/NEWS.md b/NEWS.md index 5b4354fdf..a2d355ff5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -10,10 +10,14 @@ rearrangements of Notcurses. of the provided `ncplane`. On an error in these functions, the `ncplane` will be destroyed. Otherwise, the `ncplane` is destroyed by `ncselector_destroy()` or `ncmultiselector_destroy()`. - * `ncselector_create()` and `ncmultiselector_create()` no longer accept - `int y, int x` placement parameters. Just place the `ncplane`. + * `ncselector_create()`, `ncmultiselector_create()`, and + `ncreader_create()` no longer accept `int y, int x` placement + parameters. Just place the `ncplane`. * `ncselector_options` and `ncmultiselector_options` have lost their `bgchannels` members. Just set the base character for the `ncplane`. + * `ncreader_options` has lost its `echannels`, `eattrword`, `egc`, + `physrows`, and `physcols` fields. Just set the base character and size + for the `ncplane`. * ... * 1.7.2 (2020-09-09) diff --git a/USAGE.md b/USAGE.md index 6a42d5d48..bf0d41f2a 100644 --- a/USAGE.md +++ b/USAGE.md @@ -2271,20 +2271,14 @@ xxxxxxxxxxxxxxxx╰─────────────╯xxxxxxxxxxxxxxxxxxx ```c typedef struct ncreader_options { uint64_t tchannels; // channels used for input - uint64_t echannels; // channels used for empty space uint32_t tattrword; // attributes used for input - uint32_t eattrword; // attributes used for empty space - const char* egc; // egc used for empty space - int physrows; - int physcols; bool scroll; // allow more than the physical area's worth of input } ncreader_options; -// ncreaders provide freeform input in a (possibly multiline) region, -// supporting readline keybindings. 'rows' and 'cols' both must be negative. -// there are no restrictions on 'y' or 'x'. creates its own plane. -struct ncreader* ncreader_create(struct notcurses* nc, int y, int x, - const ncreader_options* opts); +// ncreaders provide freeform input in a (possibly multiline) region, supporting +// optional readline keybindings. takes ownership of 'n', destroying it on any +// error (ncreader_destroy() otherwise destroys the ncplane). +struct ncreader* ncreader_create(struct ncplane* n, const ncreader_options* opts); // empty the ncreader of any user input, and home the cursor. int ncreader_clear(struct ncreader* n); @@ -2299,7 +2293,7 @@ bool ncreader_offer_input(struct ncreader* n, const struct ncinput* ni); // return a nul-terminated heap copy of the current (UTF-8) contents. char* ncreader_contents(const struct ncreader* n); -// destroy the reader and its bound plane. if 'contents' is not NULL, the +// destroy the reader and its bound plane(s). if 'contents' is not NULL, the // UTF-8 input will be heap-duplicated and written to 'contents'. void ncreader_destroy(struct ncreader* n, char** contents); ``` diff --git a/doc/man/man3/notcurses_reader.3.md b/doc/man/man3/notcurses_reader.3.md index db644ed65..b7f01f597 100644 --- a/doc/man/man3/notcurses_reader.3.md +++ b/doc/man/man3/notcurses_reader.3.md @@ -23,17 +23,12 @@ struct notcurses; typedef struct ncreader_options { uint64_t tchannels; // channels used for input - uint64_t echannels; // channels used for empty space uint32_t tattrword; // attributes used for input - uint32_t eattrword; // attributes used for empty space - const char* egc; // egc used for empty space - int physrows; - int physcols; unsigned flags; // bitfield over NCREADER_OPTION_* } ncreader_options; ``` -**struct ncreader* ncreader_create(struct notcurses* nc, int y, int x, const ncreader_options* opts);** +**struct ncreader* ncreader_create(struct notcurses* nc, const ncreader_options* opts);** **int ncreader_clear(struct ncreader* n);** @@ -59,8 +54,9 @@ typedef struct ncreader_options { The **ncreader** widget supports free-form, multi-line input. It supports navigation with the arrow keys and scrolling. While the visible portion of -the **ncreader** is always the same size (**physrows** by **physcols**), the -actual text backing this visible region can grow arbitrarily large. +the **ncreader** is always the same size (defined by the provided **ncplane**), +the actual text backing this visible region can grow arbitrarily large if +scrolling is enabled. The following option flags are supported: diff --git a/include/ncpp/Reader.hh b/include/ncpp/Reader.hh index ba3ff5e12..b6f7ff93b 100644 --- a/include/ncpp/Reader.hh +++ b/include/ncpp/Reader.hh @@ -12,27 +12,27 @@ namespace ncpp class NCPP_API_EXPORT Reader : public Root { public: - explicit Reader (Plane *p, int y, int x, const ncreader_options *opts) - : Reader (static_cast(p), y, x, opts) + explicit Reader (Plane *p, const ncreader_options *opts) + : Reader (static_cast(p), opts) {} - explicit Reader (Plane const* p, int y, int x, const ncreader_options *opts) + explicit Reader (Plane const* p, const ncreader_options *opts) : Root (Utilities::get_notcurses_cpp (p)) { if (p == nullptr) throw invalid_argument ("'plane' must be a valid pointer"); - common_init (Utilities::to_ncplane (p), y, x, opts); + common_init (Utilities::to_ncplane (p), opts); } - explicit Reader (Plane &p, int y, int x, const ncreader_options *opts) - : Reader (static_cast(p), y, x, opts) + explicit Reader (Plane &p, const ncreader_options *opts) + : Reader (static_cast(p), opts) {} - explicit Reader (Plane const& p, int y, int x, const ncreader_options *opts) + explicit Reader (Plane const& p, const ncreader_options *opts) : Root (Utilities::get_notcurses_cpp (p)) { - common_init (Utilities::to_ncplane (p), y, x, opts); + common_init (Utilities::to_ncplane (p), opts); } ~Reader () @@ -58,9 +58,9 @@ namespace ncpp } private: - void common_init (ncplane *n, int y, int x, const ncreader_options *opts) + void common_init (ncplane *n, const ncreader_options *opts) { - reader = ncreader_create (n, y, x, opts); + reader = ncreader_create (n, opts); if (reader == nullptr) throw init_error ("Notcurses failed to create a new reader"); } diff --git a/include/notcurses/notcurses.h b/include/notcurses/notcurses.h index 1d832df46..57f4116bb 100644 --- a/include/notcurses/notcurses.h +++ b/include/notcurses/notcurses.h @@ -3034,20 +3034,14 @@ API int ncplane_qrcode(struct ncplane* n, ncblitter_e blitter, int* ymax, typedef struct ncreader_options { uint64_t tchannels; // channels used for input - uint64_t echannels; // channels used for empty space uint32_t tattrword; // attributes used for input - uint32_t eattrword; // attributes used for empty space - const char* egc; // egc used for empty space - int physrows; - int physcols; uint64_t flags; // bitfield of NCREADER_OPTION_* } ncreader_options; -// ncreaders provide freeform input in a (possibly multiline) region, -// supporting readline keybindings. 'rows' and 'cols' both must be negative. -// there are no restrictions on 'y' or 'x'. creates its own plane. -API struct ncreader* ncreader_create(struct ncplane* n, int y, int x, - const ncreader_options* opts) +// ncreaders provide freeform input in a (possibly multiline) region, supporting +// optional readline keybindings. takes ownership of 'n', destroying it on any +// error (ncreader_destroy() otherwise destroys the ncplane). +API struct ncreader* ncreader_create(struct ncplane* n, const ncreader_options* opts) __attribute__ ((nonnull (1))); // empty the ncreader of any user input, and home the cursor. diff --git a/python/src/notcurses/build_notcurses.py b/python/src/notcurses/build_notcurses.py index 1e20eb7b5..9e722e232 100644 --- a/python/src/notcurses/build_notcurses.py +++ b/python/src/notcurses/build_notcurses.py @@ -389,15 +389,10 @@ struct ncplane* ncsubproc_plane(struct ncsubproc* n); int ncsubproc_destroy(struct ncsubproc* n); typedef struct ncreader_options { uint64_t tchannels; // channels used for input - uint64_t echannels; // channels used for empty space uint32_t tattrword; // attributes used for input - uint32_t eattrword; // attributes used for empty space - const char* egc; // egc used for empty space - int physrows; - int physcols; unsigned flags; // bitfield over NCREADER_OPTION_* } ncreader_options; -struct ncreader* ncreader_create(struct ncplane* n, int y, int x, const ncreader_options* opts); +struct ncreader* ncreader_create(struct ncplane* n, const ncreader_options* opts); int ncreader_clear(struct ncreader* n); struct ncplane* ncreader_plane(struct ncreader* n); bool ncreader_offer_input(struct ncreader* n, const struct ncinput* ni); diff --git a/src/demo/zoo.c b/src/demo/zoo.c index 109110941..c4cd71c3b 100644 --- a/src/demo/zoo.c +++ b/src/demo/zoo.c @@ -372,16 +372,15 @@ reader_demo(struct notcurses* nc){ const int READER_ROWS = 8; ncreader_options nopts = { .tchannels = CHANNELS_RGB_INITIALIZER(0xa0, 0xe0, 0xe0, 0, 0, 0), - .echannels = CHANNELS_RGB_INITIALIZER(0x20, 0xe0, 0xe0, 0, 0, 0), - .egc = " ", - .physcols = READER_COLS, - .physrows = READER_ROWS, }; - channels_set_bg_alpha(&nopts.echannels, CELL_ALPHA_BLEND); - const int x = ncplane_align(std, NCALIGN_CENTER, nopts.physcols); + uint64_t echannels = CHANNELS_RGB_INITIALIZER(0x20, 0xe0, 0xe0, 0, 0, 0); + channels_set_bg_alpha(&echannels, CELL_ALPHA_BLEND); + const int x = ncplane_align(std, NCALIGN_CENTER, READER_COLS); struct ncselector* selector = NULL; struct ncmultiselector* mselector = NULL; - struct ncreader* reader = ncreader_create(std, dimy, x, &nopts); + struct ncplane* rp = ncplane_new(nc, READER_ROWS, READER_COLS, dimy, x, NULL); + ncplane_set_base(rp, " ", 0, echannels); + struct ncreader* reader = ncreader_create(rp, &nopts); if(reader == NULL){ goto done; } diff --git a/src/lib/reader.c b/src/lib/reader.c index 68163505c..aef0776d3 100644 --- a/src/lib/reader.c +++ b/src/lib/reader.c @@ -1,53 +1,35 @@ #include "internal.h" -ncreader* ncreader_create(ncplane* n, int y, int x, const ncreader_options* opts){ +ncreader* ncreader_create(ncplane* n, const ncreader_options* opts){ ncreader_options zeroed = {}; if(!opts){ opts = &zeroed; } - if(opts->physrows <= 0 || opts->physcols <= 0){ - logerror(n->nc, "Provided illegal geometry %dx%d\n", opts->physcols, opts->physrows); - return NULL; - } if(opts->flags > NCREADER_OPTION_CURSOR){ logwarn(n->nc, "Provided unsupported flags %016lx\n", opts->flags); } ncreader* nr = malloc(sizeof(*nr)); - if(nr){ - nr->ncp = ncplane_new(n->nc, opts->physrows, opts->physcols, y, x, NULL); - if(!nr->ncp){ - free(nr); - return NULL; - } - // do *not* bind it to the visible plane; we always want it offscreen, - // to the upper left of the true origin - if((nr->textarea = ncplane_new(n->nc, opts->physrows, opts->physcols, -opts->physrows, -opts->physcols, NULL)) == NULL){ - ncplane_destroy(nr->ncp); - free(nr); - return NULL; - } - const char* egc = opts->egc ? opts->egc : "_"; - if(ncplane_set_base(nr->ncp, egc, opts->eattrword, opts->echannels) <= 0){ - ncreader_destroy(nr, NULL); - return NULL; - } - nr->horscroll = opts->flags & NCREADER_OPTION_HORSCROLL; - nr->xproject = 0; - nr->tchannels = opts->tchannels; - nr->tattrs = opts->tattrword; - nr->no_cmd_keys = opts->flags & NCREADER_OPTION_NOCMDKEYS; - nr->manage_cursor = opts->flags & NCREADER_OPTION_CURSOR; - ncplane_set_channels(nr->ncp, opts->tchannels); - ncplane_set_attr(nr->ncp, opts->tattrword); - if(nr->manage_cursor){ - if(notcurses_cursor_enable(n->nc, nr->ncp->absy, nr->ncp->absx)){ - ncplane_destroy(nr->textarea); - ncplane_destroy(nr->ncp); - free(nr); - return NULL; - } - } + if(nr == NULL){ + ncplane_destroy(n); + return NULL; } + nr->ncp = n; + // do *not* bind it to the visible plane; we always want it offscreen, + // to the upper left of the true origin + if((nr->textarea = ncplane_new(n->nc, ncplane_dim_y(n), ncplane_dim_x(n), + -ncplane_dim_y(n), -ncplane_dim_x(n), NULL)) == NULL){ + ncplane_destroy(nr->ncp); + free(nr); + return NULL; + } + nr->horscroll = opts->flags & NCREADER_OPTION_HORSCROLL; + nr->xproject = 0; + nr->tchannels = opts->tchannels; + nr->tattrs = opts->tattrword; + nr->no_cmd_keys = opts->flags & NCREADER_OPTION_NOCMDKEYS; + nr->manage_cursor = opts->flags & NCREADER_OPTION_CURSOR; + ncplane_set_channels(nr->ncp, opts->tchannels); + ncplane_set_attr(nr->ncp, opts->tattrword); return nr; } diff --git a/src/poc/reader.cpp b/src/poc/reader.cpp index 1c8daa349..c6136c7bc 100644 --- a/src/poc/reader.cpp +++ b/src/poc/reader.cpp @@ -31,16 +31,14 @@ auto main(int argc, const char** argv) -> int { nopts.flags = NCOPTION_INHIBIT_SETLOCALE; NotCurses nc(nopts); int dimy, dimx; - std::unique_ptr n = std::make_unique(nc.get_stdplane(&dimy, &dimx)); + auto n = std::make_unique(nc.get_stdplane(&dimy, &dimx)); nc.get_term_dim(&dimy, &dimx); ncreader_options opts{}; - opts.physrows = dimy / 8; - opts.physcols = dimx / 2; - opts.egc = "░"; opts.flags = NCREADER_OPTION_CURSOR | (horscroll ? NCREADER_OPTION_HORSCROLL : 0); - // FIXME c++ is crashing - //Reader nr(nc, 0, 0, &opts); - auto nr = ncreader_create(**n, 2, 2, &opts); + // can't use Plane until we have move constructor for Reader + struct ncplane* rp = ncplane_new(nc, dimy / 8, dimx / 2, 2, 2, nullptr); + ncplane_set_base(rp, "░", 0, 0); + auto nr = ncreader_create(rp, &opts); if(nr == nullptr){ return EXIT_FAILURE; } @@ -67,7 +65,7 @@ auto main(int argc, const char** argv) -> int { nc.render(); char* contents; ncreader_destroy(nr, &contents); - nc.stop(); + //nc.stop(); if(contents){ printf("\n input: %s\n", contents); } diff --git a/tests/reader.cpp b/tests/reader.cpp index 8a0008b1a..e7fe88486 100644 --- a/tests/reader.cpp +++ b/tests/reader.cpp @@ -12,32 +12,13 @@ TEST_CASE("Readers") { REQUIRE(n_); REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0)); - SUBCASE("ReaderBadOptions") { - ncreader_options opts{}; - auto nr = ncreader_create(n_, 0, 0, &opts); - CHECK(!nr); - opts.physrows = 1; - nr = ncreader_create(n_, 0, 0, &opts); - CHECK(!nr); - opts.physcols = 1; - opts.physrows = 0; - nr = ncreader_create(n_, 0, 0, &opts); - CHECK(!nr); - } - SUBCASE("ReaderRender") { ncreader_options opts{}; - opts.physrows = dimy / 2; - opts.physcols = dimx / 2; - if(enforce_utf8()){ - opts.egc = strdup("▒"); - }else{ - opts.egc = strdup("x"); - } - auto nr = ncreader_create(n_, 0, 0, &opts); + auto ncp = ncplane_new(nc_, dimy / 2, dimx / 2, 0, 0, nullptr); + uint64_t echannels = CHANNELS_RGB_INITIALIZER(0xff, 0x44, 0xff, 0, 0, 0); + ncplane_set_base(ncp, enforce_utf8() ? strdup("▒") : strdup("x"), 0, echannels); + auto nr = ncreader_create(ncp, &opts); REQUIRE(nullptr != nr); - channels_set_fg(&opts.echannels, 0xff44ff); - ncplane_set_base(n_, opts.egc, opts.eattrword, opts.echannels); CHECK(0 == notcurses_render(nc_)); char* contents = nullptr; ncreader_destroy(nr, &contents);