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