From 2741b049cb4d1870af67ec67a3aa2a5edf87902a Mon Sep 17 00:00:00 2001 From: nick black Date: Thu, 18 Feb 2021 07:04:03 -0500 Subject: [PATCH] don't expose nctree in 2.2.2 --- doc/man/index.html | 1 - doc/man/man3/notcurses.3.md | 2 - doc/man/man3/notcurses_reel.3.md | 9 +- doc/man/man3/notcurses_tree.3.md | 94 ----------- include/notcurses/notcurses.h | 67 -------- src/lib/tree.c | 264 ------------------------------- src/tests/tree.cpp | 154 ------------------ 7 files changed, 1 insertion(+), 590 deletions(-) delete mode 100644 doc/man/man3/notcurses_tree.3.md delete mode 100644 src/lib/tree.c delete mode 100644 src/tests/tree.cpp diff --git a/doc/man/index.html b/doc/man/index.html index 2429a95c17..c91c99753d 100644 --- a/doc/man/index.html +++ b/doc/man/index.html @@ -66,7 +66,6 @@

C library (section 3)

notcurses_stats—notcurses runtime statistics
notcurses_stdplane—acquire the standard ncplane
notcurses_stop—collapse the context
- notcurses_tree—high-level hierarchical line-based data
notcurses_visual—operations on ncvisual objects
diff --git a/doc/man/man3/notcurses.3.md b/doc/man/man3/notcurses.3.md index e5ba60d34c..e1a6d23c6f 100644 --- a/doc/man/man3/notcurses.3.md +++ b/doc/man/man3/notcurses.3.md @@ -118,7 +118,6 @@ A few high-level widgets are included, all built atop ncplanes: * **notcurses_reader(3)** for free-form input data * **notcurses_reel(3)** for hierarchal display of block-based data * **notcurses_selector(3)** for selecting one item from a set -* **notcurses_tree(3)** for hierarchal display of line-based data ## Threads @@ -187,7 +186,6 @@ order to turn most error returns into exceptions. **notcurses_stats(3)**, **notcurses_stdplane(3)**, **notcurses_stop(3)**, -**notcurses_tree(3)**, **notcurses_visual(3)**, **terminfo(5)**, **ascii(7)**, **utf-8(7)**, **unicode(7)** diff --git a/doc/man/man3/notcurses_reel.3.md b/doc/man/man3/notcurses_reel.3.md index 753dfcd143..837f846ce0 100644 --- a/doc/man/man3/notcurses_reel.3.md +++ b/doc/man/man3/notcurses_reel.3.md @@ -127,12 +127,6 @@ tablet, unless no tablets exist, in which case they return **NULL**. **ncreel_add** returns the newly-added **nctablet**. -# NOTES - -**ncreel** shares many properties with **notcurses_tree**. Unlike the latter, -**ncreel**s supply only a single level of hierarchy, and allow elements to -come and go across the lifetime of the widget. - # BUGS I can't decide whether to require the user to explicitly call **ncreel_redraw**. @@ -143,5 +137,4 @@ things more complicated for both me and the user. **notcurses(3)**, **notcurses_input(3)**, -**notcurses_plane(3)**, -**notcurses_tree(3)** +**notcurses_plane(3)** diff --git a/doc/man/man3/notcurses_tree.3.md b/doc/man/man3/notcurses_tree.3.md deleted file mode 100644 index 93b37f225c..0000000000 --- a/doc/man/man3/notcurses_tree.3.md +++ /dev/null @@ -1,94 +0,0 @@ -% notcurses_tree(3) -% nick black -% v2.2.1 - -# NAME - -notcurses_tree - high-level hierarchical line-based data - -# SYNOPSIS - -**#include ** - -```c -struct nctree; -struct ncplane; - -typedef struct nctree_item { - void* curry; - struct nctree_item* subs; - unsigned subcount; -} nctree_item; - -typedef struct nctree_options { - const nctree_item* items; // top-level nctree_item array - unsigned count; // size of |items| - uint64_t bchannels; // base channels - int (*nctreecb)(struct ncplane*, void*, int); // item callback - uint64_t flags; // bitfield of NCTREE_OPTION_* -} nctree_options; -``` - -**struct nctree* nctree_create(struct ncplane* ***n***, const nctree_options* ***opts***);** - -**struct ncplane* nctree_plane(struct nctree* ***n***);** - -**int nctree_redraw(struct nctree* ***n***);** - -**bool nctree_offer_input(struct nctree* ***n***, const ncinput* ***ni***);** - -**void* nctree_focused(struct nctree* ***n***);** - -**void* nctree_next(struct nctree* ***n***);** - -**void* nctree_prev(struct nctree* ***n***);** - -**void* nctree_goto(struct nctree* ***n***, const int* ***spec***, size_t ***specdepth***, int* ***failspec***);** - -**void nctree_destroy(struct nctree* ***n***);** - -# DESCRIPTION - -**nctree**s organize static hierarchical items, and allow them to be browsed. -Each item can have arbitrary subitems. Items can be collapsed and expanded. -The display supports scrolling and searching. Items cannot be added or removed, -however; they must be provided in their entirety at creation time. - -An **nctree** cannot be empty. **count** must be non-zero, and **items** must -not be **NULL**. The callback function **nctreecb** must also be non-**NULL**. - -The callback function **nctreecb** is called on tree items when the tree is -redrawn. It will be called on each visible item, and any item which has become -hidden. If the item is newly hidden, the **ncplane** argument will be **NULL**. -If the item is newly visible, the **ncplane** argument will be an empty plane. -If the item was already visible, the **ncplane** argument will be the same -plane passed before. If the item has not changed since the last time the -callback was invoked, there is no need to change the plane, and the callback -can return immediately. Otherwise, the plane ought be drawn by the callback. -Any unused rows ought be trimmed away using **ncplane_resize**. If the plane -is expanded in the callback, it will be shrunk back down by the widget. The -**int** parameter indicates distance from the focused item. If the parameter -is negative, the item is before the focused item; a positive parameter implies -that the item follows the focused item; the focused item itself is passed zero. - -# RETURN VALUES - -**nctree_create** returns **NULL** for invalid options. This includes a **NULL** -**items** or **nctreecb** field, or a zero **count** field. - -**nctree_next** and **nctree_prev** both return the **curry** pointer from the -newly-focused item. **nctree_focused** returns the **curry** pointer from the -already-focused item. - -# NOTES - -**nctree** shares many properties with **notcurses_reel**. Unlike the latter, -**nctree**s support arbitrary hierarchical levels, but they do not allow -elements to come and go across the lifetime of the widget. - -# SEE ALSO - -**notcurses(3)**, -**notcurses_input(3)**, -**notcurses_plane(3)**, -**notcurses_reel(3)** diff --git a/include/notcurses/notcurses.h b/include/notcurses/notcurses.h index 757af9ffea..eb795f94fc 100644 --- a/include/notcurses/notcurses.h +++ b/include/notcurses/notcurses.h @@ -55,7 +55,6 @@ struct ncreader; // widget supporting free string input ala readline struct ncfadectx; // context for a palette fade operation struct nctablet; // grouped item within an ncreel struct ncreel; // hierarchical block-based data browser -struct nctree; // hierarchical line-based data browser // we never blit full blocks, but instead spaces (more efficient) with the // background set to the desired foreground. @@ -2998,72 +2997,6 @@ API bool ncmultiselector_offer_input(struct ncmultiselector* n, const ncinput* n // Destroy the ncmultiselector. API void ncmultiselector_destroy(struct ncmultiselector* n); -// nctree widget -- a vertical browser supporting line-based hierarchies. -// -// each item can have subitems, and has a curry. there is one callback for the -// entirety of the nctree. visible items have the callback invoked upon their -// curry and an ncplane. the ncplane can be reused across multiple invocations -// of the callback. - -// each item has a curry, and zero or more subitems. -typedef struct nctree_item { - void* curry; - struct nctree_item* subs; - unsigned subcount; -} nctree_item; - -typedef struct nctree_options { - const nctree_item* items; // top-level nctree_item array - unsigned count; // size of |items| - uint64_t bchannels; // base channels - int (*nctreecb)(struct ncplane*, void*, int); // item callback function - uint64_t flags; // bitfield of NCTREE_OPTION_* -} nctree_options; - -// |opts| may *not* be NULL, since it is necessary to define a callback -// function. -API ALLOC struct nctree* nctree_create(struct ncplane* n, const nctree_options* opts) - __attribute__ ((nonnull (1, 2))); - -// Returns the ncplane on which this nctree lives. -API struct ncplane* nctree_plane(struct nctree* n) - __attribute__ ((nonnull (1))); - -// Redraw the nctree 'n' in its entirety. The tree will be cleared, and items -// will be lain out, using the focused item as a fulcrum. Item-drawing -// callbacks will be invoked for each visible item. -API int nctree_redraw(struct nctree* n) - __attribute__ ((nonnull (1))); - -// Offer input 'ni' to the nctree 'n'. If it's relevant, this function returns -// true, and the input ought not be processed further. If it's irrelevant to -// the tree, false is returned. Relevant inputs include: -// * a mouse click on an item (focuses item) -// * a mouse scrollwheel event (srolls tree) -// * up, down, pgup, or pgdown (navigates among items) -API bool nctree_offer_input(struct nctree* n, const ncinput* ni) - __attribute__ ((nonnull (1, 2))); - -// Return the focused item, if any items are present. This is not a copy; -// be careful to use it only for the duration of a critical section. -API void* nctree_focused(struct nctree* n) __attribute__ ((nonnull (1))); - -// Change focus to the next item. -API void* nctree_next(struct nctree* n) __attribute__ ((nonnull (1))); - -// Change focus to the previous item. -API void* nctree_prev(struct nctree* n) __attribute__ ((nonnull (1))); - -// Go to the item specified by the array |spec| having |specdepth| elements. If -// the spec is invalid, NULL is returned, and the depth of the first invalid -// spec is written to *|failspec|. Otherwise, |specdepth| is written to -// *|failspec|, and the curry is returned (|failspec| is necessary because the -// curry could itself be NULL). -API void* nctree_goto(struct nctree* n, const int* spec, size_t specdepth, int* failspec); - -// Destroy the nctree. -API void nctree_destroy(struct nctree* n); - // Menus. Horizontal menu bars are supported, on the top and/or bottom rows. // If the menu bar is longer than the screen, it will be only partially // visible. Menus may be either visible or invisible by default. In the event of diff --git a/src/lib/tree.c b/src/lib/tree.c deleted file mode 100644 index c628dc4c79..0000000000 --- a/src/lib/tree.c +++ /dev/null @@ -1,264 +0,0 @@ -#include "internal.h" - -// these are never allocated themselves, but always as arrays of object -typedef struct nctree_int_item { - void* curry; - ncplane* ncp; - unsigned subcount; - struct nctree_int_item* subs; -} nctree_int_item; - -typedef struct nctree { - int (*cbfxn)(ncplane*, void*, int); - nctree_int_item items; // topmost set of items, holds widget plane - unsigned* currentpath; // array of |maxdepth|+1 elements, ended by UINT_MAX - unsigned maxdepth; // binds the path length - int activerow; // active row 0 <= activerow < dimy - uint64_t bchannels; // border glyph channels -} nctree; - -// recursively free an array of nctree_int_item; nctree_int_item structs are -// never individually free()d, just their innards -static void -free_tree_items(nctree_int_item* iarray){ - for(unsigned c = 0 ; c < iarray->subcount ; ++c){ - free_tree_items(&iarray->subs[c]); - } - ncplane_destroy(iarray->ncp); - free(iarray->subs); -} - -// allocates a |count|-sized array of nctree_int_items, and fills |fill| in, -// using |items|. updates |*maxdepth| when appropriate. -static int -dup_tree_items(nctree_int_item* fill, const nctree_item* items, unsigned count, unsigned depth, - unsigned* maxdepth){ - fill->subcount = count; - fill->subs = malloc(sizeof(*fill->subs) * count); - if(fill->subs == NULL){ - return -1; - } - for(unsigned c = 0 ; c < fill->subcount ; ++c){ - nctree_int_item* nii = &fill->subs[c]; - nii->curry = items[c].curry; - if(nii->curry == NULL){ - while(c--){ - free_tree_items(&fill->subs[c]); - } - free(fill->subs); - return -1; - } - nii->ncp = NULL; - if(dup_tree_items(nii, items[c].subs, items[c].subcount, depth + 1, maxdepth)){ - while(c--){ - free_tree_items(&fill->subs[c]); - } - free(fill->subs); - return -1; - } - } - if(depth > *maxdepth){ - *maxdepth = depth; - } - return 0; -} - -// the initial path ought point to the first item. maxdepth must be set. -static int -prep_initial_path(nctree* n){ - n->currentpath = malloc(sizeof(*n->currentpath) * (n->maxdepth + 1)); - if(n->currentpath == NULL){ - return -1; - } - const nctree_int_item* nii = &n->items; - int c = 0; - while(nii->subcount){ - n->currentpath[c++] = 0; - nii = &nii->subs[0]; - } - n->currentpath[c] = UINT_MAX; - return 0; -} - -static nctree* -nctree_inner_create(ncplane* n, const struct nctree_options* opts){ - nctree* ret = malloc(sizeof(*ret)); - if(ret){ - ret->bchannels = opts->bchannels; - ret->cbfxn = opts->nctreecb; - ret->maxdepth = 0; - if(dup_tree_items(&ret->items, opts->items, opts->count, 0, &ret->maxdepth)){ - free(ret); - return NULL; - } -//fprintf(stderr, "MAXDEPTH: %u\n", ret->maxdepth); - if(prep_initial_path(ret)){ - free_tree_items(&ret->items); - free(ret); - return NULL; - } - ret->items.ncp = n; - ret->items.curry = NULL; - ret->activerow = 0; - nctree_redraw(ret); - } - return ret; -} - -nctree* nctree_create(ncplane* n, const struct nctree_options* opts){ - notcurses* nc = ncplane_notcurses(n); - if(opts->flags){ - logwarn(nc, "Passed invalid flags 0x%016jx\n", (uint64_t)opts->flags); - goto error; - } - if(opts->count == 0 || opts->items == NULL){ - logerror(nc, "Can't create empty tree\n"); - goto error; - } - if(opts->nctreecb == NULL){ - logerror(nc, "Can't use NULL callback\n"); - goto error; - } - nctree* ret = nctree_inner_create(n, opts); - if(ret == NULL){ - goto error; - } - return ret; - -error: - ncplane_destroy(n); - return NULL; -} - -void nctree_destroy(nctree* n){ - if(n){ - free_tree_items(&n->items); - free(n); - } -} - -// Returns the ncplane on which this nctree lives. -ncplane* nctree_plane(nctree* n){ - return n->items.ncp; -} - -// the prev is either: -// the item to the left, if the last path component is 0, or -// a drop from the rightmost non-zero path component, extended out to the right, or -// the current item -// so we can always just go to the last path component, act there, and possibly -// extend it out to the maximal topright. -void* nctree_prev(nctree* n){ - nctree_int_item* nii = &n->items; - nctree_int_item* wedge = NULL; // tracks the rightmost non-zero path - int idx = 0; - while(n->currentpath[idx] != UINT_MAX){ - nii = &nii->subs[n->currentpath[idx]]; - if(idx == 0){ - wedge = &n->items; - }else{// if(idx > 1){ - wedge = &wedge->subs[n->currentpath[idx - 1]]; - } - ++idx; - } - if(n->currentpath[idx - 1]){ - --n->currentpath[idx - 1]; - nii = &wedge->subs[n->currentpath[idx - 1]]; - while(nii->subcount){ - n->currentpath[idx - 1] = nii->subcount - 1; - nii = &nii->subs[n->currentpath[idx - 1]]; - ++idx; - } - n->currentpath[idx] = UINT_MAX; - return nii->curry; - } - if(wedge == &n->items){ - return nii->curry; // no change - } - n->currentpath[idx - 1] = UINT_MAX; - return wedge->curry; -} - -// the next is either: -// - an extension to the right, if subs are available, or -// - a bump to the rightmost path component with subcount available, or -// - the current item -void* nctree_next(nctree* n){ - nctree_int_item* nii = &n->items; - nctree_int_item* wedge = NULL; // tracks the rightmost with room in subs - int idx = 0; - int wedidx = 0; - while(n->currentpath[idx] != UINT_MAX){ - if(n->currentpath[idx] < nii->subcount - 1){ - wedge = nii; - wedidx = idx; - } - nii = &nii->subs[n->currentpath[idx]]; - ++idx; - } - // FIXME update n->activerow, redraw - if(nii->subcount){ - n->currentpath[idx] = 0; - n->currentpath[idx + 1] = UINT_MAX; - return nii->subs[n->currentpath[idx]].curry; - } - if(wedge){ - ++n->currentpath[wedidx]; - n->currentpath[wedidx + 1] = UINT_MAX; - return wedge->subs[n->currentpath[wedidx]].curry; - } - return nii->curry; -} - -int nctree_redraw(nctree* n){ - ncplane* ncp = n->items.ncp; - if(ncplane_cursor_move_yx(ncp, n->activerow, 0)){ - return -1; - } - // FIXME start at n->activerow with the currentpath. for each, until we run - // out or fill the screen, check that it has an ncplane defined. if not, - // create one. pass it to the callback with the curry. - return 0; -} - -bool nctree_offer_input(nctree* n, const ncinput* ni){ - if(ni->id == NCKEY_UP){ - nctree_prev(n); - return true; - }else if(ni->id == NCKEY_DOWN){ - nctree_next(n); - return true; - }else if(ni->id == NCKEY_PGUP){ - nctree_prev(n); // more FIXME - return true; - }else if(ni->id == NCKEY_PGDOWN){ - nctree_next(n); // more FIXME - return true; - }else if(ni->id == NCKEY_HOME){ - nctree_prev(n); // more FIXME - return true; - }else if(ni->id == NCKEY_END){ - nctree_next(n); // more FIXME - return true; - } - // FIXME implement left, right, +, - (expand/collapse) - return false; -} - -void* nctree_focused(nctree* n){ - int idx = 0; - const nctree_int_item* nii = &n->items; - while(n->currentpath[idx] != UINT_MAX){ - assert(n->currentpath[idx] < nii->subcount); - nii = &nii->subs[n->currentpath[idx]]; - ++idx; - } -//fprintf(stderr, "FOCUSED: %s\n", nii->curry); - return nii->curry; -} - -/* -void* nctree_goto(nctree* n, const int* spec, size_t specdepth, int* failspec){ - // FIXME -} -*/ diff --git a/src/tests/tree.cpp b/src/tests/tree.cpp deleted file mode 100644 index 4cbc840a98..0000000000 --- a/src/tests/tree.cpp +++ /dev/null @@ -1,154 +0,0 @@ -#include "main.h" -#include - -int treecb(struct ncplane* n, void* curry, int pos){ - ncplane_printf_yx(n, 0, 0, "item: %s pos: %d", - static_cast(curry), pos); - return 0; -} - -TEST_CASE("Tree") { - auto nc_ = testing_notcurses(); - if(!nc_){ - return; - } - struct ncplane* n_ = notcurses_stdplane(nc_); - REQUIRE(n_); - REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0)); - - // should be refused with a null items - SUBCASE("BadTreeNoItems") { - struct nctree_options opts = { - .items = nullptr, - .count = 2, - .bchannels = 0, - .nctreecb = treecb, - .flags = 0, - }; - auto treen = nctree_create(n_, &opts); - REQUIRE(nullptr == treen); - } - - // should be refused with a zero count - SUBCASE("BadTreeNoCount") { - struct nctree_options opts = { - .items = {}, - .count = 0, - .bchannels = 0, - .nctreecb = treecb, - .flags = 0, - }; - auto treen = nctree_create(n_, &opts); - REQUIRE(nullptr == treen); - } - - nctree_item subs[] = { - { - .curry = strdup("sub1-0"), - .subs = nullptr, - .subcount = 0, - },{ - .curry = strdup("sub1-1"), - .subs = nullptr, - .subcount = 0, - } - }; - - nctree_item items[] = { - { - .curry = strdup("item0"), - .subs = nullptr, - .subcount = 0, - }, { - .curry = strdup("item1"), - .subs = subs, - .subcount = 2, - }, - }; - - // should be refused with a null callback - SUBCASE("BadTreeNoCallback") { - struct nctree_options opts = { - .items = items, - .count = sizeof(items) / sizeof(*items), - .bchannels = 0, - .nctreecb = nullptr, - .flags = 0, - }; - auto treen = nctree_create(n_, &opts); - REQUIRE(nullptr == treen); - } - - SUBCASE("Create") { - struct nctree_options opts = { - .items = items, - .count = sizeof(items) / sizeof(*items), - .bchannels = 0, - .nctreecb = treecb, - .flags = 0, - }; - const ncplane_options nopts = { - .y = 0, .x = 0, .rows = 3, .cols = ncplane_dim_y(n_), - .userptr = nullptr, .name = nullptr, .resizecb = nullptr, .flags = 0, - }; - auto treen = ncplane_create(n_, &nopts); - REQUIRE(nullptr != treen); - auto tree = nctree_create(treen, &opts); - REQUIRE(nullptr != tree); - CHECK(0 == notcurses_render(nc_)); - CHECK(treen == nctree_plane(tree)); - CHECK(items[0].curry == nctree_focused(tree)); - nctree_destroy(tree); - } - - SUBCASE("Traverse") { - struct nctree_options opts = { - .items = items, - .count = sizeof(items) / sizeof(*items), - .bchannels = 0, - .nctreecb = treecb, - .flags = 0, - }; - const ncplane_options nopts = { - .y = 0, .x = 0, .rows = 3, .cols = ncplane_dim_y(n_), - .userptr = nullptr, .name = nullptr, .resizecb = nullptr, .flags = 0, - }; - auto treen = ncplane_create(n_, &nopts); - REQUIRE(nullptr != treen); - auto tree = nctree_create(treen, &opts); - REQUIRE(nullptr != tree); - CHECK(0 == notcurses_render(nc_)); - CHECK(treen == nctree_plane(tree)); - CHECK(items[0].curry == nctree_focused(tree)); - - CHECK(items[0].curry == nctree_prev(tree)); - CHECK(items[0].curry == nctree_focused(tree)); - - CHECK(items[1].curry == nctree_next(tree)); - CHECK(items[1].curry == nctree_focused(tree)); - - CHECK(items[1].subs[0].curry == nctree_next(tree)); - CHECK(items[1].subs[0].curry == nctree_focused(tree)); - - CHECK(items[1].subs[1].curry == nctree_next(tree)); - CHECK(items[1].subs[1].curry == nctree_focused(tree)); - - CHECK(items[1].subs[1].curry == nctree_next(tree)); - CHECK(items[1].subs[1].curry == nctree_focused(tree)); - - CHECK(items[1].subs[0].curry == nctree_prev(tree)); - CHECK(items[1].subs[0].curry == nctree_focused(tree)); - - CHECK(items[1].curry == nctree_prev(tree)); - CHECK(items[1].curry == nctree_focused(tree)); - - CHECK(items[0].curry == nctree_prev(tree)); - CHECK(items[0].curry == nctree_focused(tree)); - - CHECK(items[0].curry == nctree_prev(tree)); - CHECK(items[0].curry == nctree_focused(tree)); - nctree_destroy(tree); - } - - CHECK(0 == notcurses_stop(nc_)); -}