add ncdirect_detected_terminal() and notcurses_detected_terminal() #1759

This commit is contained in:
nick black 2021-06-12 13:10:16 -04:00
parent e838209d21
commit d695a8206f
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC
10 changed files with 81 additions and 19 deletions

View File

@ -32,6 +32,7 @@ rearrangements of Notcurses.
could be in another pile. An error will instead be returned.
* Fixed a bug in `ncdirect_box()` where default/palette-indexed colors
weren't properly used on the top and bottom borders.
* Added `notcurses_detected_terminal()` and `ncdirect_detected_terminal()`.
* 2.3.2 (2021-06-03)
* Fixed a bug affecting certain scalings of `ncvisual` objects created from

View File

@ -10,6 +10,8 @@ notcurses_capabilities - runtime capability detection
**#include <notcurses/notcurses.h>**
**const char* notcurses_detected_terminal(const struct notcurses* ***nc***);**
**unsigned notcurses_supported_styles(const struct notcurses* ***nc***);**
**unsigned notcurses_palette_size(const struct notcurses* ***nc***);**
@ -38,6 +40,16 @@ notcurses_capabilities - runtime capability detection
# DESCRIPTION
**notcurses_detected_terminal** returns a free-form string describing
the detected terminal. Terminal detection takes into account any
specified terminal database (see **notcurses_init(3)**), the **TERM**,
**TERM_PROGRAM**, and **TERM_PROGRAM_VERSION** environment variables,
the response to a **XTGETTCAP[TN]** Device Control String, the response
to Primary, Secondary, and Tertiary Send Device Attributes control
sequences, and the phase of the moon. You should not build logic around
this response; all relevant properties of the terminal ought be
abstracted by Notcurses. This is only made available for diagnostics.
**notcurses_supported_styles** returns a bitmask representing those styles
for which the terminal advertises support.

View File

@ -72,6 +72,8 @@ notcurses_direct - minimal notcurses instances for styling text
**int ncdirect_printf_aligned(struct ncdirect* ***n***, int ***y***, ncalign_e ***align***, const char* ***fmt***, ***...***);**
**const char* ncdirect_detected_terminal(const struct ncdirect* ***n***);**
**bool ncdirect_canopen_images(const struct ncdirect* ***n***);**
**bool ncdirect_canutf8(const struct ncdirect* ***n***);**

View File

@ -235,6 +235,9 @@ API int ncdirect_cursor_pop(struct ncdirect* n)
API int ncdirect_clear(struct ncdirect* nc)
__attribute__ ((nonnull (1)));
API const char* ncdirect_detected_terminal(const struct ncdirect* n)
__attribute__ ((nonnull (1)));
// Can we load images? This requires being built against FFmpeg/OIIO.
API bool ncdirect_canopen_images(const struct ncdirect* n)
__attribute__ ((nonnull (1)));

View File

