view: support -m argument for margins #551

pull/555/head
nick black 4 years ago
parent 6e8a0bebae
commit 84107c547d
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC

@ -98,6 +98,11 @@ typedef struct notcurses_options {
int margin_t, margin_r, margin_b, margin_l;
} notcurses_options;
// Lex a margin argument according to the standard notcurses definition. There
// can be either a single number, which will define all margins equally, or
// there can be four numbers separated by commas.
int notcurses_lex_margins(const char* op, notcurses_options* opts);
// Initialize a notcurses context on the connected terminal at 'fp'. 'fp' must
// be a tty. You'll usually want stdout. Returns NULL on error, including any
// failure initializing terminfo.

@ -23,10 +23,17 @@ and videos to the terminal. Media will be scaled to the terminal's size.
**-s scalemode**: Scaling mode, one of **none**, **scale**, or **stretch**.
**-m margins**: Define rendering margins (see below).
**-k**: Inhibit use of the alternate screen. Necessary if you want the output left on your terminal after the program exits.
files: Select which files to render, and what order to render them in.
Default margins are all 0, and thus the full screen will be rendered. Using
**-m**, margins can be supplied. Provide a single number to set all four margins
to the same value, or four comma-delimited values for the top, right, bottom,
and left margins respectively. Negative margins are illegal.
# NOTES
Optimal display requires a terminal advertising the **rgb** terminfo(5)

@ -97,6 +97,7 @@ particular EGC is heavily reused within a plane.
A few high-level widgets are included, all built atop ncplanes:
* **notcurses_fds(3)** for dumping file descriptors/subprocesses to a plane
* **notcurses_menu(3)** for menu bars at the top or bottom of the screen
* **notcurses_multiselector(3)** for selecting one or more items from a set
* **notcurses_plot(3)** for drawing histograms and lineplots

