Terminal theme support

I pushed some stuff to start supporting different color themes. The current work entails:

  • Extended ansi_format/3 to accept abstract descriptions that can be mapped to concrete attributes using a hook. The default mapping is in boot/messages.pl. library(theme/dark) is the first implementation.
  • Added support for 8-bit and true color ANSI sequences to ansi_format/3. See comments in the library.

For now, the dark theme uses lighter versions of some of the colors. I have little clue about dark themes. They are hot, but I consider them poorly readable. Might be my eyes :slight_smile:

Work to do is to support the 8-bit and true color sequences in the SWI console emulation (swipl-win) and make proper themes. An open question is whether the current design is the right approach, notably whether there might be alternatives that reuse the work by others?

Another issue are dark themes for the native development tools (PceEmacs, tracer, etc) and SWISH. XPCE supports styling, so this should be doable.

Possibly related: do we want multi-lingual messages? Most of the infrastructure is already there, so if there are people willing to write translation files, it is worth considering.


I am no expert in them either, but do use them with

Visual Studio Code
Visual Studio

My personal opinion on them is that for viewing text for hours at a time, dark theme (black background instead of white background) is easier on the eyes. It is also said they save battery life because it takes less energy to make a black background than a white background.

Many may know this already, but it never hurts to state the obvious:

All of the tools I know that support it, do so by using CSS or something similar. The colors are not hard coded in the source code for the editor for the displayed object (text, buttons, messages, etc.), instead there are names for objects needing a color and the names are typically named similar to a hierarchy/module and a mapping file holds a color for each name.

See: Visual Studio Code: Theme Color

To make it easier to use the colors, the mapping is held in a text file (XML, JSON, or similar) which is used during startup to set the colors. Some tools even have a GUI to modify the mapping; since the mapping is typically of a Key/Value and the GUI was already in the tool for managing Key/value, the GUI is easily extended to handle the color mapping.

To make it even easier to use such color mappings, a single set of values for one mapping is called a theme, held in one file and can be set as a configuration option making it much easier to change the colors; only the name of the theme is needed to change the colors. Now because the color mappings are in a standard file format and have a name, they are posted online for download and installation as a plug-in/extension. See: Studio Styles


The code highlighting for specific programming languages gets more complicated because this feature can bring in tokenizers and parsers and refine the coloring to individual words and letters. This can be done with the theme or independently. See: Visual Studio Code: Syntax Highlight Guide.

While not part of colors in a tool but something to be aware of are other plugins that might step on or try to modify colors. Some spell checkers use to highlight misspellings in red but that has changed in many code editors to the squiggly line, See: Visual Studio Code: Code Spell Checker

1 Like

Thanks for the input. The VS stuff looks pretty hard wired to me :frowning:

I do not have a lot of opinion on the usefulness of dark themes. I simply see they are hot and know I don’t like them. It is rather obvious that you want a similar theme for all your applications though and thus providing theme support will make some people happy :slight_smile:

It is also clear that there must be a mapping from something that describes the purpose/context of the colored object to the actual color. The most obvious way to do that in Prolog is to use a term for the
purpose/context and a rule that maps this to actual colors. That is what I did so far with theme/dark.pl. From a Prolog point of view this is just perfect. You can create a simple mapping as a set of facts, but also rules that apply time of day :slight_smile: or get the mapping from e.g., the style mapping of some other tool.

What would be nice if we can somehow provide a sensible default and, for example. reuse preferences specified somewhere to deal with running text, warning, error, comment,etc.

Pushed a lot of stuff that should provide reasonable dark theme support for the console output as well as PceEmacs and the graphical debugger. To use, load one of these:

:- use_module(library(theme/dark)).
:- use_module(library(theme/auto)).

The auto version establishes whether your xterm-compatible terminal emulator runs a dark theme and if so loads the dark theme. Most Unix/Linux terminal emulators are xterm-compatible. Loading dark explicitly works on any device that supports ANSI color sequences, including swipl-win.exe on Windows and probably also to some extend swipl-win for MacOS (not tested).

