Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Unicode 16 octants #2820

Merged
merged 3 commits into from
Dec 25, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,9 +226,9 @@ likely get blanks or � (U+FFFD, REPLACEMENT CHARACTER) for missing characters,
and subsequent characters on the line may be misplaced.

It is worth knowing that several terminals draw the block characters directly,
rather than loading them from a font. This is generally desirable. Quadrants
and sextants are not the place to demonstrate your design virtuosity. To
inspect your environment's rendering of drawing characters, run
rather than loading them from a font. This is generally desirable. Quadrants,
sextants, and octants are not the place to demonstrate your design virtuosity.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm guessing your methodology for this kind of thing involved grepping for at a minimum sextant. i'm trying to think of other stuff we'd want to check. NCBLIT is broad but probably a good one. i'll run these checks, just thinking aloud.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct. I looked for sextant, but not for NCBLIT.

To inspect your environment's rendering of drawing characters, run
`notcurses-info`. The desired output ought look something like this:

<p align="center">
Expand Down Expand Up @@ -309,7 +309,8 @@ If things break or seem otherwise lackluster, **please** consult the
Notcurses will not make use of bitmap protocols unless the terminal positively
indicates support for them, even if <code>NCBLIT_PIXEL</code> has been
requested. Likewise, sextants (<code>NCBLIT_3x2</code>) won't be used without
Unicode 13 support, etc. <code>ncvisual_blit()</code> will use the best blitter
Unicode 13 support, octants (<code>NCBLIT_4x2</code>) won't be used without
Unicode 17 support, etc. <code>ncvisual_blit()</code> will use the best blitter
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have we traveled to the future in a Delorean? unicode 17 does not yet exist afaik

available, unless <code>NCVISUAL_OPTION_NODEGRADE</code> is provided (in
which case it will fail).
</details>
Expand Down
5 changes: 3 additions & 2 deletions doc/man/man1/notcurses-info.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ terminal environment, including material loaded from **terminfo(5)** (based
on the **TERM** environment variable), replies from the terminal in
response to our queries, and built-in heuristics.

The Unicode half block, quadrant, sextant, and Braille glyphs are all included
The Unicode half block, quadrant, sextant, octant, and Braille glyphs are all included
in the output. If their appearance is irregular, it might behoove you to choose
another font.

Expand Down Expand Up @@ -70,6 +70,7 @@ The next five lines describe properties of the terminal environment:
* 2x1: Upper- and lower-half blocks are available
* 2x2: Quadrant blocks are available
* 3x2: Sextant blocks are available
* 4x2: Octant blocks are available
* 4x2: Braille characters are available
* img: Images can be decoded
* vid: Video can be decoded
Expand All @@ -93,7 +94,7 @@ To the right of this material is the Notcurses homepage's URI, and the
Notcurses logo (the latter only if bitmap graphics are available).

The final eleven lines, only printed when in a UTF8 locale, show various
Unicode glyphs. The first four lines include the quadrant, sextant, and
Unicode glyphs. The first four lines include the quadrant, sextant, octant, and
box-drawing characters. The next four lines include the entire Braille set.
The following two lines include many of the Symbols for Legacy Computing
introduced in Unicode 13. The final line includes many emoji.
Expand Down
4 changes: 4 additions & 0 deletions doc/man/man3/notcurses_capabilities.3.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ notcurses_capabilities - runtime capability detection

**bool notcurses_cansextant(const struct notcurses* ***nc***);**

**bool notcurses_canoctant(const struct notcurses* ***nc***);**

**bool notcurses_canbraille(const struct notcurses* ***nc***);**

**bool notcurses_canpixel(const struct notcurses* ***nc***);**
Expand Down Expand Up @@ -92,6 +94,8 @@ multimedia support capable of decoding videos.
**notcurses_canutf8** returns **true** if the configured locale uses
UTF-8 encoding, and the locale was successfully loaded.

**notcurses_canoctant** returns **true** if the heuristics suggest
that the terminal can properly render Unicode 17 octants. Likewise,
eschnett marked this conversation as resolved.
Show resolved Hide resolved
**notcurses_cansextant** returns **true** if the heuristics suggest
that the terminal can properly render Unicode 13 sextants. Likewise,
**notcurses_canquadrant** and **notcurses_canhalfblock** return **true**
Expand Down
2 changes: 2 additions & 0 deletions doc/man/man3/notcurses_direct.3.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ notcurses_direct - the Direct Mode API

