11.3 Color schemes
The compiler tries to make diagnostics usable more quickly
by using color to direct people’s attention
to the most relevant parts of diagnostics.
The compiler uses colors for the following five purposes.
We must explain these first,
before we can explain color schemes,
which are simple mappings from purposes (which we also call color roles)
to actual shades of color.
- ‘subject’
The compiler uses the ‘subject’ color
for the entity that the diagnostic is about.
(This may be something like a specific variable, type or predicate.)
- ‘incorrect’
The compiler uses the ‘incorrect’ color
to emphasize either
the description of what is wrong with the subject entity,
or the property of the subject entity that is wrong.
- ‘correct’
The compiler uses the ‘correct’ color
to emphasize the expected property of the subject entity,
where that differs from its actual property.
For example, when a call passes an argument of the wrong type,
it will show the argument’s actual type using the ‘incorrect’ color,
and the expected type using the ‘correct’ color.
It does this because the type is far more likely to be wrong in the call
than in the declaration of the called predicate or function.
- ‘inconsistent’
The compiler uses the ‘inconsistent’ color
when it knows that two parts of the code are inconsistent with each other,
but neither part is a priori more likely to be wrong than the other.
For example, when unifying two values of different types,
the compiler uses this color when printing the type of both values;
the compiler knows that in all likelyhood,
one type is correct and one is incorrect,
but it does not know which is which.
- ‘hint’
The compiler uses the ‘hint’ color when it reports observations
that may or may not explain the root of the problem it reports,
but which are worth looking into.
For example, when it reports that two actual arguments of a call
have types that do not match the types of the corresponding arguments
in the declaration of the callee,
it may give a hint that each of those actual arguments
do in fact each match the type of an argument in the callee,
just not the ones in the right positions,
implying that the actual problem may be
passing the right arguments in the wrong order.
Programmers can specify the colors
they want the compiler to use for each purpose
either by setting the environment variable ‘MERCURY_COLOR_SCHEME’
to a string (let’s call it ColorScheme),
or by specifying the compiler option ‘--color-scheme ColorScheme’.
In both cases, ColorScheme can be either
- the name of a color scheme built into the Mercury compiler, or
- the assignment of specific colors
for the roles that colors can play in its diagnostics.
The compiler currently has the following six builtin color schemes:
- ‘darkmode’
- ‘darkmode256’
- ‘darkmode16’
- ‘lightmode’
- ‘lightmode256’
- ‘lightmode16’
The “mode” in each name is optional,
meaning that e.g. ‘dark’ names the same color scheme as ‘darkmode’.
The schemes whose names contain “dark”
are intended to be used on terminal screens with dark backgrounds
(including black backgrounds).
The schemes whose names contain “light”
are intended to be used on terminal screens with light backgrounds
(including white backgrounds).
- The schemes ending without numbers use 24-bit RGB colors,
which your terminal or terminal emulator probably supports.
- The schemes ending in “256” use
the colors listed in the 8-bit color section under
‘https://en.wikipedia.org/wiki/ANSI_escape_code#Colors’,
which your terminal or terminal emulator
is virtually certain to support.
- The schemes ending in “16” use
the first 16 color slots listed of that 8-bit color table.
These 16 color slots differ from the other 240 colors in that table
in that most terminal emulators allow users
to select the actual colors that go into those slots.
This means that output that uses color schemes ending in “16”
may look different on terminals with different color palette settings,
and will match the intended look only with the default color palette.
(The builtin color schemes ending in “256”
avoid using these reassignable color slots.)
The other way to specify a color scheme
is to directly specify the colors you want the compiler to use
using a string such as
‘specified@subject=87:correct=40:incorrect=203:inconsistent=171:hint=226’.
The rules for this form of color scheme specification are as follows.
- The string must start with the string ‘specified@’.
- The rest of the string must not contain any white space,
but must consist of a colon-separated list
of one or more color assignments.
- Each color assignment must have the form ‘Role=Color’,
which assigns the given color to the given role.
- Each Role must be one of the five strings
‘subject’,
‘correct’,
‘incorrect’,
‘inconsistent’, and
‘hint’.
- Each Color must have of the following two forms.
- The first form is a decimal integer in the range 0 to 255 (both inclusive).
This selects a slot in the table in the 8-bit color section of
‘https://en.wikipedia.org/wiki/ANSI_escape_code#Colors’.
The caveat mentioned above about colors 0 to 15 apply here as well:
in most terminal emulators, these slots are reassignable,
so specifying one of these slots may or may not
get you to the color in that slot in that table.
The other 240 slots are not usually reassignable.
- The second form is a seven-character string
where the first character is ‘#’,
and each of the following six characters is a hexadecimal digit.
Each string ‘#RRGGBB’ specifies a 24-bit RGB color,
with ‘RR’ specifying its red component,
‘GG’ specifying its green component, and
‘BB’ specifying its blue component.
- If the color scheme has no color assignment for a given role,
then the compiler will not use color for that role.
- If the color scheme has two or more color assignments for the same role,
only the last one counts; the others are ignored.
As mentioned above,
programmers can specify color schemes
using the environment variable ‘MERCURY_COLOR_SCHEME’
and by using the ‘--color-scheme’ compiler option.
These can specify different schemes.
The rules the compiler uses to choose the color scheme that it will use
are as follows.
- If the command line contains a ‘--color-scheme’ option,
the compiler will use its color scheme.
(If the command line contains more than one ‘--color-scheme’ option,
the compiler will use the last one.)
- If the command line contains no ‘--color-scheme’ option,
but the environment variable ‘MERCURY_COLOR_SCHEME’ exists
and contains a nonempty string,
then the compiler will use its color scheme.
- If the command line contains no ‘--color-scheme’ option,
and the environment variable ‘MERCURY_COLOR_SCHEME’ does not exist
or contains an empty string,
but the files named in any ‘--options-file’ compiler options
(or, in the absence of such options, the ‘Mercury.options’ file),
include a ‘--color-scheme’ option
among the module-specific ‘MCFLAGS’ for the current module,
then the compiler will use its color scheme.
(If the options file(s) contain more than one ‘--color-scheme’ option,
the compiler will use the last one.)
- In the absence of a ‘--color-scheme’ option
on the command line, in the ‘MERCURY_COLOR_SCHEME’ environment variable
and in the options files,
the compiler will use its default color scheme, which is ‘light16’.
This scheme works reasonably well even on dark backgrounds,
even though (as its name indicates) it was designed for light backgrounds.
(This assumes that the color slots it uses hold
either their standard colors, or something reasonably close to them.)