Tested using terminator (a variant of gnome-terminal that supports splitting) on Ubuntu as well as Fedora and swipl-win.exe (under Wine on Linux).

My hope is this is enough of a start to motivate notably of lovers of dark themes to pick up the current status, refine and complete the theming support. Please send your pull requests :slight_smile:

1 Like

Not just your eyes, mine too :slight_smile:

Some non-xterm terminals, such as kitty and neo-vim's terminal (probably vim’s terminal also has the problem, but did not test) are looping forever with the following call used by the auto theme:

?- % loops forever in kitty and nvim's terminal
?- ansi_get_color(background,rgb(R,G,B)).

Other terminals, such as lxterm, urxvt, and alacritty respond properly (with false, or actual RGB values).

Perhaps it would be useful to use the format hook in order to extend format/2 to handle the most common ANSI sequences by using especial characters after the ~ (tilde).

Often you want to colorize different parts of a line in a different way, similar to what gcc 9 is doing now days to show nicely colorized errors.

PS. with_tty_raw/1 is not found by help/1 (I thought the help/1 index was generated automatically?)

Thanks for testing a lot of terminals!

Yes, this is rather fragile and in fact still broken. To detect the colours we must send the terminal an escape sequence and we expect it to reply with an escape sequence telling about its color mapping. Unfortunately we do not know what is on the other end of the line. I thought the proper convention is to test $TERM to be xterm or xterm-256color and the OS telling us we are talking to a terminal device (isatty). Unfortunately there seem to be terminals that set this variable but do not implement the color reporting (e.g., Apple Terminal App). There are also applications that create a pseudo tty, but do not change the TERM variable to dumb to tell applications this isn’t a smart terminal.

The whole sequence is also fragile because there can be data buffered on the line, so the first thing we read may not be the terminals reply. At the moment this data is skipped, but not (yet) re-added to the input.

One thing we can do is add a short timeout. Of course, no timeout is right and if too short we get the escape sequence as normal input (and thus typically a syntax error). This all is notably painful if Prolog is used by scripts, although having I/O connected to a terminal is not very common in that scenario.

It was my hope that we could add auto to the default initialization sequence at some point and give most users a nice welcome experience. That might never happen,

Ideas (and code) welcome!