**bool ncdirect_cansextant(const struct ncdirect* ***nc***);**

**bool ncdirect_canoctant(const struct ncdirect* ***nc***);**

**bool ncdirect_canbraille(const struct ncdirect* ***nc***);**

**bool ncdirect_canget_cursor(const struct ncdirect* ***nc***);**
Expand Down
6 changes: 3 additions & 3 deletions doc/man/man3/notcurses_plot.3.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ contribute to the plot. Supplying an **x** below the current window is an
error, and has no effect.

More granular block glyphs means more resolution in your plots, but they can
be difficult to differentiate at small text sizes. Sextants and Braille allow
for more resolution on the independent variable. It can be difficult to predict
how the Braille glyphs will look in a given font.
be difficult to differentiate at small text sizes. Octants, sextants, and Braille
allow for more resolution on the independent variable. It can be difficult to
predict how the Braille glyphs will look in a given font.

The same **ncplot_options** struct can be used with all ncplot types. The
**flags** field is a bitmask composed of:
Expand Down
11 changes: 7 additions & 4 deletions doc/man/man3/notcurses_visual.3.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ typedef enum {
NCBLIT_2x1, // halves + 1x1
NCBLIT_2x2, // quadrants + 2x1
NCBLIT_3x2, // sextants + 1x1
NCBLIT_4x2, // octants + quadrants + 2x1 + 1x1
NCBLIT_BRAILLE, // 4 rows, 2 cols (braille)
NCBLIT_PIXEL, // pixel graphics
NCBLIT_4x1, // four vertical levels, (plots)
Expand Down Expand Up @@ -238,6 +239,7 @@ The different **ncblitter_e** values select from among available glyph sets:
* **NCBLIT_2x1**: Adds the half blocks (▄▀) to **NCBLIT_1x1**.
* **NCBLIT_2x2**: Adds left and right half blocks (▌▐) and quadrants (▖▗▟▙) to **NCBLIT_2x1**.
* **NCBLIT_3x2**: Adds sextants to **NCBLIT_1x1**.
* **NCBLIT_4x2**: Adds octants to **NCBLIT_2x2**.
* **NCBLIT_BRAILLE**: 4 rows and 2 columns of braille (⡀⡄⡆⡇⢀⣀⣄⣆⣇⢠⣠⣤⣦⣧⢰⣰⣴⣶⣷⢸⣸⣼⣾⣿).
* **NCBLIT_PIXEL**: Adds pixel graphics (these also work in ASCII).

Expand Down Expand Up @@ -343,10 +345,11 @@ or if both ***nc*** and ***n*** are **NULL**.

**ncvisual_media_defblitter** returns the blitter selected by **NCBLIT_DEFAULT**
in the specified configuration. If UTF8 is not enabled, this will always be
**NCBLIT_1x1**. If ***scale*** is **NCSCALE_NONE** or **NCSCALE_SCALE**, the
aspect-preserving **NCBLIT_2x1** will be returned. If sextants are available
(see **notcurses_cansextant**), this will be **NCBLIT_3x2**, or otherwise
**NCBLIT_2x2**.
**NCBLIT_1x1**. If octants are available, (see **notcurses_canictant**), the
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

canoctant i think you mean. and i don't think 4x2 is aspect-preserving? am i being stupid?

the whole reason why 2x1 preserves aspect (mostly) is that a cell is (usually) (roughly) twice as tall as it is wide. so when you put two pixels in there, on top of one anotther, you suddenly have pixels be squares, like they (usually) are in your image. but, 4x2 is a linear map from 2x1, so yeah, i guess that works too. good deal. nice to have another aspect-preserving blitter!

i'm not sure about it being the default for NCSCALE_NONE and NCSCALE_SCALE, though. 2x1 allows full color fidelity. remember, you only have a background and foreground for each cell. so with two source pixels mapped to the cell, you can do both colors losslessly. there's no way to losslessly pack 8 pixels into 2 cell colors, though. so you're going to lose some image quality for certain images, and ruin pathological ones.

so i think we stick with 2x1.

now, maybe it should be the default for NCSCALE_STRETCH (which is currently 3x2, which is honestly a garbage blitter).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't quite follow the reasoning. The 4x2 aspect-preserving mode is never chosen when the caller wants to preserve the aspect, but it might be chosen when the caller explicitly allows non-aspect preserving mapping? That seems a bit confusing.

I'd be fine with never making 4x2 the default (at the moment it's new and untested). In the future, maybe there could be a new flag to preserving colour accuracy?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm thinking of octants as basically a more attractive, predictable braille. i.e. both are just implementing a 4x2 blitter, but you pretty much know what octants are going to look like. so octants have the same advantages and disadvantages otherwise that braille does -- the advantage is that you can get higher resolution in a fixed cell geometry, and the disadvantage is that you stand to lose color fidelity (which can in certain cases make the image effectively unrecognizable).

