# Copyright Kevin Deldycke <kevin@deldycke.com> and contributors.
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
"""The bundled catalog of terminal presets a capture can be drawn as.
A capture is a picture of a terminal, and terminals do not look alike. A preset
carries the four things that make one recognizable, so a reader placing the
image knows which desktop it came from:
- the **window decorations**, three round buttons on the left for macOS, three
glyphs on the right for Windows, a single one for GNOME;
- the **palette** its colors resolve against, which is what turns a bright blue
into Campbell's `#3B78FF` or Tango's `#729FCF`;
- the **font** the terminal ships with;
- the **prompt** its shell draws, `$` against `PS C:\\>`.
None of it is applied unless asked for: a capture with no preset keeps the
renderer's own neutral window, which is what every image in this project's
documentation is drawn as.
```{caution}
A palette here is a *published default*, transcribed from the scheme each
terminal ships (Campbell and One Half Light for Windows Terminal, Basic and Pro
for Apple's Terminal, Tango for GNOME), and cross-checked against
[iTerm2-Color-Schemes](https://github.com/mbadolato/iTerm2-Color-Schemes). It is
what the terminal looks like out of the box, not what any given reader has
configured theirs to.
```
"""
from __future__ import annotations
from typing import NamedTuple
TYPE_CHECKING = False
if TYPE_CHECKING:
from typing import Final
[docs]
class TerminalPalette(NamedTuple):
"""The colors a terminal resolves a capture's ANSI codes against.
The 16 `ansi` entries are the standard palette in the canonical order:
black, red, green, yellow, blue, magenta, cyan, white, then the same eight
in their bright variants.
"""
background: str
"""Color behind the text, as CSS spells it."""
foreground: str
"""Color of the text a CLI leaves unstyled."""
ansi: tuple[str, ...]
"""The 16 palette entries, normal eight first."""
titlebar: str
"""Color of the strip the window's title and buttons sit in.
A window's chrome, which the desktop paints rather than the terminal: a
shade off the background, so the top of the window reads as a window rather
than as the first line of output.
"""
MACOS_BUTTONS: Final = WindowButtons(circles=("#ff5f57", "#febc2e", "#28c840"))
"""Close, minimize and zoom, the three round buttons of an Aqua title bar."""
WINDOWS_BUTTONS: Final = WindowButtons(glyphs="\uff0d\u25a1\u2715")
"""Minimize, maximize and close, the three glyphs of a Windows title bar."""
GNOME_BUTTONS: Final = WindowButtons(glyphs="\u2715")
"""The single close button a GNOME window carries by default."""
APPLE_ANSI: Final = (
"#000000",
"#c23621",
"#25bc24",
"#adad27",
"#492ee1",
"#d338d3",
"#33bbc8",
"#cbcccd",
"#818383",
"#fc391f",
"#31e722",
"#eaec23",
"#5833ff",
"#f935f8",
"#14f0f0",
"#e9ebeb",
)
"""Palette shared by Apple Terminal's `Basic` and `Pro` schemes."""
CAMPBELL_ANSI: Final = (
"#0c0c0c",
"#c50f1f",
"#13a10e",
"#c19c00",
"#0037da",
"#881798",
"#3a96dd",
"#cccccc",
"#767676",
"#e74856",
"#16c60c",
"#f9f1a5",
"#3b78ff",
"#b4009e",
"#61d6d6",
"#f2f2f2",
)
"""Palette of `Campbell`, the scheme Windows Terminal opens with."""
ONE_HALF_LIGHT_ANSI: Final = (
"#383a42",
"#e45649",
"#50a14f",
"#c18301",
"#0184bc",
"#a626a4",
"#0997b3",
"#fafafa",
"#4f525d",
"#df6c75",
"#98c379",
"#e4c07a",
"#61afef",
"#c577dd",
"#56b5c1",
"#ffffff",
)
"""Palette of `One Half Light`, the light scheme Windows Terminal ships."""
TANGO_ANSI: Final = (
"#2e3436",
"#cc0000",
"#4e9a06",
"#c4a000",
"#3465a4",
"#75507b",
"#06989a",
"#d3d7cf",
"#555753",
"#ef2929",
"#8ae234",
"#fce94f",
"#729fcf",
"#ad7fa8",
"#34e2e2",
"#eeeeec",
)
"""Palette of Tango, which GNOME Terminal ships in a dark and a light dress."""
[docs]
class TerminalPreset(NamedTuple):
"""A terminal a capture can be drawn as.
Pass one to `click-extra screenshot --preset`, or to a `click:run` block as
`:screenshot-preset:`. Anything stated alongside it wins: a preset picks the
defaults, it does not lock them.
"""
label: str
"""Human name of the terminal, for the documentation and the help screen."""
buttons: WindowButtons
"""Decorations drawn in the title bar, see {class}`WindowButtons`."""
radius: int
"""How round the window's corners are, in pixels."""
prompt: str
"""Sigil the terminal's usual shell draws before a command."""
font_stack: str
"""Fonts the capture asks for, the terminal's own first.
Nothing is embedded, so a reader without the family falls back down the
list. Which is why each ends with the same generic `monospace` a browser
always resolves.
"""
dark: TerminalPalette
"""Colors the terminal shows on its dark scheme."""
light: TerminalPalette
"""Colors it shows on its light one."""
PRESETS: Final[dict[str, TerminalPreset]] = {
"linux": TerminalPreset(
label="GNOME Terminal",
buttons=GNOME_BUTTONS,
radius=6,
prompt="$",
font_stack="'Ubuntu Mono', 'DejaVu Sans Mono', monospace",
dark=TerminalPalette("#2e3436", "#d3d7cf", TANGO_ANSI, "#303030"),
light=TerminalPalette("#ffffff", "#2e3436", TANGO_ANSI, "#ebebeb"),
),
"macos": TerminalPreset(
label="Apple Terminal",
buttons=MACOS_BUTTONS,
radius=10,
prompt="$",
font_stack="'SF Mono', Menlo, Monaco, monospace",
dark=TerminalPalette("#000000", "#f2f2f2", APPLE_ANSI, "#3a3a3a"),
light=TerminalPalette("#ffffff", "#000000", APPLE_ANSI, "#e9e9e9"),
),
"plain": TerminalPreset(
label="No terminal at all",
buttons=WindowButtons(),
radius=0,
prompt="$",
font_stack="'Fira Code', 'Cascadia Code', Menlo, Consolas, monospace",
dark=TerminalPalette("#292929", "#c5c8c6", TANGO_ANSI, "#292929"),
light=TerminalPalette("#ffffff", "#000000", TANGO_ANSI, "#ffffff"),
),
"windows": TerminalPreset(
label="Windows Terminal",
buttons=WINDOWS_BUTTONS,
radius=0,
prompt="PS C:\\>",
font_stack="'Cascadia Code', 'Cascadia Mono', Consolas, monospace",
dark=TerminalPalette("#0c0c0c", "#cccccc", CAMPBELL_ANSI, "#202020"),
light=TerminalPalette("#fafafa", "#383a42", ONE_HALF_LIGHT_ANSI, "#f3f3f3"),
),
}
"""Every terminal a capture can be drawn as, alphabetically.
`plain` is the odd one out: it mimics no desktop, dropping the buttons and the
rounded corners for a capture that has to read as a block of output rather than
as a window, on a slide or in a paper.
"""