Multiple colours in a single message are supported in print_message/2 since not-so-long. See boot/messages.pl, notably the message for discontiguous predicates. This should be applied consistently throughout all messages (with input from someone with some feeling for nice colour schemes it would become even better :slight_smile:

Was a typo in the docs. Yes, the docs are generated and indexed as part of the normal build.

Pushed a patch that adds a timeout and prints a warning if the timeout fires. This at least prevents the awkward blocking.

Ahh, this is very nice. I just took a look at library(theme/dark). New themes and theme components can be defined rather easily with prolog:console_color(ComponentType,AnsiSpec). It is simple to define a new theme. It is pretty much just a set of facts with prolog:console_color/2.

Very nice and easy to make new themes! Thanks Jan.

I guess you can unload a theme with unload_file/1?

P.S. Perhaps someone in the forum (maybe @EricGT who seems to be great with visual things!) can go through boot/messages.pl (GitHub) and colorize it in a beautiful way. Right now most messages are just one color (with a few exceptions like discontiguous errors).

That should remove the theme for the console. Part of the theme realization, notably for the IDE tools is done using directives though and unloading the code thus doesn’t help. XPCE lacks support for runtime change of preferences, So, I fear the correct answer is mostly not :frowning:


While themes do allow one to change the color of items ((text, buttons, messages, etc.) as I noted

and Jan notes

IMHO just adding colors to the messages would not be the first step, instead the messages would have to be mapped to a purpose/context and then a separate mapping from purpose/context to color would exist in a theme and the theme can be stored as a file. So until the purpose/context for all the items that are to be used with a theme are done, adding the colors is putting the cart before the horse. The mapping from item to purpose/context is a herculean task in itself. In my view all of the code would have to be read to find items that may or could use color and then add them to the purpose/context mapping. Also what happens if items are latter added or removed from the purpose/context mapping and default colors conflict with those added or missing mappings, e.g. one person decides that an error should have a red background and other person decides that an error should have a red foreground, now somewhere along the way errors get both red background and red foreground which results in a message that cannot be read because it is red text on a red background, I have seen this happen. If you are trying to debug this or figure it out and have this problem, how do you read the error message.

With regards to choosing colors, the colors should not be picked at random. There are actually very standardized ways of picking a base set of colors such that they are easy to distinguish the different colors. For a very basic way see: Color Schemes

Also IMHO when using colors with IDEs, the colors should be used to enhance the understanding of something or have a positive impact, be it controls, source code, messages, etc. Just adding colors to add colors can actually have a negative effect.

My personal understanding of why dark themes started was not to be different but because when many programmers used laptops and the battery would only last a few hours, by switching to a dark theme the battery would last longer. If you really want a battery to last longer, the easiest way is to just turn on airplane mode which shuts down the wireless receivers and transmitters.

Remember that this is a reply to a Request For Comments so these are all just comments and can be ignored. :slightly_smiling_face:

This is all already done, look at library(theme/dark); it already uses the purpose/context (like code) and maps it to a color.

AFAIK, virtually all laptops use backlight and thus it makes no difference.

From code to message we go through the following layers (skipping some hooks that are not so relevant here):

  • The code calls print_message(+Level, +Term)
    Where Level is informational, warning, error and a few more obscure ones and Term is an arbitrary Prolog that represents the message meaning and relevant context information. An example could be no_file(Name), meaning that there is no file named Name. There is no clear convention for constructing these terms, just make them sufficiently unique and self-explaining.
  • A DCG (prolog:message//1) that translates the message in a list of line elements. These are typically format terms (Format-Args) and some special instructions such as nl (newline). It also allows for ansi(Class, Format, Args), which requests for a styled string described by the format arguments Format-Args. Class used to be hard-wired, but can now be an abstract description (Prolog term) of the string. Examples used now are truth(true) representing this describes successful completion of a toplevel query.
  • The hook prolog:console_color(Class, Attrs) maps the class to concrete ANSI text attributes.

I think that is mostly ok. One could argue to add type information to the initial term passed to print_message/2. Most of the definition of this is history though and I’m nor entirely convinced this makes much sense. For the last step one could argue to make an indirection over a color scheme ar @EricGT suggests. Right now both the default and dark theme map to the default ANSI 16 color scheme. The rest does allow binding to 256 colors or direct color (if the terminal can do that).

The syntax highlighting goes through a similar process, library(prolog_colour) labeling ranges of the file with classes described as a Prolog term that is subsequently mapped to an xpce style object that describes foreground, background, font, underline, etc.

And yes, you can end up with red-on-red :frowning:

Colorgorical is more advanced color scheme generator, what I like about this one is

  1. gives you a choice of the number of colors up to 20
  2. gives the colors as RGB, Hex and a few others
  3. all of the color codes can be copied as a text string
  4. shows you a few examples of all of the colors used near each other
  5. can select lightness range, not too dark, not too light.
  6. keeps a history of results so you can compare several of them on a single screen together
  7. is based on research (paper)
  8. open source at GitHub

The one thing it is missing is an option for color blindness. It should choose colors that can be seen by people with different color blindness.

1 Like

Nice to create a new palette for the IDE tools! Also nice for the console if direct color is used. Right now we use the 16 colour ANSI palette though as this is the most widely supported baseline.

Since you work on the terminal palette, you might be interested in the True Color initiative for terminal emulators and console programs. See also the original gist. There is a list and some clarifications for many terminals.

1 Like