mirror of
https://github.com/dankamongmen/notcurses
synced 2025-03-09 17:19:03 -04:00
ncneofetch rewritten in CLI mode
ncneofetch was previously direct mode followed by rendered mode with margins, a Frankenstein application if one ever existed. Rewrite it using CLI mode, extending the latter as necessary to accomplish this task. We now have one fewer dependency on direct mode, we have better proven out CLI mode, and we get a ~30% reduction in ncneofetch runtime. Good stuff! Closes #2030. Add ncplane_scrollup() and ncplane_scrollup_child() Cleans up ncport.h Eliminates some inconsequential memory leaks in ncneofetch Add SPRIXEL_UNSEEN to avoid invalid moves on not-yet-displayed sprixels
This commit is contained in:
parent
47fa86f90d
commit
4d6526a61d
4
NEWS.md
4
NEWS.md
@ -2,6 +2,10 @@ This document attempts to list user-visible changes and any major internal
|
||||
rearrangements of Notcurses.
|
||||
|
||||
* 2.3.14 (not yet released)
|
||||
* `ncneofetch` has been changed to use "CLI mode" instead of Direct Mode,
|
||||
as a proof of concept. It is very likely that Direct Mode will be
|
||||
deprecated for ABI3. New code ought not be written using it.
|
||||
* Added `ncplane_scrollup()` and `ncplane_scrollup_child()`.
|
||||
* Fixed grotesque errors in `ncplane_set_*_palindex()`.
|
||||
|
||||
* 2.3.13 (2021-08-04)
|
||||
|
9
USAGE.md
9
USAGE.md
@ -883,6 +883,15 @@ scrolling is enabled).
|
||||
// controlled with ncplane_set_scrolling(). Returns true if scrolling was
|
||||
// previously enabled, or false if it was disabled.
|
||||
bool ncplane_set_scrolling(struct ncplane* n, bool scrollp);
|
||||
|
||||
// Effect |r| scroll events on the plane |n|. Returns an error if |n| is not
|
||||
// a scrolling plane, and otherwise returns the number of lines scrolled.
|
||||
int ncplane_scrollup(struct ncplane* n, int r);
|
||||
|
||||
// Scroll |n| up until |child| is no longer hidden beneath it. Returns an
|
||||
// error if |child| is not a child of |n|, or |n| is not scrolling, or |child|
|
||||
// is fixed. Returns the number of scrolling events otherwise (might be 0).
|
||||
int ncplane_scrollup_child(struct ncplane* n, const struct ncplane* child);
|
||||
```
|
||||
|
||||
Planes can be freely resized, though they must retain a positive size in
|
||||
|
@ -209,6 +209,10 @@ typedef struct ncplane_options {
|
||||
|
||||
**bool ncplane_scrolling_p(const struct ncplane* ***n***);**
|
||||
|
||||
**int ncplane_scrollup(struct ncplane* ***n***, int ***r***);**
|
||||
|
||||
**int ncplane_scrollup_child(struct ncplane* ***n***, const struct ncplane* ***child***);**
|
||||
|
||||
**int ncplane_rotate_cw(struct ncplane* ***n***);**
|
||||
|
||||
**int ncplane_rotate_ccw(struct ncplane* ***n***);**
|
||||
|
@ -5,37 +5,30 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// take host byte order and turn it into network (reverse on LE, no-op on BE),
|
||||
// then reverse that, guaranteeing LE. htole(x) == ltohe(x).
|
||||
#if defined(__linux__) || defined(__gnu_hurd__)
|
||||
#include <poll.h>
|
||||
#include <termios.h>
|
||||
#include <byteswap.h>
|
||||
#include <netinet/in.h>
|
||||
#define htole(x) (__bswap_32(htonl(x)))
|
||||
#elif defined(__APPLE__)
|
||||
#include <poll.h>
|
||||
#include <termios.h>
|
||||
#include <netinet/in.h>
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#define htole(x) (OSSwapInt32(htonl(x)))
|
||||
#elif defined(__MINGW64__)
|
||||
#define htole(x) (x) // FIXME
|
||||
// Platform-dependent preprocessor material (includes and definitions) needed
|
||||
// to compile against Notcurses. A critical definition is htole(), which forces
|
||||
// 32-bit values to little-endian (as used in the nccell gcluster field). This
|
||||
// ought be defined so that it's a a no-op on little-endian builds.
|
||||
|
||||
#if defined(__MINGW64__) // Windows
|
||||
// FIXME placeholders, need real solutions here
|
||||
#define wcwidth(w) 1
|
||||
#define wcswidth(w, s) (s)
|
||||
#define sigset_t int
|
||||
#define sigemptyset(x)
|
||||
#define O_CLOEXEC O_NOINHERIT
|
||||
#define O_NONBLOCK 0
|
||||
#define O_DIRECTORY 0
|
||||
#define S_IFLNK 0
|
||||
#else // bsd
|
||||
#define htole(x) (x) // FIXME are all windows installs LE?
|
||||
#else // Non-Windows, UNIX-common
|
||||
#include <poll.h>
|
||||
#include <netinet/in.h>
|
||||
#include <termios.h>
|
||||
#if defined(__linux__) || defined(__gnu_hurd__) // Linux/Hurd
|
||||
#include <byteswap.h>
|
||||
#define htole(x) (__bswap_32(htonl(x)))
|
||||
#elif defined(__APPLE__) // macOS
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#define htole(x) (OSSwapInt32(htonl(x)))
|
||||
#else // BSD
|
||||
#include <sys/endian.h>
|
||||
#define htole(x) (bswap32(htonl(x)))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
@ -1570,8 +1570,23 @@ API int ncplane_move_below(struct ncplane* RESTRICT n,
|
||||
struct ncplane* RESTRICT below);
|
||||
|
||||
// Return the plane below this one, or NULL if this is at the bottom.
|
||||
API struct ncplane* ncplane_below(struct ncplane* n);
|
||||
API struct ncplane* ncplane_above(struct ncplane* n);
|
||||
API struct ncplane* ncplane_below(struct ncplane* n)
|
||||
__attribute__ ((nonnull (1)));
|
||||
|
||||
// Return the plane above this one, or NULL if this is at the top.
|
||||
API struct ncplane* ncplane_above(struct ncplane* n)
|
||||
__attribute__ ((nonnull (1)));
|
||||
|
||||
// Effect |r| scroll events on the plane |n|. Returns an error if |n| is not
|
||||
// a scrolling plane, and otherwise returns the number of lines scrolled.
|
||||
API int ncplane_scrollup(struct ncplane* n, int r)
|
||||
__attribute__ ((nonnull (1)));
|
||||
|
||||
// Scroll |n| up until |child| is no longer hidden beneath it. Returns an
|
||||
// error if |child| is not a child of |n|, or |n| is not scrolling, or |child|
|
||||
// is fixed. Returns the number of scrolling events otherwise (might be 0).
|
||||
API int ncplane_scrollup_child(struct ncplane* n, const struct ncplane* child)
|
||||
__attribute__ ((nonnull (1, 2)));
|
||||
|
||||
// Rotate the plane π/2 radians clockwise or counterclockwise. This cannot
|
||||
// be performed on arbitrary planes, because glyphs cannot be arbitrarily
|
||||
|
@ -17,6 +17,7 @@ extern "C" {
|
||||
|
||||
#ifdef __MINGW64__
|
||||
#include <Lmcons.h>
|
||||
#define wcswidth(w, s) (s)
|
||||
#define tcgetattr(x, y) -1
|
||||
#define tcsetattr(x, y, z) -1
|
||||
#define ECHO 0
|
||||
@ -27,6 +28,10 @@ extern "C" {
|
||||
#define TCSAFLUSH 0
|
||||
#define TCSANOW 0
|
||||
#define O_NOCTTY 0
|
||||
#define O_CLOEXEC O_NOINHERIT
|
||||
#define O_NONBLOCK 0
|
||||
#define O_DIRECTORY 0
|
||||
#define S_IFLNK 0
|
||||
#define SA_SIGINFO 0
|
||||
#define SA_RESETHAND 0
|
||||
#define SIGQUIT 0
|
||||
|
@ -200,8 +200,8 @@ int unicodeblocks_demo(struct notcurses* nc){
|
||||
{ .name = "CJK Compatibility Ideographs, Alphabetic Presentation Forms", .start = 0xfa00, },
|
||||
{ .name = "Arabic Presentation Forms-A", .start = 0xfc00, },
|
||||
{ .name = "Halfwidth and Fullwidth Forms", .start = 0xfe00, },
|
||||
{ .name = "Linear B Syllabary, Linear B Ideograms, Aegean Numbers, Phaistos Disc", .start = 0x10000, },
|
||||
{ .name = "Lycian, Carian, Coptic Epact Numbers, Old Italic, Gothic, Old Permic", .start = 0x10200, },
|
||||
{ .name = "Linear B Syllabary, Linear B Ideograms, Aegean, Phaistos Disc", .start = 0x10000, },
|
||||
{ .name = "Lycian, Carian, Coptic Epact, Old Italic, Gothic, Old Permic", .start = 0x10200, },
|
||||
{ .name = "Cuneiform", .start = 0x12000, },
|
||||
{ .name = "Cuneiform (cont.)", .start = 0x12200, },
|
||||
{ .name = "Byzantine Musical Symbols, Musical Symbols", .start = 0x1d000, },
|
||||
@ -278,10 +278,10 @@ int unicodeblocks_demo(struct notcurses* nc){
|
||||
if(ncplane_set_fg_rgb8(n, 0x40, 0xc0, 0x40)){
|
||||
return -1;
|
||||
}
|
||||
if(ncplane_cursor_move_yx(n, 6 + BLOCKSIZE / CHUNKSIZE, 2)){
|
||||
if(ncplane_cursor_move_yx(n, 6 + BLOCKSIZE / CHUNKSIZE, 4)){
|
||||
return -1;
|
||||
}
|
||||
if(ncplane_printf(n, "%*.*s", maxx - 4, maxx - 4, "") <= 0){
|
||||
if(ncplane_printf(n, "%*.*s", maxx - 8, maxx - 8, "") <= 0){
|
||||
return -1;
|
||||
}
|
||||
if(ncplane_printf_aligned(n, 6 + BLOCKSIZE / CHUNKSIZE, NCALIGN_CENTER, "%s", description) <= 0){
|
||||
|
@ -48,7 +48,12 @@ typedef struct fetched_info {
|
||||
static void
|
||||
free_fetched_info(fetched_info* fi){
|
||||
free(fi->cpu_model);
|
||||
free(fi->hostname);
|
||||
free(fi->username);
|
||||
free(fi->kernel);
|
||||
free(fi->kernver);
|
||||
free(fi->distro_pretty);
|
||||
free(fi->term);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -337,7 +342,7 @@ xnu_ncneofetch(fetched_info* fi){
|
||||
.logofile = "/System/Library/PrivateFrameworks/LoginUIKit.framework/Versions/A/Frameworks/LoginUICore.framework/Versions/A/Resources/apple@2x.png",
|
||||
};
|
||||
fi->neologo = get_neofetch_art("Darwin");
|
||||
fi->distro_pretty = "OS X 11.4 (Big Sur)"; // FIXME
|
||||
fi->distro_pretty = strdup("OS X 11.4 (Big Sur)"); // FIXME
|
||||
return &fbsd;
|
||||
}
|
||||
|
||||
@ -380,9 +385,11 @@ static int
|
||||
infoplane_notcurses(struct notcurses* nc, const fetched_info* fi, int planeheight){
|
||||
const int planewidth = 72;
|
||||
int dimy;
|
||||
int y;
|
||||
struct ncplane* std = notcurses_stddim_yx(nc, &dimy, NULL);
|
||||
ncplane_cursor_yx(std, &y, NULL);
|
||||
struct ncplane_options nopts = {
|
||||
.y = dimy - planeheight,
|
||||
.y = y,
|
||||
.x = NCALIGN_CENTER,
|
||||
.rows = planeheight,
|
||||
.cols = planewidth,
|
||||
@ -428,7 +435,6 @@ infoplane_notcurses(struct notcurses* nc, const fetched_info* fi, int planeheigh
|
||||
}else{
|
||||
ncplane_printf_aligned(infop, 4, NCALIGN_LEFT, " TERM: %s", fi->term);
|
||||
}
|
||||
free(fi->term);
|
||||
ncplane_printf_aligned(infop, 4, NCALIGN_RIGHT, "Screen0: %dx%d ", fi->dimx, fi->dimy);
|
||||
ncplane_printf_aligned(infop, 5, NCALIGN_LEFT, " LANG: %s", fi->lang);
|
||||
#ifndef __MINGW64__
|
||||
@ -469,6 +475,7 @@ infoplane_notcurses(struct notcurses* nc, const fetched_info* fi, int planeheigh
|
||||
ncchannels_set_fg_rgb8(&channels, 0, 0, 0);
|
||||
ncchannels_set_bg_rgb8(&channels, 0x50, 0x50, 0x50);
|
||||
ncplane_set_base(infop, " ", 0, channels);
|
||||
ncplane_scrollup_child(std, infop);
|
||||
if(notcurses_render(nc)){
|
||||
return -1;
|
||||
}
|
||||
@ -522,7 +529,7 @@ neologo_present(struct notcurses* nc, const char* nlogo){
|
||||
struct ncplane* n = notcurses_stddim_yx(nc, &dimy, &dimx);
|
||||
const int leftpad = (dimx - maxlinelen) / 2;
|
||||
for(int i = 0 ; i < linecount ; ++i){
|
||||
printf("%*.*s%s", leftpad, leftpad, "", lines[i]);
|
||||
ncplane_printf(n, "%*.*s%s", leftpad, leftpad, "", lines[i]);
|
||||
free(lines[i]);
|
||||
}
|
||||
free(lines);
|
||||
@ -542,6 +549,8 @@ display_thread(void* vmarshal){
|
||||
struct marshal* m = vmarshal;
|
||||
drawpalette(m->nc);
|
||||
notcurses_render(m->nc);
|
||||
ncplane_set_bg_default(notcurses_stdplane(m->nc));
|
||||
ncplane_set_fg_default(notcurses_stdplane(m->nc));
|
||||
// we've just rendered, so any necessary scrolling has been performed. draw
|
||||
// our image wherever the palette ended, and then scroll as necessary to
|
||||
// make that new plane visible.
|
||||
@ -553,6 +562,8 @@ display_thread(void* vmarshal){
|
||||
ncv = ncvisual_from_file(m->dinfo->logofile);
|
||||
}
|
||||
if(ncv){
|
||||
int y;
|
||||
ncplane_cursor_yx(notcurses_stdplane_const(m->nc), &y, NULL);
|
||||
struct ncvisual_options vopts = {
|
||||
.x = NCALIGN_CENTER,
|
||||
.blitter = NCBLIT_PIXEL,
|
||||
@ -561,7 +572,14 @@ display_thread(void* vmarshal){
|
||||
};
|
||||
struct ncplane* iplane = ncvisual_render(m->nc, ncv, &vopts);
|
||||
ncvisual_destroy(ncv);
|
||||
if(iplane){
|
||||
ncplane_move_yx(iplane, y, 0);
|
||||
ncplane_scrollup_child(notcurses_stdplane(m->nc), iplane);
|
||||
notcurses_render(m->nc);
|
||||
ncplane_cursor_move_yx(notcurses_stdplane(m->nc),
|
||||
ncplane_abs_y(iplane) + ncplane_dim_y(iplane), 0);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(m->neologo){
|
||||
@ -627,12 +645,10 @@ ncneofetch(struct notcurses* nc){
|
||||
}
|
||||
|
||||
int main(void){
|
||||
if(setlocale(LC_ALL, "") == NULL){
|
||||
fprintf(stderr, "Warning: couldn't set locale based off LANG\n");
|
||||
}
|
||||
struct notcurses_options opts = {
|
||||
.flags = NCOPTION_SUPPRESS_BANNERS | NCOPTION_INHIBIT_SETLOCALE
|
||||
| NCOPTION_NO_ALTERNATE_SCREEN | NCOPTION_NO_CLEAR_BITMAPS
|
||||
.flags = NCOPTION_SUPPRESS_BANNERS
|
||||
| NCOPTION_NO_ALTERNATE_SCREEN
|
||||
| NCOPTION_NO_CLEAR_BITMAPS
|
||||
| NCOPTION_PRESERVE_CURSOR,
|
||||
};
|
||||
struct notcurses* nc = notcurses_init(&opts, NULL);
|
||||
|
@ -1145,10 +1145,8 @@ int kitty_draw(const tinfo* ti, const ncpile* p, sprixel* s, fbuf* f,
|
||||
}
|
||||
if(animated){
|
||||
fbuf_free(&s->glyph);
|
||||
s->invalidated = SPRIXEL_LOADED;
|
||||
}else{
|
||||
s->invalidated = SPRIXEL_LOADED;
|
||||
}
|
||||
s->invalidated = SPRIXEL_LOADED;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1544,6 +1544,43 @@ void scroll_down(ncplane* n){
|
||||
}
|
||||
}
|
||||
|
||||
int ncplane_scrollup(ncplane* n, int r){
|
||||
if(!ncplane_scrolling_p(n)){
|
||||
logerror("can't scroll %d on non-scrolling plane\n", r);
|
||||
return -1;
|
||||
}
|
||||
if(r < 0){
|
||||
logerror("can't scroll %d lines\n", r);
|
||||
return -1;
|
||||
}
|
||||
while(r-- > 0){
|
||||
scroll_down(n);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Scroll |n| up until |child| is no longer hidden beneath it. Returns an
|
||||
// error if |child| is not a child of |n|, or |n| is not scrolling, or |child|
|
||||
// is fixed. Returns the number of scrolling events otherwise (might be 0).
|
||||
int ncplane_scrollup_child(ncplane* n, const ncplane* child){
|
||||
if(ncplane_parent_const(child) != n){
|
||||
logerror("not a child of specified plane\n");
|
||||
return -1;
|
||||
}
|
||||
if(child->fixedbound){
|
||||
logerror("child plane is fixed\n");
|
||||
return -1;
|
||||
}
|
||||
int parend = ncplane_abs_y(n) + ncplane_dim_y(n); // where parent ends
|
||||
int chend = ncplane_abs_y(child) + ncplane_dim_y(child); // where child ends
|
||||
if(chend <= parend){
|
||||
return 0;
|
||||
}
|
||||
int r = chend - parend; // how many rows we need scroll parent
|
||||
int ret = ncplane_scrollup(n, r);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int nccell_width(const ncplane* n __attribute__ ((unused)), const nccell* c){
|
||||
return nccell_cols(c);
|
||||
}
|
||||
|
@ -840,7 +840,7 @@ clean_sprixels(notcurses* nc, ncpile* p, fbuf* f){
|
||||
}
|
||||
continue; // don't account as an elision
|
||||
}
|
||||
if(s->invalidated == SPRIXEL_MOVED || s->invalidated == SPRIXEL_INVALIDATED){
|
||||
if(s->invalidated == SPRIXEL_MOVED || s->invalidated == SPRIXEL_INVALIDATED || s->invalidated == SPRIXEL_UNSEEN){
|
||||
int y, x;
|
||||
ncplane_yx(s->n, &y, &x);
|
||||
//fprintf(stderr, "1 MOVING BITMAP %d STATE %d AT %d/%d for %p\n", s->id, s->invalidated, y + nc->margin_t, x + nc->margin_l, s->n);
|
||||
@ -929,6 +929,7 @@ rasterize_scrolls(ncpile* p, fbuf* f){
|
||||
if(goto_location(p->nc, f, p->dimy, 0)){
|
||||
return -1;
|
||||
}
|
||||
// FIXME if bce is set, we need reset background color
|
||||
while(p->scrolls){
|
||||
if(fbuf_putc(f, '\n') < 0){
|
||||
return -1;
|
||||
@ -955,9 +956,9 @@ rasterize_sprixels(notcurses* nc, ncpile* p, fbuf* f){
|
||||
while( (s = *parent) ){
|
||||
//fprintf(stderr, "YARR HARR HARR SPIRXLE %u STATE %d\n", s->id, s->invalidated);
|
||||
if(s->invalidated == SPRIXEL_INVALIDATED){
|
||||
//fprintf(stderr, "3 DRAWING BITMAP %d STATE %d AT %d/%d for %p\n", s->id, s->invalidated, y + nc->margin_t, x + nc->margin_l, s->n);
|
||||
int y, x;
|
||||
ncplane_yx(s->n, &y, &x);
|
||||
//fprintf(stderr, "3 DRAWING BITMAP %d STATE %d AT %d/%d for %p\n", s->id, s->invalidated, y + nc->margin_t, x + nc->margin_l, s->n);
|
||||
int r = sprite_draw(&nc->tcache, p, s, f, y + nc->margin_t, x + nc->margin_l);
|
||||
if(r < 0){
|
||||
return -1;
|
||||
|
@ -933,7 +933,13 @@ int sixel_draw(const tinfo* ti, const ncpile* p, sprixel* s, fbuf* f,
|
||||
}
|
||||
if(s->invalidated == SPRIXEL_MOVED){
|
||||
for(int yy = s->movedfromy ; yy < s->movedfromy + s->dimy && yy < p->dimy ; ++yy){
|
||||
if(yy < 0){
|
||||
continue;
|
||||
}
|
||||
for(int xx = s->movedfromx ; xx < s->movedfromx + s->dimx && xx < p->dimx ; ++xx){
|
||||
if(xx < 0){
|
||||
continue;
|
||||
}
|
||||
struct crender *r = &p->crender[yy * p->dimx + xx];
|
||||
if(!r->sprixel || sprixel_state(r->sprixel, yy, xx) != SPRIXCELL_OPAQUE_SIXEL){
|
||||
r->s.damaged = 1;
|
||||
|
@ -67,7 +67,7 @@ sprixel* sprixel_recycle(ncplane* n){
|
||||
// store the original (absolute) coordinates from which we moved, so that
|
||||
// we can invalidate them in sprite_draw().
|
||||
void sprixel_movefrom(sprixel* s, int y, int x){
|
||||
if(s->invalidated != SPRIXEL_HIDE){
|
||||
if(s->invalidated != SPRIXEL_HIDE && s->invalidated != SPRIXEL_UNSEEN){
|
||||
if(s->invalidated != SPRIXEL_MOVED){
|
||||
// FIXME if we're Sixel, we need to effect any wipes that were run
|
||||
// (we normally don't because redisplaying sixel doesn't change
|
||||
@ -168,7 +168,7 @@ int sprixel_load(sprixel* spx, fbuf* f, int pixy, int pixx,
|
||||
fbuf_free(&spx->glyph);
|
||||
memcpy(&spx->glyph, f, sizeof(*f));
|
||||
}
|
||||
spx->invalidated = SPRIXEL_INVALIDATED;
|
||||
spx->invalidated = SPRIXEL_UNSEEN;
|
||||
spx->pixx = pixx;
|
||||
spx->pixy = pixy;
|
||||
spx->parse_start = parse_start;
|
||||
|
@ -17,8 +17,9 @@ struct blitterargs;
|
||||
|
||||
typedef enum {
|
||||
SPRIXEL_QUIESCENT, // up-to-date and visible at the proper place
|
||||
SPRIXEL_UNSEEN, // not yet loaded, invisible, but wants loading
|
||||
SPRIXEL_LOADED, // loaded, but not yet made visible (kitty-only)
|
||||
SPRIXEL_INVALIDATED, // not up-to-date, need reload, trumps MOVED
|
||||
SPRIXEL_INVALIDATED, // not up-to-date, need reload
|
||||
SPRIXEL_HIDE, // queued for destruction
|
||||
SPRIXEL_MOVED, // visible, up-to-date, but in the wrong place
|
||||
} sprixel_e;
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <locale.h>
|
||||
#include <compat/compat.h>
|
||||
#include <notcurses/direct.h>
|
||||
|
||||
static int
|
||||
|
Loading…
x
Reference in New Issue
Block a user