1 #include <limits.h>
2 #include <notcurses/notcurses.h>
3 #include "structure.h"
4
5 #define HIERARCHY_MAX 3
6
7 typedef struct docnode {
8 char* title;
9 int line;
10 docstruct_e level;
11 } docnode;
12
13 typedef struct docstructure {
14 struct nctree* nct;
15 // one entry for each hierarchy level + terminator
16 unsigned curpath[HIERARCHY_MAX + 1];
17 } docstructure;
18
19 static int
docstruct_callback(struct ncplane * n,void * curry,int i)20 docstruct_callback(struct ncplane* n, void* curry, int i){
21 docnode* dn = curry;
22 ncplane_printf(n, "%p", dn);
23 ncplane_resize_simple(n, 1, ncplane_dim_x(n));
24 (void)i;
25 return 0;
26 }
27
docstructure_create(struct ncplane * n)28 docstructure* docstructure_create(struct ncplane* n){
29 docstructure* ds = malloc(sizeof(*ds));
30 if(ds == NULL){
31 return NULL;
32 }
33 const int ROWS = 7;
34 const int COLDIV = 4;
35 ncplane_options nopts = {
36 .rows = ROWS,
37 .cols = ncplane_dim_x(n) / COLDIV,
38 .y = ncplane_dim_y(n) - ROWS,
39 .x = ncplane_dim_x(n) - (ncplane_dim_x(n) / COLDIV) - 1,
40 .flags = NCPLANE_OPTION_AUTOGROW, // autogrow to right
41 };
42 struct ncplane* p = ncplane_create(n, &nopts);
43 if(p == NULL){
44 return NULL;
45 }
46 uint64_t channels = NCCHANNELS_INITIALIZER(0, 0, 0, 0x99, 0xed, 0xc3);
47 ncplane_set_base(p, "", 0, channels);
48 nctree_options topts = {
49 .nctreecb = docstruct_callback,
50 };
51 if((ds->nct = nctree_create(p, &topts)) == NULL){
52 free(ds);
53 return NULL;
54 }
55 for(unsigned z = 0 ; z < sizeof(ds->curpath) / sizeof(*ds->curpath) ; ++z){
56 ds->curpath[z] = UINT_MAX;
57 }
58 return ds;
59 }
60
docstructure_free(docstructure * ds)61 void docstructure_free(docstructure* ds){
62 if(ds){
63 nctree_destroy(ds->nct);
64 free(ds);
65 }
66 }
67
68 static void
docnode_free(docnode * dn)69 docnode_free(docnode* dn){
70 if(dn){
71 free(dn->title);
72 free(dn);
73 }
74 }
75
76 static docnode*
docnode_create(const char * title,int line,docstruct_e level)77 docnode_create(const char* title, int line, docstruct_e level){
78 docnode* dn = malloc(sizeof(*dn));
79 if(dn == NULL){
80 return NULL;
81 }
82 if((dn->title = strdup(title)) == NULL){
83 free(dn);
84 return NULL;
85 }
86 dn->level = level;
87 dn->line = line;
88 return dn;
89 }
90
91 // add the specified [sub]section to the document strucure. |line| refers to
92 // the row on the display plane, *not* the line in the original content.
docstructure_add(docstructure * ds,const char * title,int line,docstruct_e level)93 int docstructure_add(docstructure* ds, const char* title, int line,
94 docstruct_e level){
95 unsigned addpath[sizeof(ds->curpath) / sizeof(*ds->curpath)];
96 if(level < 0 || (unsigned)level >= sizeof(addpath) / sizeof(*addpath) - 1){
97 fprintf(stderr, "invalid level %d\n", level);
98 return -1;
99 }
100 docnode* dn = docnode_create(title, line, level);
101 if(dn == NULL){
102 return -1;
103 }
104 unsigned z = 0;
105 while(z < level){
106 if((addpath[z] = ds->curpath[z]) == UINT_MAX){
107 ds->curpath[z] = 0;
108 addpath[z] = 0;
109 }
110 ++z;
111 }
112 addpath[z] = ds->curpath[z] + 1;
113 addpath[z + 1] = UINT_MAX;
114 struct nctree_item nitem = {
115 .curry = dn,
116 };
117 if(nctree_add(ds->nct, addpath, &nitem)){
118 docnode_free(dn);
119 return -1;
120 }
121 ds->curpath[z] = addpath[z];
122 if(nctree_redraw(ds->nct)){
123 return -1;
124 }
125 return 0;
126 }
127