[tfman] move structure browser along with page #2457

This commit is contained in:
nick black 2021-12-15 01:42:48 -05:00
parent e49394a702
commit 7f05f5281d
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC
5 changed files with 211 additions and 163 deletions

View File

@ -11,6 +11,7 @@
#include <notcurses/notcurses.h>
#include "structure.h"
#include "builddef.h"
#include "parse.h"
static void
usage(const char* argv0, FILE* o){
@ -163,158 +164,6 @@ get_troff_data(const char *arg, size_t* len){
return buf;
}
typedef enum {
LINE_UNKNOWN,
LINE_COMMENT,
LINE_B, LINE_BI, LINE_BR, LINE_I, LINE_IB, LINE_IR,
LINE_RB, LINE_RI, LINE_SB, LINE_SM,
LINE_EE, LINE_EX, LINE_RE, LINE_RS,
LINE_SH, LINE_SS, LINE_TH,
LINE_IP, LINE_LP, LINE_P, LINE_PP,
LINE_TP, LINE_TQ,
LINE_ME, LINE_MT, LINE_UE, LINE_UR,
LINE_OP, LINE_SY, LINE_YS,
LINE_NF, LINE_FI,
} ltypes;
typedef enum {
TROFF_UNKNOWN,
TROFF_COMMENT,
TROFF_FONT,
TROFF_STRUCTURE,
TROFF_PARAGRAPH,
TROFF_HYPERLINK,
TROFF_SYNOPSIS,
TROFF_PREFORMATTED,
} ttypes;
typedef struct {
ltypes ltype;
const char* symbol;
ttypes ttype;
uint32_t channel;
} trofftype;
// all troff types start with a period, followed by one or two ASCII
// characters.
static const trofftype trofftypes[] = {
{ .ltype = LINE_UNKNOWN, .symbol = "", .ttype = TROFF_UNKNOWN, .channel = 0, },
{ .ltype = LINE_COMMENT, .symbol = "\\\"", .ttype = TROFF_COMMENT, .channel = 0, },
#define TROFF_FONT(x) { .ltype = LINE_##x, .symbol = #x, .ttype = TROFF_FONT, .channel = 0, },
TROFF_FONT(B) TROFF_FONT(BI) TROFF_FONT(BR)
TROFF_FONT(I) TROFF_FONT(IB) TROFF_FONT(IR)
#undef TROFF_FONT
#define TROFF_STRUCTURE(x, c) { .ltype = LINE_##x, .symbol = #x, .ttype = TROFF_STRUCTURE, .channel = (c), },
TROFF_STRUCTURE(EE, 0)
TROFF_STRUCTURE(EX, 0)
TROFF_STRUCTURE(RE, 0)
TROFF_STRUCTURE(RS, 0)
TROFF_STRUCTURE(SH, NCCHANNEL_INITIALIZER(0x9b, 0x9b, 0xfc))
TROFF_STRUCTURE(SS, NCCHANNEL_INITIALIZER(0x6c, 0x6b, 0xfb))
TROFF_STRUCTURE(TH, NCCHANNEL_INITIALIZER(0xcb, 0xcb, 0xfd))
#undef TROFF_STRUCTURE
#define TROFF_PARA(x) { .ltype = LINE_##x, .symbol = #x, .ttype = TROFF_PARAGRAPH, .channel = 0, },
TROFF_PARA(IP) TROFF_PARA(LP) TROFF_PARA(P)
TROFF_PARA(PP) TROFF_PARA(TP) TROFF_PARA(TQ)
#undef TROFF_PARA
#define TROFF_HLINK(x) { .ltype = LINE_##x, .symbol = #x, .ttype = TROFF_HYPERLINK, .channel = 0, },
TROFF_HLINK(ME) TROFF_HLINK(MT) TROFF_HLINK(UE) TROFF_HLINK(UR)
#undef TROFF_HLINK
#define TROFF_SYNOPSIS(x) { .ltype = LINE_##x, .symbol = #x, .ttype = TROFF_SYNOPSIS, .channel = 0, },
TROFF_SYNOPSIS(OP) TROFF_SYNOPSIS(SY) TROFF_SYNOPSIS(YS)
#undef TROFF_SYNOPSIS
{ .ltype = LINE_UNKNOWN, .symbol = "hy", .ttype = TROFF_UNKNOWN, .channel = 0, },
{ .ltype = LINE_UNKNOWN, .symbol = "br", .ttype = TROFF_UNKNOWN, .channel = 0, },
{ .ltype = LINE_COMMENT, .symbol = "IX", .ttype = TROFF_COMMENT, .channel = 0, },
{ .ltype = LINE_NF, .symbol = "nf", .ttype = TROFF_FONT, .channel = 0, },
{ .ltype = LINE_FI, .symbol = "fi", .ttype = TROFF_FONT, .channel = 0, },
};
// the troff trie is only defined on the 128 ascii values.
struct troffnode {
struct troffnode* next[0x80];
const trofftype *ttype;
};
static void
destroy_trofftrie(struct troffnode* root){
if(root){
for(unsigned i = 0 ; i < sizeof(root->next) / sizeof(*root->next) ; ++i){
destroy_trofftrie(root->next[i]);
}
free(root);
}
}
// build a trie rooted at an implicit leading period.
static struct troffnode*
trofftrie(void){
struct troffnode* root = malloc(sizeof(*root));
if(root == NULL){
return NULL;
}
memset(root, 0, sizeof(*root));
for(size_t toff = 0 ; toff < sizeof(trofftypes) / sizeof(*trofftypes) ; ++toff){
const trofftype* t = &trofftypes[toff];
if(strlen(t->symbol) == 0){
continue;
}
struct troffnode* n = root;
for(const char* s = t->symbol ; *s ; ++s){
if(*s <= 0){ // illegal symbol
fprintf(stderr, "illegal symbol: %s\n", t->symbol);
goto err;
}
unsigned char us = *s;
if(us > sizeof(root->next) / sizeof(*root->next)){ // illegal symbol
fprintf(stderr, "illegal symbol: %s\n", t->symbol);
goto err;
}
if(n->next[us] == NULL){
if((n->next[us] = malloc(sizeof(*root))) == NULL){
goto err;
}
memset(n->next[us], 0, sizeof(*root));
}
n = n->next[us];
}
if(n->ttype){ // duplicate command
fprintf(stderr, "duplicate command: %s %s\n", t->symbol, n->ttype->symbol);
goto err;
}
n->ttype = t;
}
return root;
err:
destroy_trofftrie(root);
return NULL;
}
// lex the troffnode out from |ws|, where the troffnode is all text prior to
// whitespace or a NUL. the byte following the troffnode is written back to
// |ws|. if it is a valid troff command sequence, the node is returned;
// NULL is otherwise returned. |len| ought be non-negative.
static const trofftype*
get_type(const struct troffnode* trie, const unsigned char** ws, size_t len){
if(**ws != '.'){
return NULL;
}
++*ws;
--len;
while(len && !isspace(**ws) && **ws){
if(**ws > sizeof(trie->next) / sizeof(*trie->next)){ // illegal command
return NULL;
}
if((trie = trie->next[**ws]) == NULL){
return NULL;
}
++*ws;
--len;
}
return trie->ttype;
}
typedef struct pagenode {
char* text;
const trofftype* ttype;
@ -710,9 +559,11 @@ draw_domnode(struct ncplane* p, const pagedom* dom, const pagenode* n,
unsigned* wrotetext){
ncplane_set_fchannel(p, n->ttype->channel);
size_t b = 0;
unsigned y;
ncplane_cursor_yx(p, &y, NULL);
switch(n->ttype->ltype){
case LINE_TH:
if(docstructure_add(dom->ds, dom->title, ncplane_y(p), DOCSTRUCTURE_TITLE)){
if(docstructure_add(dom->ds, dom->title, ncplane_y(p), DOCSTRUCTURE_TITLE, y)){
return -1;
}
/*
@ -722,7 +573,7 @@ draw_domnode(struct ncplane* p, const pagedom* dom, const pagenode* n,
ncplane_set_styles(p, NCSTYLE_NONE);
*/break;
case LINE_SH: // section heading
if(docstructure_add(dom->ds, n->text, ncplane_y(p), DOCSTRUCTURE_SECTION)){
if(docstructure_add(dom->ds, n->text, ncplane_y(p), DOCSTRUCTURE_SECTION, y)){
return -1;
}
if(strcmp(n->text, "NAME")){
@ -735,7 +586,7 @@ draw_domnode(struct ncplane* p, const pagedom* dom, const pagenode* n,
}
break;
case LINE_SS: // subsection heading
if(docstructure_add(dom->ds, n->text, ncplane_y(p), DOCSTRUCTURE_SUBSECTION)){
if(docstructure_add(dom->ds, n->text, ncplane_y(p), DOCSTRUCTURE_SUBSECTION, y)){
return -1;
}
ncplane_puttext(p, -1, NCALIGN_LEFT, "\n\n", &b);
@ -997,6 +848,8 @@ manloop(struct notcurses* nc, const char* arg){
ret = 0;
goto done;
}
unsigned newy = ncplane_y(page);
docstructure_move(dom.ds, newy);
}while(key != (uint32_t)-1);
done:

114
src/man/parse.c Normal file
View File

@ -0,0 +1,114 @@
#include <notcurses/notcurses.h>
#include "parse.h"
// all troff types start with a period, followed by one or two ASCII
// characters.
static const trofftype trofftypes[] = {
{ .ltype = LINE_UNKNOWN, .symbol = "", .ttype = TROFF_UNKNOWN, .channel = 0, },
{ .ltype = LINE_COMMENT, .symbol = "\\\"", .ttype = TROFF_COMMENT, .channel = 0, },
#define TROFF_FONT(x) { .ltype = LINE_##x, .symbol = #x, .ttype = TROFF_FONT, .channel = 0, },
TROFF_FONT(B) TROFF_FONT(BI) TROFF_FONT(BR)
TROFF_FONT(I) TROFF_FONT(IB) TROFF_FONT(IR)
#undef TROFF_FONT
#define TROFF_STRUCTURE(x, c) { .ltype = LINE_##x, .symbol = #x, .ttype = TROFF_STRUCTURE, .channel = (c), },
TROFF_STRUCTURE(EE, 0)
TROFF_STRUCTURE(EX, 0)
TROFF_STRUCTURE(RE, 0)
TROFF_STRUCTURE(RS, 0)
TROFF_STRUCTURE(SH, NCCHANNEL_INITIALIZER(0x9b, 0x9b, 0xfc))
TROFF_STRUCTURE(SS, NCCHANNEL_INITIALIZER(0x6c, 0x6b, 0xfb))
TROFF_STRUCTURE(TH, NCCHANNEL_INITIALIZER(0xcb, 0xcb, 0xfd))
#undef TROFF_STRUCTURE
#define TROFF_PARA(x) { .ltype = LINE_##x, .symbol = #x, .ttype = TROFF_PARAGRAPH, .channel = 0, },
TROFF_PARA(IP) TROFF_PARA(LP) TROFF_PARA(P)
TROFF_PARA(PP) TROFF_PARA(TP) TROFF_PARA(TQ)
#undef TROFF_PARA
#define TROFF_HLINK(x) { .ltype = LINE_##x, .symbol = #x, .ttype = TROFF_HYPERLINK, .channel = 0, },
TROFF_HLINK(ME) TROFF_HLINK(MT) TROFF_HLINK(UE) TROFF_HLINK(UR)
#undef TROFF_HLINK
#define TROFF_SYNOPSIS(x) { .ltype = LINE_##x, .symbol = #x, .ttype = TROFF_SYNOPSIS, .channel = 0, },
TROFF_SYNOPSIS(OP) TROFF_SYNOPSIS(SY) TROFF_SYNOPSIS(YS)
#undef TROFF_SYNOPSIS
{ .ltype = LINE_UNKNOWN, .symbol = "hy", .ttype = TROFF_UNKNOWN, .channel = 0, },
{ .ltype = LINE_UNKNOWN, .symbol = "br", .ttype = TROFF_UNKNOWN, .channel = 0, },
{ .ltype = LINE_COMMENT, .symbol = "IX", .ttype = TROFF_COMMENT, .channel = 0, },
{ .ltype = LINE_NF, .symbol = "nf", .ttype = TROFF_FONT, .channel = 0, },
{ .ltype = LINE_FI, .symbol = "fi", .ttype = TROFF_FONT, .channel = 0, },
};
void destroy_trofftrie(struct troffnode* root){
if(root){
for(unsigned i = 0 ; i < sizeof(root->next) / sizeof(*root->next) ; ++i){
destroy_trofftrie(root->next[i]);
}
free(root);
}
}
// build a trie rooted at an implicit leading period.
struct troffnode* trofftrie(void){
struct troffnode* root = malloc(sizeof(*root));
if(root == NULL){
return NULL;
}
memset(root, 0, sizeof(*root));
for(size_t toff = 0 ; toff < sizeof(trofftypes) / sizeof(*trofftypes) ; ++toff){
const trofftype* t = &trofftypes[toff];
if(strlen(t->symbol) == 0){
continue;
}
struct troffnode* n = root;
for(const char* s = t->symbol ; *s ; ++s){
if(*s <= 0){ // illegal symbol
fprintf(stderr, "illegal symbol: %s\n", t->symbol);
goto err;
}
unsigned char us = *s;
if(us > sizeof(root->next) / sizeof(*root->next)){ // illegal symbol
fprintf(stderr, "illegal symbol: %s\n", t->symbol);
goto err;
}
if(n->next[us] == NULL){
if((n->next[us] = malloc(sizeof(*root))) == NULL){
goto err;
}
memset(n->next[us], 0, sizeof(*root));
}
n = n->next[us];
}
if(n->ttype){ // duplicate command
fprintf(stderr, "duplicate command: %s %s\n", t->symbol, n->ttype->symbol);
goto err;
}
n->ttype = t;
}
return root;
err:
destroy_trofftrie(root);
return NULL;
}
// lex the troffnode out from |ws|, where the troffnode is all text prior to
// whitespace or a NUL. the byte following the troffnode is written back to
// |ws|. if it is a valid troff command sequence, the node is returned;
// NULL is otherwise returned. |len| ought be non-negative.
const trofftype* get_type(const struct troffnode* trie, const unsigned char** ws,
size_t len){
if(**ws != '.'){
return NULL;
}
++*ws;
--len;
while(len && !isspace(**ws) && **ws){
if(**ws > sizeof(trie->next) / sizeof(*trie->next)){ // illegal command
return NULL;
}
if((trie = trie->next[**ws]) == NULL){
return NULL;
}
++*ws;
--len;
}
return trie->ttype;
}

60
src/man/parse.h Normal file
View File

@ -0,0 +1,60 @@
#ifndef NOTCURSES_MAN_PARSE
#define NOTCURSES_MAN_PRASE
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdint.h>
typedef enum {
LINE_UNKNOWN,
LINE_COMMENT,
LINE_B, LINE_BI, LINE_BR, LINE_I, LINE_IB, LINE_IR,
LINE_RB, LINE_RI, LINE_SB, LINE_SM,
LINE_EE, LINE_EX, LINE_RE, LINE_RS,
LINE_SH, LINE_SS, LINE_TH,
LINE_IP, LINE_LP, LINE_P, LINE_PP,
LINE_TP, LINE_TQ,
LINE_ME, LINE_MT, LINE_UE, LINE_UR,
LINE_OP, LINE_SY, LINE_YS,
LINE_NF, LINE_FI,
} ltypes;
typedef enum {
TROFF_UNKNOWN,
TROFF_COMMENT,
TROFF_FONT,
TROFF_STRUCTURE,
TROFF_PARAGRAPH,
TROFF_HYPERLINK,
TROFF_SYNOPSIS,
TROFF_PREFORMATTED,
} ttypes;
typedef struct {
ltypes ltype;
const char* symbol;
ttypes ttype;
uint32_t channel;
} trofftype;
// the troff trie is only defined on the 128 ascii values.
struct troffnode {
struct troffnode* next[0x80];
const trofftype *ttype;
};
const trofftype*
get_type(const struct troffnode* trie, const unsigned char** ws, size_t len);
struct troffnode* trofftrie(void);
void destroy_trofftrie(struct troffnode* root);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -8,12 +8,14 @@ typedef struct docnode {
char* title;
int line;
docstruct_e level;
unsigned y;
} docnode;
typedef struct docstructure {
struct nctree* nct;
// one entry for each hierarchy level + terminator
unsigned curpath[HIERARCHY_MAX + 1];
unsigned cury;
bool visible;
} docstructure;
@ -22,10 +24,10 @@ docstruct_callback(struct ncplane* n, void* curry, int i){
if(n){
docnode* dn = curry;
uint64_t channels =
NCCHANNELS_INITIALIZER(0xff, 0xff, 0xff, 0x49, (0x9d - 0x10 * i), 0x63);
NCCHANNELS_INITIALIZER(0xff, 0xff, 0xff, 0x49,
(0x9d - 0x8 * i), (0x9d + 0x8 * i));
ncplane_set_channels(n, channels);
ncplane_erase(n);
//ncplane_putstr(n, dn->title);
ncplane_putstr_aligned(n, 0, NCALIGN_RIGHT, dn->title);
ncplane_resize_simple(n, 1, ncplane_dim_x(n));
(void)i;
@ -62,6 +64,7 @@ docstructure* docstructure_create(struct ncplane* n){
ds->curpath[z] = UINT_MAX;
}
ds->visible = true;
ds->cury = 0;
return ds;
}
@ -93,7 +96,7 @@ docnode_free(docnode* dn){
}
static docnode*
docnode_create(const char* title, int line, docstruct_e level){
docnode_create(const char* title, int line, docstruct_e level, unsigned y){
docnode* dn = malloc(sizeof(*dn));
if(dn == NULL){
return NULL;
@ -104,19 +107,20 @@ docnode_create(const char* title, int line, docstruct_e level){
}
dn->level = level;
dn->line = line;
dn->y = y;
return dn;
}
// add the specified [sub]section to the document strucure. |line| refers to
// the row on the display plane, *not* the line in the original content.
int docstructure_add(docstructure* ds, const char* title, int line,
docstruct_e level){
docstruct_e level, unsigned y){
unsigned addpath[sizeof(ds->curpath) / sizeof(*ds->curpath)];
if(level < 0 || (unsigned)level >= sizeof(addpath) / sizeof(*addpath) - 1){
fprintf(stderr, "invalid level %d\n", level);
return -1;
}
docnode* dn = docnode_create(title, line, level);
docnode* dn = docnode_create(title, line, level, y);
if(dn == NULL){
return -1;
}
@ -144,3 +148,17 @@ int docstructure_add(docstructure* ds, const char* title, int line,
}
return 0;
}
int docstructure_move(docstructure* ds, unsigned newy){
// FIXME might need to do multiple moves!
if(newy > ds->cury){
nctree_prev(ds->nct);
}else if(newy < ds->cury){
nctree_next(ds->nct);
}
ds->cury = newy;
if(nctree_redraw(ds->nct)){
return -1;
}
return 0;
}

View File

@ -1,5 +1,5 @@
#ifndef ncplane_MAN_STRUCTURE
#define ncplane_MAN_STRUCTURE
#ifndef NOTCURSES_MAN_STRUCTURE
#define NOTCURSES_MAN_STRUCTURE
#ifdef __cplusplus
extern "C" {
@ -22,7 +22,10 @@ void docstructure_toggle(struct ncplane* p, struct ncplane* b, struct docstructu
// add the specified [sub]section to the document strucure. |line| refers to
// the row on the display plane, *not* the line in the original content.
int docstructure_add(struct docstructure* ds, const char* title, int line,
docstruct_e level);
docstruct_e level, unsigned y);
// update the docstructure browser based off a move of the page plane from to |newy|.
int docstructure_move(struct docstructure* ds, unsigned newy);
#ifdef __cplusplus
}