@ -1242,21 +1242,29 @@ API bool ncplane_set_scrolling(struct ncplane* n, bool scrollp);
// (NCSTYLE_UNDERLINE, NCSTYLE_BOLD, etc.) The attribute is only
// indicated as supported if the terminal can support it together with color.
// For more information, see the "ncv" capability in terminfo(5).
API unsigned notcurses_supported_styles(const struct notcurses* nc);
API unsigned notcurses_supported_styles(const struct notcurses* nc)
__attribute__ ((nonnull (1)));
// Returns the number of simultaneous colors claimed to be supported, or 1 if
// there is no color support. Note that several terminal emulators advertise
// more colors than they actually support, downsampling internally.
API unsigned notcurses_palette_size(const struct notcurses* nc);
API unsigned notcurses_palette_size(const struct notcurses* nc)
__attribute__ ((nonnull (1)));
API const char* notcurses_detected_terminal(const struct notcurses* nc)
__attribute__ ((nonnull (1)));
// Can we directly specify RGB values per cell, or only use palettes?
API bool notcurses_cantruecolor(const struct notcurses* nc);
API bool notcurses_cantruecolor(const struct notcurses* nc)
__attribute__ ((nonnull (1)));
// Can we fade? Fading requires either the "rgb" or "ccc" terminfo capability.
API bool notcurses_canfade(const struct notcurses* nc);
API bool notcurses_canfade(const struct notcurses* nc)
__attribute__ ((nonnull (1)));
// Can we set the "hardware" palette? Requires the "ccc" terminfo capability.
API bool notcurses_canchangecolor(const struct notcurses* nc);
API bool notcurses_canchangecolor(const struct notcurses* nc)
__attribute__ ((nonnull (1)));
// Can we load images? This requires being built against FFmpeg/OIIO.
API bool notcurses_canopen_images(const struct notcurses* nc);
@ -1265,24 +1273,30 @@ API bool notcurses_canopen_images(const struct notcurses* nc);
API bool notcurses_canopen_videos(const struct notcurses* nc);
// Is our encoding UTF-8? Requires LANG being set to a UTF8 locale.
API bool notcurses_canutf8(const struct notcurses* nc);
API bool notcurses_canutf8(const struct notcurses* nc)
__attribute__ ((nonnull (1)));
// Can we reliably use Unicode halfblocks?
API bool notcurses_canhalfblock(const struct notcurses* nc);
API bool notcurses_canhalfblock(const struct notcurses* nc)
__attribute__ ((nonnull (1)));
// Can we reliably use Unicode quadrants?
API bool notcurses_canquadrant(const struct notcurses* nc);
API bool notcurses_canquadrant(const struct notcurses* nc)
__attribute__ ((nonnull (1)));
// Can we reliably use Unicode 13 sextants?
API bool notcurses_cansextant(const struct notcurses* nc);
API bool notcurses_cansextant(const struct notcurses* nc)
__attribute__ ((nonnull (1)));
// Can we reliably use Unicode Braille?
API bool notcurses_canbraille(const struct notcurses* nc);
API bool notcurses_canbraille(const struct notcurses* nc)
__attribute__ ((nonnull (1)));
// This function must successfully return before NCBLIT_PIXEL is available.
// Returns -1 on error, 0 for no support, or 1 if pixel output is supported.
// Must not be called concurrently with either input or rasterization.
API int notcurses_check_pixel_support(struct notcurses* nc);
API int notcurses_check_pixel_support(struct notcurses* nc)
__attribute__ ((nonnull (1)));
// whenever a new field is added here, ensure we add the proper rule to
// notcurses_stats_reset(), so that values are preserved in the stash stats.

View File