@ -23,7 +23,9 @@ typedef struct notcurses_options {
} notcurses_options;
```
**struct notcurses* notcurses_init(const struct notcurses_options* opts, FILE* fp);**
**int notcurses_lex_margins(const char* op, notcurses_options* opts);**
**struct notcurses* notcurses_init(const notcurses_options* opts, FILE* fp);**
# DESCRIPTION
@ -67,7 +69,11 @@ the full screen cleared, followed by rendering to a subregion. Inhibiting the
alternate screen plus margins will see rendering to a subregion, with the screen
outside this region not cleared. This is the only means by which existing
output can be undisturbed by notcurses. Margins are best-effort. Supplying any
negative margin is an error.
negative margin is an error. **notcurses_lex_margins** provides lexing a
margin argument expression in one of two forms:
* a single number, which will be applied to all sides, or
* four comma-delimited numbers, applied to top, right, bottom, and left.
## Fatal signals

@ -785,6 +785,11 @@ typedef struct notcurses_options {
int margin_t, margin_r, margin_b, margin_l;
} notcurses_options;
// Lex a margin argument according to the standard notcurses definition. There
// can be either a single number, which will define all margins equally, or
// there can be four numbers separated by commas.
API int notcurses_lex_margins(const char* op, notcurses_options* opts);
// Initialize a notcurses context on the connected terminal at 'fp'. 'fp' must
// be a tty. You'll usually want stdout. Returns NULL on error, including any
// failure initializing terminfo.

@ -79,6 +79,7 @@ typedef struct notcurses_options {
int margin_t, margin_r, margin_b, margin_l;
} notcurses_options;
struct notcurses* notcurses_init(const notcurses_options*, FILE*);
int notcurses_lex_margins(const char* op, notcurses_options* opts);
int notcurses_stop(struct notcurses*);
int notcurses_render(struct notcurses*);
struct ncplane* notcurses_stdplane(struct notcurses*);

@ -127,53 +127,6 @@ usage(const char* exe, int status){
exit(status);
}
// extract an integer, which must be non-negative, and followed by either a
// comma or a NUL terminator.
static int
lex_long(const char* op, int* i, char** endptr){
errno = 0;
long l = strtol(op, endptr, 10);
if(l < 0 || (l == LONG_MAX && errno == ERANGE) || (l > INT_MAX)){
fprintf(stderr, "Invalid margin: %s\n", op);
return -1;
}
if((**endptr != ',' && **endptr) || *endptr == op){
fprintf(stderr, "Invalid margin: %s\n", op);
return -1;
}
*i = l;
return 0;
}
static int
lex_margins(const char* op, notcurses_options* opts){
if(opts->margin_t || opts->margin_r || opts->margin_b || opts->margin_l){
fprintf(stderr, "Provided margins twice!\n");
return -1;
}
char* eptr;
if(lex_long(op, &opts->margin_t, &eptr)){
return -1;
}
if(!*eptr){ // allow a single value to be specified for all four margins
opts->margin_r = opts->margin_l = opts->margin_b = opts->margin_t;
return 0;
}
op = ++eptr; // once here, we require four values
if(lex_long(op, &opts->margin_r, &eptr) || !*eptr){
return -1;
}
op = ++eptr;
if(lex_long(op, &opts->margin_b, &eptr) || !*eptr){
return -1;
}
op = ++eptr;
if(lex_long(op, &opts->margin_l, &eptr) || *eptr){ // must end in NUL
return -1;
}
return 0;
}
static demoresult*
ext_demos(struct notcurses* nc, const char* spec, bool ignore_failures){
int ret = 0;
@ -255,7 +208,11 @@ handle_opts(int argc, char** argv, notcurses_options* opts, bool* ignore_failure
}
break;
}case 'm':{
if(lex_margins(optarg, opts)){
if(opts->margin_t || opts->margin_r || opts->margin_b || opts->margin_l){
fprintf(stderr, "Provided margins twice!\n");
usage(*argv, EXIT_FAILURE);
}
if(notcurses_lex_margins(optarg, opts)){
usage(*argv, EXIT_FAILURE);
}
break;

@ -1897,3 +1897,45 @@ bool ncplane_set_scrolling(ncplane* n, bool scrollp){
n->scrolling = scrollp;
return old;
}
// extract an integer, which must be non-negative, and followed by either a
// comma or a NUL terminator.
static int
lex_long(const char* op, int* i, char** endptr){
errno = 0;
long l = strtol(op, endptr, 10);
if(l < 0 || (l == LONG_MAX && errno == ERANGE) || (l > INT_MAX)){
fprintf(stderr, "Invalid margin: %s\n", op);
return -1;
}
if((**endptr != ',' && **endptr) || *endptr == op){
fprintf(stderr, "Invalid margin: %s\n", op);
return -1;
}
*i = l;
return 0;
}
int notcurses_lex_margins(const char* op, notcurses_options* opts){
char* eptr;
if(lex_long(op, &opts->margin_t, &eptr)){
return -1;
}
if(!*eptr){ // allow a single value to be specified for all four margins
opts->margin_r = opts->margin_l = opts->margin_b = opts->margin_t;
return 0;
}
op = ++eptr; // once here, we require four values
if(lex_long(op, &opts->margin_r, &eptr) || !*eptr){
return -1;
}
op = ++eptr;
if(lex_long(op, &opts->margin_b, &eptr) || !*eptr){
return -1;
}
op = ++eptr;
if(lex_long(op, &opts->margin_l, &eptr) || *eptr){ // must end in NUL
return -1;
}
return 0;
}

@ -17,10 +17,11 @@ static void usage(std::ostream& os, const char* name, int exitcode)
__attribute__ ((noreturn));
void usage(std::ostream& o, const char* name, int exitcode){
o << "usage: " << name << " [ -h ] [ -l loglevel ] [ -d mult ] [ -s scaletype ] [ -k ] files" << '\n';
o << "usage: " << name << " [ -h ] [ -m margins ] [ -l loglevel ] [ -d mult ] [ -s scaletype ] [ -k ] files" << '\n';
o << " -k: don't use the alternate screen\n";
o << " -l loglevel: integer between 0 and 9, goes to stderr'\n";
o << " -s scaletype: one of 'none', 'scale', or 'stretch'\n";
o << " -m margins: margin, or 4 comma-separated margins\n";
o << " -d mult: non-negative floating point scale for frame time" << std::endl;
exit(exitcode);
}
@ -104,7 +105,7 @@ int handle_opts(int argc, char** argv, notcurses_options& opts, float* timescale
*timescale = 1.0;
*scalemode = NCScale::Scale;
int c;
while((c = getopt(argc, argv, "hl:d:s:k")) != -1){
while((c = getopt(argc, argv, "hl:d:s:m:k")) != -1){
switch(c){
case 'h':
usage(std::cout, argv[0], EXIT_SUCCESS);
@ -121,6 +122,15 @@ int handle_opts(int argc, char** argv, notcurses_options& opts, float* timescale
case 'k':{
opts.inhibit_alternate_screen = true;
break;
}case 'm':{
if(opts.margin_t || opts.margin_r || opts.margin_b || opts.margin_l){
std::cerr << "Provided margins twice!" << std::endl;
usage(std::cerr, argv[0], EXIT_FAILURE);
}
if(notcurses_lex_margins(optarg, &opts)){
usage(std::cerr, argv[0], EXIT_FAILURE);
}
break;
}case 'd':{
std::stringstream ss;
ss << optarg;

Loading…
Cancel
Save