I keep it playa while some choose to play it safe
boi, check the résumé: it's risky business in the 'A'
Notcurses 3.0.0 “In the 'A'” with API/ABI3
- boom! =]
- major additions since 2.0.0
- what they're saying
- gallery
- the new CLI mode
- porting api2 applications to api3
- what's coming in Notcurses IV
- coda: in the "A"
boom! =]
Notcurses 3.0.0 represents over a year of development since Notcurses 2.0.0 "Stankonia".
The overall vision remains unchanged from the very beginning—composition of z-ordered planes, with an API naturally expressed in terms of 888RGB DirectColor and Unicode Extended Grapheme Clusters, amenable to multithreading—but it's grown beyond all my dreams. Notcurses has pushed the terminal ecosystem forward, with patches and influence going into XTerm, Kitty, Alacritty, MLterm, Contour, foot, the Linux console, iTerm2, MSYS2, console-setup, Valgrind, musl, and some I'm forgetting. Notcurses makes use of advanced new kernel functionality like Linux's pidfds, but at the same time runs on various BSDs, macOS, and even Microsoft Windows (natively, not just through WSL). It fully supports the new Windows ConPTY and Microsoft Terminal. It can be used to build fixed-screen TUIs and scrolling CLIs. Aside from its lack of Curses compatibility, it is—as far as I'm aware—the best, most powerful, ballinest terminal graphics library in existence.
If you're writing a new terminal application in 202x, you probably ought be using Notcurses.
help wanted/needed
are you a python hacker with a solid understanding of wrapping C? because i absolutely am not, and honestly have no interest in becoming one. i desperately need someone committed to adapting new C functionality in python as it emerges, ideally further extending that to create a truly pythonesque Notcurses interface. pick up @igo95862 's work in python/
and go to town. do you write go? same shit! c#? dot-net this motherfucker! what's in it for you? i wish i knew the answer to that question myself. @joseluis seems to have the situation pretty well handled for rust; ask him. i'll be handling fortran, prolog, and threaded intercal wrappers.
left: a python eats a crocodile, before unhinging its dynamically-typed jaw and eating my time. note that the python is devouring the crocodile without a hint of parallelism, despite having seemingly evolved for, like, six hundred million years now. i bet it OOMs.
API and ABI break
Notcurses 3.0.0 introduces a hard ABI break relative to previous versions, and changes the SONAME to reflect this. Previous binaries will not link against Notcurses 3.0.0+. Even if you use no new API, nor any API which has been deprecated, your binary must be recompiled. The API has expanded throughout 2.x development, but 3.0.0 removes all functionality previously only deprecated. See the API changenotes below for complete information. I'm sorry for the API changes, but they leave Notcurses much improved for the future. Most changes can be safely implemented via global regex.
There may be any number of additions to the API for Notcurses 4, but every attempt will be made to maintain backwards compatibility. The ABI will not change across 3.x development.
major additions since 2.0.0
With that, the most major changes since 2.0.0 include:
- Direct interrogation of terminals, when present, to determine capabilities—Notcurses is moving away from reliance on Terminfo. Capabilities acquired in this fashion aren't dependent on the local copy of the terminfo database, nor upstream authors getting their terminfo changes into NCURSES, and especially not on the user correctly setting
TERM
. - Support for
XTMODKEYS
and the Kitty keyboard protocol for rich events. Support for console mice via GPM. Note that the Kitty keyboard protocol is now supported by foot! Among other things, this allows disambiguation of key depress, repeat, and release, as well as detection of modifier keys by themselves. Clients can now specify which mouse events they want, and get mouse movement events even when no buttons are pressed. - Support for Sixel and Kitty bitmap graphics, and direct draws to the Linux framebuffer console. Note that Kitty graphics are now supported by WezTerm! Bitmap capabilities are determined at runtime, and no matter what the backend, they're efficiently integrated into the overall z-axis model. They cover glyphs, and are covered by glyphs, just like any other plane. As always, Notcurses steps down among its blitters based on local capabilities.
- The Unicode 13-based 3x2 "sexblitter" and 8x1 "eightsplotter" were added.
- Support for Microsoft Windows, macOS, and Dragonfly BSD. macOS support benefitted greatly from @michaelsbradleyjr 's assistance testing, setting up GitHub CI, and providing a development platform. Windows support benefitted greatly from the wisdom and grandmotherly patience of @j4james. Both were substantial efforts, with Windows being by far the larger one, consuming close to two months' development time. It was worth it, though, to show off the powerful new Microsoft Terminal and the ConPTY, wherein Microsoft gets it almost right. Notcurses is nothing less than a sea change for Windows console app developers.
- Non-interpolative scaling suitable for e.g. pixel art.
- Scrolling on the standard plane for construction of CLI-like programs in Rendered Mode.
- New
nctree
,ncprogbar
, andnctabbed
widgets, the latter from @MasFlam. - Much-improved Python wrappers from @igo95862.
- Rust wrappers taken to an entirely new level by @joseluis.
- Construction of
ncvisual
s via various RGB formats, as requested by @kaniini . libnotcurses-core
has been split out fromlibnotcurses
, allowing binaries to be linked without the multimedia stack, even if the installed Notcurses was built with a multimedia stack.- Distinct rendering contexts are available as piles; there are no concurrency hazards shared between piles.
- The new
notcurses-info
binary provides a quick summation and exercise of terminal capabilities. - The new
ncls
binary lists and renders files. notcurses-view
has been renamed toncplayer
, and now accepts-n
for non-interpolative scaling, and-a
to alpha-mask a color.
...but this is only a small sample of the expansions, improvements, and achievements of Notcurses 3.0.0! Give it a test drive. Write some apps around it. Hack. May one hundred flowers bloom! 百花齊放,百家爭鳴
868 issues were closed via 7.7K+ commits in this release cycle.
what they're saying
The first time I ran notcurses’ “jungle” demo in foot nothing happened. Turned out to be a bug in foot’s handling of color palette changes. This phenomenon has kept repeating itself; notcurses using features in novel ways unearths terminal emulator bugs. notcurses-demo turns your terminal emulator into a 90s computer demo—and that’s a good thing."
—Daniel Eklöf (@dnkl), author of foot
I believe notcurses forms an excellent foundation for the next generation of terminal applications, with rich support for graphics and input, and lots of effort into graceful degradation for legacy terminals. I recommend anyone starting to build a terminal application in 2021 consider it as the foundation layer.
—Kovid Goyal (@kovidgoyal), author of Kitty
Terminals have long been seen as an old era tech, and so, many applications retain the behavior of those apps and standard being even older than I am. Notcurses not so much! I am glad notcurses is trying to break out and breathe fresh air and new life into our beloved eco system again with many features the young generation of users and developers want and will expect. A huge thanks to Nick Black for helping us move forward in the terminal land. The notcurses demos are mind blowing and inspiring of what modern terminal applications can be capable of and I recommend anyone asking me what to use when building terminal apps to give notcurses a try. Hack on!
—Christian Parpart (@christianparpart), author of Contour
The demo is great, and looks like it can push out enough detail to pull off silliness like pushing an SNES game’s output straight to the console. What might be the most impressive element of the library is that while it can blit high res graphics through a terminal emulator with graphical support, it will also work on the basic Linux console, with no graphical system installed, by using some very old tricks. I know what you’re wondering: That’s all well and good, but can it run Doom? Yep.
—Hackaday 2021-05-20 "Terminal Magic with Notcurses"
Just ran
notcurses-demo
. Mind blowing. Is it even legal?
—u/rmrfchik
gallery
Two Microsoft Terminals run ncneofetch
and ncplayer
. Microsoft Terminal does not (yet) support bitmap graphics, nor Unicode 13 (necessary for the sexblitter), so here we see the quadblitter.
Terminal.App, iTerm2, and Kitty 0.21.2 on macOS. iTerm2 does not yet support partially-transparent bitmap graphics, but its author is working on it. Terminal.App is a somewhat lackluster program.
WezTerm runs ncneofetch
while ssh'd into a FreeBSD 13 virtual machine. On the left, Kitty 0.21.3 churns through the [xray]
phase of notcurses-demo
.
the new CLI mode
In the beginning, there was struct notcurses
for a "Rendered Mode" context, and struct ncdirect
for a "Direct Mode" context. Among other differences, output never resulted in true, externally-meaningful screen scrolling in Rendered Mode (you could fake it internally with a scrolling plane, but this wouldn't e.g. scroll existing content you hadn't generated). Rendered Mode was geared towards fullscreen TUIs, and free-scrolling CLIs were only possible in Direct Mode.
Well, Direct Mode allows other programs to generate output, and thus never knows the screen contents, eliminating most optimizations. The two APIs diverged extensively, and you basically couldn't use any of the Notcurses widgets etc. with a CLI program. @klamonte's "The Command Line vs. the Terminal" speaks truth:
...users really need the "command line", but not so much the "terminal". What do I mean by that? By "command line", I mean pipe-able (composable) programs that read from stdin, write to stdout, and do a sequence of command / response / command / response. Just like the "read-eval-print-loop" (REPL) used by Lisp, Python, and many other programming languages.
We needed to unleash the full power of Rendered Mode on CLI-style applications. Hence "CLI mode", which uses the struct notcurses
context. It ought be initialized with NCOPTION_NO_CLEAR_BITMAPS
(to leave previous output unmolested), NCOPTION_PRESERVE_CURSOR
(to start wherever the program was launched), and NCOPTION_NO_ALTERNATE_SCREEN
(hopefully obvious). Upon acquiring the context, invoke ncplane_set_scrolling()
on the standard plane (it was not previously possible to enable scrolling on the standard plane). Congratulations, you now have a CLI app. You must continue to invoke notcurses_render()
or some other rasterizer to generate output.
I'm not yet satisfied with the CLI mode (see "Notcurses IV" below), but think its shortcomings can be remedied without any API/ABI breakage. In particular, it's currently too difficult to simply stream data and ensure you have it all in your scrollback history, due to all those manual render/raster calls. This will be improved.
porting api2 applications to api3
If you've kept your application up to date through the 2.x.x development cycle, updating to eliminate deprecation warnings, congratulations! 3.0.0 introduces no user-visible changes relative to 2.4.x, save the removal of long-deprecated material. Some functions which were previously symbols in the library are now static inline
header-only implementations, and a recompile will be sufficient to get you linked and going. A recompile is in any case necessary due to struct
changes and other ABI variations.
Let's assume the worst plausible case: you have a program built against Notcurses 2.0.0, and want to build it against 3.0.0, retaining prior behavior. You'll probably need to make a change or two, most of them insubstantial:
- It is no longer possible to have multiple contexts open concurrently, including a rendered mode
notcurses
context alongside a direct modencdirect
context. If you were doing this to handle input, manage your cursor and use anncreader
. If you were doing this to run a subprocess, use anncsubproc
. ncvisual_render()
has been dropped in favor ofncvisual_blit()
. The latter responds to aNULL
target plane by creating a new pile, rather than creating a new plane in the standard pile. To get the old behavior, pass the standard plane asn
inncvisual_options
, and addNCVISUAL_OPTION_CHILDPLANE
toflags
.- Removed unsafe
cell_fchannel()
,cell_bchannel()
,cell_set_fchannel()
, andcell_set_bchannel()
. If you were using these, the safe parts can be accomplished with other existing functions.cell_width()
has been replaced bynccell_cols()
, and no longer requires anncplane*
argument. All other functions starting withcell
now start withnccell
, and thecell
type is nownccell
. Macros starting withCELL
now start withNCCELL
. - All functions starting with
channel
now start withncchannel
, and thechannel
/channels
types are nowncchannel
/ncchannels
. Macros beginning withCHANNEL
now begin withNCCHANNEL
. - All functions starting with
palette
now start withncpalette
. Thepalette256
type has been renamedncpalette
. ncvisual_subtitle()
has been replaced withncvisual_subtitle_plane()
, and returns a newncplane*
.NCSTYLE_REVERSE
has been eliminated.ncchannels_reverse()
is available to reverse the fore- and background of anncchannels
variable, but is not a direct replacement.NCSTYLE_DIM
has been eliminated. The same effect can be more portably achieved with channel RGB.NCSTYLE_BLINK
has been eliminated. The same effect can be more portably achieved withncplane_pulse()
.renderfp
has been removed fromnotcurses_options
, with no replacement functionality.ncplane_rgba()
has been renamedncplane_as_rgba()
.ncvisual_geom()
has been reworked to use the newncvgeom
struct.ncplane_align()
has been replaced byncplane_halign()
.notcurses_stats()
traded theconst
modifier on itsnotcurses*
parameter for elimination of data races.ncplane_qrcode()
no longer accepts a blitter specification, since onlyNCBLIT_2x1
works.- All
ncplane_put*()
functions now return the number of columns output, as documented (some were erroneously returning the number of bytes output). ncdirect_styles_{set, on, off}()
have been renamedncdirect_{set, on, off}_styles()
.ncdirect_raster_frame()
no longer requiresblitter
norscale
.ncdirect_{fg, bg}_{default, rgb}()
have been renamedncdirect_set_{fg, bg}_{default, rgb}()
.ncplane_options
lost itshoriz
union, which was replaced with itsx
member.- There were many changes to Direct Mode, but I've not bothered listing them here because you ought be using CLI mode.
what's coming in Notcurses IV
I've got big plans for Notcurses IV, most of them regarding sweet, sweet perf.the endankification of CLI mode
The CLI mode came up kinda late in Notcurses design, well into the 2.x cycle. It became clear that streaming stdio CLIs are more frequently authored than high-performance, non-scrolling TUIs. By allowing the standard plane to be placed into scrolling mode, this functionality was bolted on. It's not where I want it. You currently have to manage all the scrolling yourself, which gets pretty hairy once you bring multiple planes into the picture. You furthermore need decide when to render, and no one wants to think about that. Render insufficiently frequently, and data will be lost to virtual internal scrolling; render every line, and you do a lot of extra work (CLI mode doesn't yet always take advantage of hardware scrolling). I intend to make fuller use of hardware scrolling so that rendering can take place on every virtual scroll event, for full fidelity, full performance, and no developer effort.
wholesale emancipation from terminfo
Notcurses has made use of Terminfo (as distributed with NCURSES) since its inception. The limitations of that library have become more and more apparent, and with Notcurses now using direct terminal queries wherever possible, it's time to consider ditching libterminfo (and perhaps even the TERM
environment variable, which can be—and all too often is—incorrect). Terminfo doesn't cover a substantial amount of behavior Notcurses actively employs, from bitmap graphics to extended input protocols. Many terminals in any case don't bother putting together an accurate terminfo database entry, simply calling themselves xterm
or xterm-256color
and approximating XTerm to one degree or another. Let us cast off this taint, and become taintless.
If you're a terminal author, I encourage you to implement the XTGETTCAP
and XTVERSION
control sequences.
mosaicworld
It was obvious from the very first days of bitmap graphics support that breaking an image into cell-sized fragments offered many significant advantages. Performance issues of some terminals when making use of hundreds of independent graphics prevented me from immediately pursuing this implementation, but it's time to use it where possible. Mosaics will improve performance when interacting with other planes, improve reliability when the screen geometry changes, eliminate problems when a sprixel moves partially off-screen, and drastically simplify the logic of bitmapped graphics atop a terminal's matrix of cells.
better and faster sixel quantization
My quantization algorithm is slower than libsixel, and yet manages to also produce lower-quality encodings (on the plus side, it's not known to be riddled with major security problems). I look forward to significant improvements in both regards, certainly to the level of libsixel. It's likely that we'll want to integrate some dithering capabilities as well. Here's another area where mosaics have benefits: when your sixels are only as large as a single cell, you're less likely to suffer from quantization effects (at the cost, of course, of bandwidth).
When using the Kitty graphics protocol, Notcurses is unparalleled.
a replacement for libsixel
The maintainer of libsixel has been missing for years. @ctrlcctrlv roped me into comaintainership of a fork earlier this year, and we've been patching up the worst of things, but it's a fundamentally insecure API. I'll be wrapping the Notcurses sixel code with a libsixel-like API, one existing applications can move to with simple changes (essentially, a length needs be passed in along with the source buffer).
Notcurses-within-Notcurses and Background-Stay-Resident terminal "widgets"
This is some Deeper Fucking Magic from Beyond the Dawn of Time. Stay tuned to see something fundamentally new, if I can pull it off.
optimized PseudoColor palettes derived from dynamic RGB DirectColor content
It's oftentimes (almost always, actually) the case that a palette-indexed encoding of a given frame can require less bandwidth than a pure RGB version, yet encode all colors losslessly (assuming it can freely fall back to RGB). Notcurses currently always uses RGB when it is available, and maps RGB to palette-indexed terminals in a naive fashion. We can instead come up with an optimal palette on the fly, so long as it can be done with sufficient performance (i.e. median cut on all cells of every frame is not going to cut it). Suitable algorithms seem pretty obvious, if perhaps non-trivial. Implement this to save bandwidth (the first-order determinant of overall performance), and also to improve image quality when rendering to non-RGB terminals, especially color-starved terminals like the Linux console.
support for Linux's Direct Rendering Infrastructure
Just when I added Linux framebuffer support, it gets well and truly obsoleted. DRM is the (relatively) new hotness. I started in on some support during this development cycle, but it proved an unexpectedly tremendous pain in my ass, and was punted down the road.
more of the usual bullshit
- more commit messages making esoteric references to the literature of High Modernism
- more Ice Cube videos embedded into GitHub issues
- more ballin'
- yes of course i'm going to make a dank hype video for this release, gimme a week/fortnight