@ -32,8 +32,8 @@ typedef struct fetched_info {
char* kernel; // strdup(uname(2)->name)
char* kernver; // strdup(uname(2)->version);
char* desktop; // getenv("XDG_CURRENT_DESKTOP")
char* shell; // getenv("SHELL")
char* term; // getenv("TERM")
const char* shell; // getenv("SHELL")
const char* term; // ncdirect_detected_terminal()
char* lang; // getenv("LANG")
int dimy, dimx; // extracted from xrandr
char* cpu_model; // FIXME don't handle hetero setups yet
@ -49,10 +49,10 @@ free_fetched_info(fetched_info* fi){
}
static int
fetch_env_vars(fetched_info* fi){
fetch_env_vars(struct ncdirect* nc, fetched_info* fi){
fi->desktop = getenv("XDG_CURRENT_DESKTOP");
fi->shell = getenv("SHELL");
fi->term = getenv("TERM");
fi->term = ncdirect_detected_terminal(nc);
fi->lang = getenv("LANG");
return 0;
}
@ -628,7 +628,7 @@ ncneofetch(struct ncdirect* nc){
const bool launched = !pthread_create(&tid, NULL, display_thread, &display_marshal);
unix_gethostname(&fi);
unix_getusername(&fi);
fetch_env_vars(&fi);
fetch_env_vars(nc, &fi);
fetch_x_props(&fi);
if(kern == NCNEO_LINUX){
fetch_cpu_info(&fi);

View File

@ -1368,3 +1368,7 @@ int ncdirectf_geom(ncdirect* n, ncdirectf* frame,
unsigned ncdirect_supported_styles(const ncdirect* nc){
return term_supported_styles(&nc->tcache);
}
const char* ncdirect_detected_terminal(const ncdirect* nc){
return nc->tcache.termname;
}

View File

@ -858,12 +858,12 @@ init_banner_warnings(const notcurses* nc, FILE* out){
// unless the suppress_banner flag was set, print some version information and
// (if applicable) warnings to stdout. we are not yet on the alternate screen.
static void
init_banner(const notcurses* nc, const char* shortname_term){
init_banner(const notcurses* nc){
if(!nc->suppress_banner){
char prefixbuf[BPREFIXSTRLEN + 1];
term_fg_palindex(nc, stdout, 50 % nc->tcache.colors);
printf("\n notcurses %s by nick black et al", notcurses_version());
printf(" on %s", shortname_term ? shortname_term : "?");
printf(" on %s", nc->tcache.termname ? nc->tcache.termname : "?");
term_fg_palindex(nc, stdout, 12 % nc->tcache.colors);
if(nc->tcache.cellpixy && nc->tcache.cellpixx){
printf("\n %d rows (%dpx) %d cols (%dpx) (%sB) %zuB crend %d colors",
@ -1127,7 +1127,7 @@ notcurses* notcurses_core_init(const notcurses_options* opts, FILE* outfp){
goto err;
}
ret->rstate.x = ret->rstate.y = -1;
init_banner(ret, shortname_term);
init_banner(ret);
// flush on the switch to alternate screen, lest initial output be swept away
const char* clearscr = get_escape(&ret->tcache, ESCAPE_CLEAR);
if(ret->ttyfd >= 0){
@ -1652,6 +1652,10 @@ unsigned notcurses_palette_size(const notcurses* nc){
return nc->tcache.colors;
}
const char* notcurses_detected_terminal(const notcurses* nc){
return nc->tcache.termname;
}
bool notcurses_cantruecolor(const notcurses* nc){
return nc->tcache.RGBflag;
}

View File

@ -86,6 +86,7 @@ apply_term_heuristics(tinfo* ti, const char* termname, int fd){
}
ti->braille = true; // most everyone has working braille, even from fonts
if(strstr(termname, "kitty")){ // kitty (https://sw.kovidgoyal.net/kitty/)
termname = "Kitty";
// see https://sw.kovidgoyal.net/kitty/protocol-extensions.html
// FIXME detect the actual default background color; this assumes it to
// be RGB(0, 0, 0) (the default). we could also just set it, i guess.
@ -96,20 +97,25 @@ apply_term_heuristics(tinfo* ti, const char* termname, int fd){
ti->RGBflag = true;
setup_kitty_bitmaps(ti, fd);
}else if(strstr(termname, "alacritty")){
termname = "Alacritty";
ti->alacritty_sixel_hack = true;
ti->quadrants = true;
// ti->sextants = true; // alacritty https://github.com/alacritty/alacritty/issues/4409 */
ti->RGBflag = true;
}else if(strstr(termname, "vte") || strstr(termname, "gnome") || strstr(termname, "xfce")){
termname = "VTE";
ti->sextants = true; // VTE has long enjoyed good sextant support
ti->quadrants = true;
}else if(strncmp(termname, "foot", 4) == 0){
termname = "foot";
ti->sextants = true;
ti->quadrants = true;
ti->RGBflag = true;
}else if(strncmp(termname, "st", 2) == 0){
termname = "simple terminal";
// st had neithersextants nor quadrants last i checked (0.8.4)
}else if(strstr(termname, "mlterm")){
termname = "MLterm";
ti->quadrants = true; // good quadrants, no sextants as of 3.9.0
ti->sprixel_cursor_hack = true;
}else if(strstr(termname, "xterm")){
@ -117,7 +123,21 @@ apply_term_heuristics(tinfo* ti, const char* termname, int fd){
// of people using xterm when they shouldn't be, or even real database
// entries like "xterm-kitty" (if we don't catch them above), giving a
// pretty minimal (but safe) experience. set your TERM correctly!
// wezterm wants a TERM of xterm-256color, and identifies itself based
// off TERM_PROGRAM and TERM_PROGRAM_VERSION.
const char* term_program = getenv("TERM_PROGRAM");
if(term_program && strcmp(term_program, "WezTerm") == 0){
termname = "WezTerm";
ti->quadrants = true;
const char* termver = getenv("TERM_PROGRAM_VERSION");
if(termver && strcmp(termver, "20210610") >= 0){
ti->sextants = true; // good sextants as of 2021-06-10
}
}else{
termname = "XTerm";
}
}else if(strcmp(termname, "linux") == 0){
termname = "Linux console";
ti->braille = false; // no braille, no sextants in linux console
// FIXME if the NCOPTION_NO_FONT_CHANGES, this isn't true
// FIXME we probably want to do this based off ioctl()s in linux.c
@ -131,6 +151,7 @@ apply_term_heuristics(tinfo* ti, const char* termname, int fd){
if(wcwidth(L'🬸') < 0){
ti->sextants = false;
}
ti->termname = termname;
return 0;
}

View File

@ -118,6 +118,7 @@ typedef struct tinfo {
int (*pixel_shutdown)(int fd); // called during context shutdown
int (*pixel_clear_all)(int fd); // called during startup, kitty only
int sprixel_scale_height; // sprixel must be a multiple of this many rows
const char* termname; // determined terminal name
struct termios tpreserved; // terminal state upon entry
ncinputlayer input; // input layer
bool bitmap_supported; // do we support bitmaps (post pixel_query_done)?