The nctree widget, PoC, and unitt rs #1164.
5.1 KiB
Notcurses viz Curses/NCURSES
The biggest difference, of course, is that Notcurses is neither an implementation of X/Open (aka XSI) Curses, nor part of SUS4-2018.
Differences from Curses
The detailed differences between Notcurses and NCURSES (a high-quality, ubiquitous implementation of Curses) probably can't be fully enumerated, and if they could, no one would want to read them. With that said, some design decisions might surprise NCURSES programmers:
- There is no distinct
PANEL
type. The z-buffer is a fundamental property, and all drawable surfaces are ordered along the z axis. There is no equivalent toupdate_panels()
. - Scrolling is disabled by default, and cannot be globally enabled.
- The Curses
cchar_t
has a fixed-size array ofwchar_t
. The Notcursescell
instead supports a UTF-8 encoded extended grapheme cluster of arbitrary length. The only supported encodings are ASCII viaANSI_X3.4-1968
and Unicode viaUTF-8
. - The cursor is disabled by default, when supported (
civis
capability). - Echoing of input is disabled by default, and
cbreak
mode is used by default. - Colors are usually specified as 24 bits in 3 components (RGB). If necessary, these will be quantized for the actual terminal. There are no "color pairs", but indexed palettes are supported.
- There is no distinct "pad" concept (these are NCURSES
WINDOW
s created with thenewpad()
function). All drawable surfaces can exceed the display size. - Multiple threads can freely call into Notcurses, so long as they're not
accessing the same data. In particular, it is always safe to concurrently
mutate different
ncplane
s in different threads. - NCURSES has thread-ignorant and thread-semi-safe versions, trace-enabled and traceless versions, and versions with and without support for wide characters. Notcurses is one library: no tracing, UTF-8, thread safety.
- There is no
ESCDELAY
concept; Notcurses expects that all bytes of a keyboard escape sequence arrive at the same time. This improves latency and simplifies the API. - It is an error in NCURSES to print to the bottommost, rightmost coordinate of the screen when scrolling is disabled (because the cursor cannot be advanced). Failure to advance the cursor does not result in an error in Notcurses (but attempting to print at the cursor when it has been advanced off the plane does).
- Notcurses has no support for soft labels (
slk_init()
, etc.), subwindows which share memory with their parents, nor the NCURSES tracing functionality (trace(3NCURSES)
). - Notcurses doesn't implement any of the
curs_util(3x)
functions, including window serialization/deserialization viaputwin()
/getwin()
. - Notcurses doesn't interact with
LINES
norCOLUMNS
environment variables.
Adapting NCURSES programs
Do you really want to do such a thing? NCURSES and the Curses API it implements are far more portable and better-tested than Notcurses is ever likely to be. Will your program really benefit from Notcurses's advanced features? If not, it's probably best left as it is.
Otherwise, most NCURSES concepts have clear partners in Notcurses. Any functions
making implicit use of stdscr
ought be replaced with their explicit
equivalents. stdscr
ought then be replaced with the result of
notcurses_stdplane()
(the standard plane). PANEL
s become ncplane
s; the
Panels API is otherwise pretty close. Anything writing a bare character will
become a simple cell
; multibyte or wide characters become complex cell
s.
Color no longer uses "color pairs". You can easily enough hack together a
simple table mapping your colors to RGB values, and color pairs to foreground
and background indices into said table. That'll work for the duration of a
porting effort, certainly.
I have adapted two large (~5k lines of C UI code each) programs from NCURSES to
Notcurses, and found it a fairly painless process. It was helpful to introduce
a shim layer, e.g. compat_mvwprintw
for NCURSES's mvwprintw
:
static int
compat_mvwprintw(struct ncplane* nc, int y, int x, const char* fmt, ...){
va_list va;
va_start(va, fmt);
if(ncplane_vprintf_yx(nc, y, x, fmt, va) < 0){
va_end(va);
return ERR;
}
va_end(va);
return OK;
}
These are pretty obvious, implementation-wise.
Some details
cbreak()
/nocbreak()
/echo()
/noecho()
/nl()
/nonl()
: termios properties are not exposed as granularly by Notcurses. Rendered mode always enters cbreak mode. Direct mode enters cbreak mode by default, butNCDIRECT_OPTION_INHIBIT_CBREAK
will inhibit this.raw()
/noraw()
: The line discipline conversions (e.g. Ctrl+C) can be disabled at any time withnotcurses_linesigs_disable()
, and turned back on withnotcurses_linesigs_enable()
.keypad()
: The keypad is always enabled, if thesmkx
capability is advertised.halfdelay()
/nodelay()
/timeout()
/wtimeout()
: No such global controls are supported. Usenotcurses_getc()
with a timeout if you want a timeout. Usenotcurses_getc_nblock()
if you want an immediate return.intrflush()
/qiflush()
/noqiflush()
: No such functionality is supported.typeahead()
: No such functionality is supported.