4x2 is chosen when the user requests 4x2, whether they choose _SCALE, _NONE, or _STRETCH. this only affects the case where they choose NCBLIT_DEFAULT together with _SCALE or _NONE. if you choose 4x2 explicitly, you get 4x2 (unless we can't do it). does that make sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I agree.

aspect-preserving **NCBLIT_4x2** will be returned. If ***scale*** is
**NCSCALE_NONE** or **NCSCALE_SCALE**, the aspect-preserving **NCBLIT_2x1**
will be returned. If sextants are available (see **notcurses_cansextant**),
this will be **NCBLIT_3x2**, or otherwise **NCBLIT_2x2**.

# NOTES

Expand Down
5 changes: 5 additions & 0 deletions include/ncpp/NotCurses.hh
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@ namespace ncpp
return notcurses_cansextant (nc);
}

bool can_octant () const noexcept
{
return notcurses_canoctant (nc);
}

bool can_utf8 () const noexcept
{
return notcurses_canutf8 (nc);
Expand Down
6 changes: 6 additions & 0 deletions include/notcurses/direct.h
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,12 @@ ncdirect_cansextant(const struct ncdirect* nc){
return ncdirect_canutf8(nc) && ncdirect_capabilities(nc)->sextants;
}

// Can we reliably use Unicode 16 octants?
static inline bool
ncdirect_canoctant(const struct ncdirect* nc){
return ncdirect_canutf8(nc) && ncdirect_capabilities(nc)->octants;
}

// Can we reliably use Unicode Braille?
static inline bool
ncdirect_canbraille(const struct ncdirect* nc){
Expand Down
33 changes: 33 additions & 0 deletions include/notcurses/ncseqs.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,39 @@ extern "C" {
#define NCHALFBLOCKS L" ▀▄█"
#define NCQUADBLOCKS L" ▘▝▀▖▌▞▛▗▚▐▜▄▙▟█"
#define NCSEXBLOCKS L" 🬀🬁🬂🬃🬄🬅🬆🬇🬈🬊🬋🬌🬍🬎🬏🬐🬑🬒🬓▌🬔🬕🬖🬗🬘🬙🬚🬛🬜🬝🬞🬟🬠🬡🬢🬣🬤🬥🬦🬧▐🬨🬩🬪🬫🬬🬭🬮🬯🬰🬱🬲🬳🬴🬵🬶🬷🬸🬹🬺🬻█"
#define NCOCTBLOCKS \
L" \U0001CEA8\U0001CEAB\U0001FB82\U0001CD00\U00002598\U0001CD01\U0001CD02"\
"\U0001CD03\U0001CD04\U0000259D\U0001CD05\U0001CD06\U0001CD07\U0001CD08\U00002580"\
"\U0001CD09\U0001CD0A\U0001CD0B\U0001CD0C\U0001FBE6\U0001CD0D\U0001CD0E\U0001CD0F"\
"\U0001CD10\U0001CD11\U0001CD12\U0001CD13\U0001CD14\U0001CD15\U0001CD16\U0001CD17"\
"\U0001CD18\U0001CD19\U0001CD1A\U0001CD1B\U0001CD1C\U0001CD1D\U0001CD1E\U0001CD1F"\
"\U0001FBE7\U0001CD20\U0001CD21\U0001CD22\U0001CD23\U0001CD24\U0001CD25\U0001CD26"\
"\U0001CD27\U0001CD28\U0001CD29\U0001CD2A\U0001CD2B\U0001CD2C\U0001CD2D\U0001CD2E"\
"\U0001CD2F\U0001CD30\U0001CD31\U0001CD32\U0001CD33\U0001CD34\U0001CD35\U0001FB85"\
"\U0001CEA3\U0001CD36\U0001CD37\U0001CD38\U0001CD39\U0001CD3A\U0001CD3B\U0001CD3C"\
"\U0001CD3D\U0001CD3E\U0001CD3F\U0001CD40\U0001CD41\U0001CD42\U0001CD43\U0001CD44"\
"\U00002596\U0001CD45\U0001CD46\U0001CD47\U0001CD48\U0000258C\U0001CD49\U0001CD4A"\
"\U0001CD4B\U0001CD4C\U0000259E\U0001CD4D\U0001CD4E\U0001CD4F\U0001CD50\U0000259B"\
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my eyes

"\U0001CD51\U0001CD52\U0001CD53\U0001CD54\U0001CD55\U0001CD56\U0001CD57\U0001CD58"\
"\U0001CD59\U0001CD5A\U0001CD5B\U0001CD5C\U0001CD5D\U0001CD5E\U0001CD5F\U0001CD60"\
"\U0001CD61\U0001CD62\U0001CD63\U0001CD64\U0001CD65\U0001CD66\U0001CD67\U0001CD68"\
"\U0001CD69\U0001CD6A\U0001CD6B\U0001CD6C\U0001CD6D\U0001CD6E\U0001CD6F\U0001CD70"\
"\U0001CEA0\U0001CD71\U0001CD72\U0001CD73\U0001CD74\U0001CD75\U0001CD76\U0001CD77"\
"\U0001CD78\U0001CD79\U0001CD7A\U0001CD7B\U0001CD7C\U0001CD7D\U0001CD7E\U0001CD7F"\
"\U0001CD80\U0001CD81\U0001CD82\U0001CD83\U0001CD84\U0001CD85\U0001CD86\U0001CD87"\
"\U0001CD88\U0001CD89\U0001CD8A\U0001CD8B\U0001CD8C\U0001CD8D\U0001CD8E\U0001CD8F"\
"\U00002597\U0001CD90\U0001CD91\U0001CD92\U0001CD93\U0000259A\U0001CD94\U0001CD95"\
"\U0001CD96\U0001CD97\U00002590\U0001CD98\U0001CD99\U0001CD9A\U0001CD9B\U0000259C"\
"\U0001CD9C\U0001CD9D\U0001CD9E\U0001CD9F\U0001CDA0\U0001CDA1\U0001CDA2\U0001CDA3"\
"\U0001CDA4\U0001CDA5\U0001CDA6\U0001CDA7\U0001CDA8\U0001CDA9\U0001CDAA\U0001CDAB"\
"\U00002582\U0001CDAC\U0001CDAD\U0001CDAE\U0001CDAF\U0001CDB0\U0001CDB1\U0001CDB2"\
"\U0001CDB3\U0001CDB4\U0001CDB5\U0001CDB6\U0001CDB7\U0001CDB8\U0001CDB9\U0001CDBA"\
"\U0001CDBB\U0001CDBC\U0001CDBD\U0001CDBE\U0001CDBF\U0001CDC0\U0001CDC1\U0001CDC2"\
"\U0001CDC3\U0001CDC4\U0001CDC5\U0001CDC6\U0001CDC7\U0001CDC8\U0001CDC9\U0001CDCA"\
"\U0001CDCB\U0001CDCC\U0001CDCD\U0001CDCE\U0001CDCF\U0001CDD0\U0001CDD1\U0001CDD2"\
"\U0001CDD3\U0001CDD4\U0001CDD5\U0001CDD6\U0001CDD7\U0001CDD8\U0001CDD9\U0001CDDA"\
"\U00002584\U0001CDDB\U0001CDDC\U0001CDDD\U0001CDDE\U00002599\U0001CDDF\U0001CDE0"\
"\U0001CDE1\U0001CDE2\U0000259F\U0001CDE3\U00002586\U0001CDE4\U0001CDE5\U00002588"
#define NCBRAILLEEGCS \
L"\u2800\u2801\u2808\u2809\u2802\u2803\u280a\u280b\u2810\u2811\u2818\u2819\u2812\u2813\u281a\u281b"\
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh apparently i pulled this shit too, hah

"\u2804\u2805\u280c\u280d\u2806\u2807\u280e\u280f\u2814\u2815\u281c\u281d\u2816\u2817\u281e\u281f"\
Expand Down
11 changes: 10 additions & 1 deletion include/notcurses/notcurses.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ typedef enum {
NCBLIT_2x1, // halves + 1x1 (space) ▄▀
NCBLIT_2x2, // quadrants + 2x1 ▗▐ ▖▀▟▌▙
NCBLIT_3x2, // sextants (*NOT* 2x2) 🬀🬁🬂🬃🬄🬅🬆🬇🬈🬉🬊🬋🬌🬍🬎🬏🬐🬑🬒🬓🬔🬕🬖🬗🬘🬙🬚🬛🬜🬝🬞
NCBLIT_4x2, // octants
NCBLIT_BRAILLE, // 4 rows, 2 cols (braille) ⡀⡄⡆⡇⢀⣀⣄⣆⣇⢠⣠⣤⣦⣧⢰⣰⣴⣶⣷⢸⣸⣼⣾⣿
NCBLIT_PIXEL, // pixel graphics
// these blitters are suitable only for plots, not general media
Expand Down Expand Up @@ -1641,6 +1642,7 @@ typedef struct nccapabilities {
bool halfblocks;// we assume halfblocks, but some are known to lack them
bool quadrants; // do we have (good, vetted) Unicode 1 quadrant support?
bool sextants; // do we have (good, vetted) Unicode 13 sextant support?
bool octants; // do we have (good, vetted) Unicode 16 octant support?
dankamongmen marked this conversation as resolved.
Show resolved Hide resolved
bool braille; // do we have Braille support? (linux console does not)
} nccapabilities;

Expand Down Expand Up @@ -1756,6 +1758,12 @@ notcurses_cansextant(const struct notcurses* nc){
return notcurses_canutf8(nc) && notcurses_capabilities(nc)->sextants;
}

// Can we reliably use Unicode 16 octants?
dankamongmen marked this conversation as resolved.
Show resolved Hide resolved
__attribute__ ((nonnull (1))) __attribute__ ((pure)) static inline bool
notcurses_canoctant(const struct notcurses* nc){
return notcurses_canutf8(nc) && notcurses_capabilities(nc)->octants;
}

// Can we reliably use Unicode Braille?
__attribute__ ((nonnull (1))) __attribute__ ((pure)) static inline bool
notcurses_canbraille(const struct notcurses* nc){
Expand Down Expand Up @@ -3510,11 +3518,12 @@ API ALLOC struct ncplane* ncvisual_subtitle_plane(struct ncplane* parent,
// Get the default *media* (not plot) blitter for this environment when using
// the specified scaling method. Currently, this means:
// - if lacking UTF-8, NCBLIT_1x1
// - otherwise, if octants are known to be good, NCBLIT_4x2
// - otherwise, if not NCSCALE_STRETCH, NCBLIT_2x1
// - otherwise, if sextants are not known to be good, NCBLIT_2x2
// - otherwise NCBLIT_3x2
// NCBLIT_2x2 and NCBLIT_3x2 both distort the original aspect ratio, thus
// NCBLIT_2x1 is used outside of NCSCALE_STRETCH.
// NCBLIT_4x2 or NCBLIT_2x1 is used outside of NCSCALE_STRETCH.
API ncblitter_e ncvisual_media_defblitter(const struct notcurses* nc, ncscale_e scale)
__attribute__ ((nonnull (1)));

Expand Down
1 change: 1 addition & 0 deletions src/demo/keller.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ visualize(struct notcurses* nc, struct ncvisual* ncv){
{ NCBLIT_2x1, notcurses_canhalfblock, },
{ NCBLIT_2x2, notcurses_canquadrant, },
{ NCBLIT_3x2, notcurses_cansextant, },
{ NCBLIT_4x2, notcurses_canoctant, },
{ NCBLIT_PIXEL, notcurses_canpixel, },
};
struct ncplane* stdn = notcurses_stdplane(nc);
Expand Down
1 change: 1 addition & 0 deletions src/info/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,7 @@ tinfo_debug_styles(const notcurses* nc, struct ncplane* n, const char* indent){
tinfo_debug_cap(n, "2x1", notcurses_canhalfblock(nc));
tinfo_debug_cap(n, "2x2", notcurses_canquadrant(nc));
tinfo_debug_cap(n, "3x2", notcurses_cansextant(nc));
tinfo_debug_cap(n, "4x2", notcurses_canoctant(nc));
tinfo_debug_cap(n, "4x2", notcurses_canbraille(nc));
tinfo_debug_cap(n, "img", notcurses_canopen_images(nc));
tinfo_debug_cap(n, "vid", notcurses_canopen_videos(nc));
Expand Down
Loading