Skip to content

Support truecolour output with ncurses #1807

@Screwtapello

Description

@Screwtapello

Kakoune has (deliberately) limited support for applying colour-schemes with it's default ncurses-based UI. On one hand, ncurses really wants applications to use colour-indexes into the terminal's standard palette; on the other hand, every other modern display API wants 8-bits-per-channel RGB triples in the sRGB colour-space, and mawww is uncomfortable with designing Kakoune's colour-scheme API around the limitations of ncurses.

The current compromise is that Kakoune supports a few named colours that happen to map to the standard 8 terminal colours in the ncurses UI, arbitrary #rrggbb colours are passed to init_color(3N), modifying the entries in the terminal's 256-colour palette. This has it's downsides; as well as being impolite (the user might have configured those palette entries themselves, and Kakoune stomps on them) there are terminals that don't support modifying the 256-colour palette at all (the Qt terminal widget being a notable example).

Some terminals have added a 24-bit or "direct colour" mode so an application can set an arbitrary colour at any time without having to declare it beforehand; in particular, libvte (used by gnome-terminal), tmux and xterm (since version 331). People have previously suggested using this with Kakoune, but nothing has ever come of it because there was no way to ask or trick ncurses into taking advantage of this mode. However, support is being added to ncurses 6.1 libraries, I've spent some time trying to figure out how it's all supposed to work, and I wanted to write that information down somewhere before I forgot.

terminfo and ncurses

A new fragment has been added to the terminfo database, named xterm+direct, along with an entry named xterm-direct that layers the +direct fragment on top of the standard xterm entry.

This fragment rewrites the setab (set ANSI background) and setaf (set ANSI foreground) rules to directly accept a 24-bit colour rather than a palette index. Actually, it's a bit more complex than that: if I understand correctly, the darkest 8 shades of blue (i.e. #000000 through #000007) are taken to mean the standard 8 terminal colours rather than indistinguishable shades of black, so programs that blindly send setaf 2 will get the traditional green text instead of effectively-black. It also sets the RGB flag to signal that setab and setaf do not follow the traditional behaviour.

applications

Since most classic curses APIs take colour values as shorts, they can't be used with direct colour. You'll have to use ncurses extended APIs instead. For example, init_extended_pair(3N) instead of init_pair(3N).

Looking at the changes in xterm+direct, I'm guessing most palette-related ncurses functions like init_color(3N) and init_extended_color(3N) will just break. extended_color_content(3N) is a notable exception: if the terminfo RGB flag is set, it can get the RGB fields of a colour through masking and shifting instead of consulting the palette.

I'm not sure if there's a good way for an application to detect whether init_extended_pair(3N) wants palette-indexes or raw colours. Perhaps if calling tigetflag(3N) with "RGB" returns anything other than 0 (that is, if it's boolean true, or if it's present but not a boolean), that's the best heuristic?

users

This ncurses direct-colour mode is only available if $TERM is set to the name of a terminal-entry that contains the appropriate configuration. Right now, that's only true if $TERM is set to xterm-direct on a machine with a sufficiently-modern copy of ncurses installed (and by "sufficiently-modern" I mean "newer than January 2018"). Even on machines that have the xterm-direct entry in the terminfo database, users might not want to use it, since it will probably break applications designed to work with 256-colour support, and it deliberately excludes a bunch of other useful fragments like xterm+tmux (which declares extra xterm features tmux uses) and xterm+sl (declares a sequence for setting xterm's title text). Therefore, it will probably be a while before this mode is widely available, let alone the default.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions