theme

package
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 30, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package theme is the look of the UI: the style roles every view draws with, and the small widgets built from them (framed boxes, key chips, key hints). It knows nothing of the model, so any part of the UI can use it.

Index

Constants

View Source
const (
	HighContrast      = "high-contrast"
	HighContrastDark  = "High Contrast Dark"
	HighContrastLight = "High Contrast Light"
)

HighContrast is the theme name for the high-contrast schemes: the dark one on a dark terminal, the light one on a light terminal, switching when the terminal does. HighContrastDark and HighContrastLight name one of them.

View Source
const ClassicName = "1-2-3 Classic"

ClassicName is the built-in 1-2-3 scheme.

View Source
const Peers = 6

Peers is how many colors tell the others sharing a workbook apart.

View Source
const SepRow = "\x00"

SepRow marks a separator in the rows passed to Frame.

View Source
const Terminal = "terminal"

Terminal is the theme name that keeps the terminal's own palette.

Variables

This section is empty.

Functions

func BarCover added in v0.3.0

func BarCover(frac float64, w int) []int

BarCover is how much of each of w columns a bar frac (0 to 1) of their width long covers, in eighths. A bar of a number above its shortest point is at least an eighth long, so it shows.

func Block added in v0.3.0

func Block(n int) string

Block is the glyph of a column a bar covers n eighths of, from the left: a space for none, a full block for all.

func Bridges added in v0.3.0

func Bridges(up, down, left, right sheet.Line) (onLeft, onRight bool)

Bridges reports which of a junction's horizontal arms are double lines it draws thick, meeting a thick line: the line beside the joint on that side starts with a thick stub (━═══), so the joint's arm runs on into it rather than stopping at a gap.

func Cells

func Cells(style lipgloss.Style, s string, w int) string

Cells pads or truncates s to exactly w columns, then styles it.

func Center

func Center(s string, w int) string

Center centers s in w columns, any odd space going right.

func Drawable added in v0.3.0

func Drawable(s lipgloss.Style) lipgloss.Style

Drawable returns s as it can be drawn: a standout role with an underline or strikethrough layered on it is drawn in its own colors without reverse video, because lipgloss draws the spaces of underlined or struck-out text without it, which would show their colors swapped. The underline or strikethrough is then that text's cue without color.

func Fill

func Fill(line string, width int, band lipgloss.Style) string

Fill draws a rendered line on a band's colors out to width columns: every cell without a background of its own gets the band's background, and every cell without a text color its foreground. Styled parts (key chips, the mode indicator) keep their colors. A band with no colors returns the line unchanged.

It works on the escape sequences, so it costs one pass over the line: the band's colors are set at the start and again after every SGR that resets them.

func HighlightMatches

func HighlightMatches(s string, idx []int, w int, base, hl lipgloss.Style) string

HighlightMatches renders s in w columns with the bytes at idx in the hl style, truncating with an ellipsis.

func Junction added in v0.3.0

func Junction(up, down, left, right sheet.Line) string

Junction returns the character drawn where cell edges meet, given the line of each arm: up, down, left and right (LineNone for no arm). A lone arm draws the whole line through, and no arm a space. Unicode joins double lines only to single ones: a single arm on the same axis as a double draws double, and where a double line meets a thick one the joint is drawn thick, the heavier look, as Unicode has no joint of the two (╠ between ┃ lines reads as a stray mark). The double line then starts beside the joint with a thick stub (see Bridges).

func KeyLabel

func KeyLabel(k string) string

KeyLabel formats a key binding for display, e.g. "ctrl+s" -> "Ctrl+S".

func Mixed added in v0.3.0

func Mixed(up, down, left, right sheet.Line) bool

Mixed reports whether a junction of these arms joins double and thick lines, which it draws thick.

func PadLeft

func PadLeft(s string, w int) string

PadLeft right-aligns s in w columns.

func PadRight

func PadRight(s string, w int) string

PadRight pads s with spaces to w columns.

func RuleSlot added in v0.2.0

func RuleSlot(c sheet.Color) int

RuleSlot is the ANSI color index of a rule color, or -1 for none.

Types

type Entry

type Entry struct {
	Name string
	Dark bool
	User bool // a file in the themes directory
}

Entry is a theme a picker can offer.

func List

func List(dir string) []Entry

List returns the themes available: terminal and high-contrast first, then the files in dir (the user's themes directory, may be ""), then the built-ins, each group sorted by name case-insensitively. A file with a built-in's name hides the built-in.

type Palette

type Palette struct {
	Name       string
	ANSI       [16]color.Color
	Background color.Color
	Foreground color.Color
	Selection  color.Color // may be nil
	Dark       bool
	File       string // the file it came from; empty for built-ins
	// HighContrast holds every role to WCAG AAA (7:1 for text) instead
	// of AA: the built-in high-contrast schemes.
	HighContrast bool
}

A Palette is a terminal color scheme, the kind every terminal ships and Ghostty, kitty, iTerm2 and VHS share: the 16 ANSI colors, the background and foreground, and optionally the selection color. 012's roles are defined on these slots (see New), so any scheme works.

func Builtins

func Builtins() []Palette

Builtins returns the built-in schemes.

func Lookup

func Lookup(name, dir string) (Palette, error)

Lookup finds a scheme by name: a file in dir first (named exactly, or with .json or .conf), then a built-in. Names match case-insensitively, and then ignoring spaces, hyphens and underscores, so "tokyo-night" finds "TokyoNight".

func ReadFile

func ReadFile(path string) ([]Palette, error)

ReadFile reads a theme file: Ghostty's format (palette = N=#rrggbb, background, foreground, selection-background), kitty's (color0 ... color15, background, foreground, selection_background), or VHS's JSON (one scheme or a list). A scheme without a name is named after the file.

type Shade added in v0.2.0

type Shade struct {
	Style       lipgloss.Style
	Open, Close string
}

Shade is a style drawn often, with the escape codes that open and close it, so a cell of plain text in it is written without rendering the style again.

func ShadeOf added in v0.3.0

func ShadeOf(s lipgloss.Style) Shade

ShadeOf is s with the escape codes that open and close it, for text drawn in it often.

func (Shade) Wrap added in v0.2.0

func (s Shade) Wrap(text string) string

Wrap draws text in the shade.

type Syntax added in v0.3.0

type Syntax int

Syntax is a kind of token in a code cell, which Theme.Code styles.

const (
	SyntaxCommand  Syntax = iota // a command's name: ls, where, open
	SyntaxString                 // a string: "a", 'b', a bare word argument
	SyntaxVariable               // $name, $in
	SyntaxNumber                 // numbers, sizes, durations, dates
	SyntaxKeyword                // let, def, if, true, null
	SyntaxOperator               // |, ==, and, =
	SyntaxComment                // # to the end of the line
	NumSyntax
)

type Theme

type Theme struct {
	Indicator    lipgloss.Style // mode indicator, top right
	Recording    lipgloss.Style // the REC chip beside the mode indicator while a macro is recorded
	Header       lipgloss.Style // column letters, row numbers and the name box
	HeaderActive lipgloss.Style // header of the focused row and column
	HeaderSel    lipgloss.Style // headers of selected rows and columns
	HeaderHover  lipgloss.Style // a header under the mouse
	Handle       lipgloss.Style // a column resize handle being hovered or dragged
	Pointer      lipgloss.Style // the cell pointer
	Selection    lipgloss.Style // a range being pointed at
	Hint         lipgloss.Style // guidance on the context line
	Warning      lipgloss.Style // recoverable problems, e.g. a formula error
	Error        lipgloss.Style // ERROR mode message
	Muted        lipgloss.Style // secondary text: key hints, file lists
	Key          lipgloss.Style // emphasized text in the status line, e.g. a range
	KeyChip      lipgloss.Style // a key cap in hints, menus and the palette, e.g. " Enter "
	ErrorCell    lipgloss.Style // cells whose value is ERR or NA
	// ErrorMark is layered on an error's text, so errors show beyond
	// color: a curly underline, in the error color where the terminal
	// supports colored underlines.
	ErrorMark lipgloss.Style
	Link      lipgloss.Style // a cell's URL or HYPERLINK label, layered on the cell's role
	Spilled   lipgloss.Style // values an array formula spilled into the cells below and right of it
	Found     lipgloss.Style // cells matching an open search
	// Precedent and Dependent mark what a formula reads and the formulas
	// reading a cell, while traced: in reverse video, dependents bold too,
	// so the two read apart without color.
	Precedent lipgloss.Style
	Dependent lipgloss.Style
	Argument  lipgloss.Style // the argument at the caret in a function's signature
	// EvalNext is the part of a formula Evaluate formula computes next,
	// underlined; Evaluated the values it has put in place of the parts
	// it computed, italic.
	EvalNext     lipgloss.Style
	Evaluated    lipgloss.Style
	Progress     lipgloss.Style // the done part of an import's progress bar
	ProgressTodo lipgloss.Style // the rest of the progress bar
	// Copied marks the range on the clipboard, like Sheets' dashed border:
	// a dashed underline across every cell, layered on the cell's own
	// style, with its own text color where the cell has none.
	Copied lipgloss.Style
	// FrozenLine divides frozen rows and columns from the scrolling ones,
	// like a tmux pane border.
	FrozenLine lipgloss.Style
	// Sheet tabs on the status line, like lazygit's panel tabs: plain
	// names (so they don't read as key chips), the sheet shown in the
	// accent and bold, and a tab under the mouse, or where a dragged tab
	// would go, bold and underlined.
	Tab       lipgloss.Style
	TabActive lipgloss.Style
	TabHover  lipgloss.Style
	// FilterOn is the filter mark in the header of a column whose filter
	// hides something (the mark itself also changes, from ▾ to ▼).
	FilterOn lipgloss.Style
	// TableHeader is a table's header row when the table styles it,
	// bold and underlined so it reads without color. TableBand is every
	// other data row of a banded table: a band of the background moved
	// toward the text, with the text on it readable.
	TableHeader lipgloss.Style
	TableBand   lipgloss.Style
	// NoteMark is the mark in the top-right corner of a cell with a note,
	// like Sheets' small triangle.
	NoteMark lipgloss.Style
	// CellBorder draws the lines of Format > Borders, in the ink of the
	// text beside them rather than a color of their own, as Sheets draws
	// borders black.
	CellBorder lipgloss.Style

	// Conditional formats (rules.go), indexed by sheet.Color: a rule's
	// text color on the cell, its fill with text readable on it, and
	// RuleOn[fill*sheet.NumColors+text] a text color on a fill, in the
	// fill's own ink where the text color wouldn't read on it.
	RuleText [sheet.NumColors]lipgloss.Style
	RuleFill [sheet.NumColors]lipgloss.Style
	RuleOn   [sheet.NumColors * sheet.NumColors]lipgloss.Style
	// Invalid is layered on the text of a cell that fails its data
	// validation, as Sheets' red corner: a dotted underline, in the
	// warning color where the terminal colors underlines.
	Invalid lipgloss.Style
	// Dropdown is the ▾ at the right of a cell with a dropdown list.
	Dropdown lipgloss.Style
	// DropdownChip is a dropdown's value drawn as a chip, as Sheets
	// draws them: in reverse video, so it reads without color, with its
	// rounded ends (▐ ▌) in DropdownCap, the chip's color.
	DropdownChip lipgloss.Style
	DropdownCap  lipgloss.Style
	// BarOn is text a data bar of a rule color runs under: reverse
	// video in the bar's color (see bars.go).
	BarOn [sheet.NumColors]lipgloss.Style

	// Chrome: the menu bar, dropdowns, the palette and dialogs.
	MenuBar           lipgloss.Style // menu bar titles
	MenuAccel         lipgloss.Style // a title's accelerator letter
	MenuSelected      lipgloss.Style // open title, highlighted item
	MenuAccelSelected lipgloss.Style // accelerator letter of the open title
	Border            lipgloss.Style // box borders and separators
	Title             lipgloss.Style // box titles and group headings
	Disabled          lipgloss.Style // items that can't run right now
	Match             lipgloss.Style // characters matched by a search
	MatchSelected     lipgloss.Style // matched characters in the highlighted row
	Cell              lipgloss.Style // an ordinary cell: the base for bold, italic and underline

	// Bars: full-width bands behind the menu bar, formula bar, context
	// line, column headers and status line. Each line is drawn on its
	// role's background, with its foreground for text that has none, out
	// to the terminal's edge; an empty role leaves the line as it is.
	MenuBarRow      lipgloss.Style
	FormulaBarRow   lipgloss.Style
	ContextRow      lipgloss.Style
	ColumnHeaderRow lipgloss.Style
	StatusBarRow    lipgloss.Style
	RowHeader       lipgloss.Style // row numbers not focused, selected or hovered
	// Screen is the background and default text color of the whole
	// screen. Empty in the terminal theme, so the terminal's own show.
	Screen lipgloss.Style

	// Name is the theme's name, and Palette its colors: nil for the
	// terminal theme, whose colors only the terminal knows.
	Name    string
	Palette *Palette

	// Notebooks: see package nbview. Code is a code cell's syntax, by
	// its kind (SyntaxCommand and the rest). CellHead is what the cells
	// say around their code: the [1]: and Out[1]: prompts, a cell's name
	// and state on its box. CellBar is the bar left of the active cell in
	// command mode, blue as Jupyter's, and CellBarEdit in edit mode,
	// green, which also draws the edited cell's box; both are glyphs, so
	// they read without color. OutputHead is an output table's header
	// row, bold and underlined so it reads without color, and Stale the
	// mark of an output that may be out of date.
	Code        [NumSyntax]lipgloss.Style
	CellHead    lipgloss.Style
	CellBar     lipgloss.Style
	CellBarEdit lipgloss.Style
	OutputHead  lipgloss.Style
	Stale       lipgloss.Style

	// Charts: see charts.go in package ui.
	ChartFrame    lipgloss.Style // a chart's border
	ChartSelected lipgloss.Style // the border of the selected chart and its resize handle
	ChartAxis     lipgloss.Style // axis lines and tick marks
	ChartLabel    lipgloss.Style // tick values, category labels and legend text
	// Series colors bars, lines, slices and legend swatches, in order;
	// SeriesBg is the same colors as backgrounds, for the lower half of a
	// pie's half blocks. SeriesANSI is the ANSI index of each, so images
	// can use the terminal's own colors.
	Series     [chart.Colors]lipgloss.Style
	SeriesBg   [chart.Colors]lipgloss.Style
	SeriesANSI [chart.Colors]int

	// Peers are the others sharing a workbook in 012 serve, each in a
	// color of their own: their pointer's cell in it, with a double
	// underline so it reads without color, and their initial as a chip
	// in it on the row header and their name on the status line (Peer,
	// text readable on the color); a cell they changed lately has a ▘ in
	// its top-left corner in their color (PeerMark).
	Peer     [Peers]lipgloss.Style
	PeerMark [Peers]lipgloss.Style
	// contains filtered or unexported fields
}

Theme holds every style the UI draws with. Views must use these roles instead of creating styles inline, so the look stays consistent and a new theme only has to be defined here.

Roles are defined on the 16 ANSI colors (New). The terminal theme draws them as ANSI indexes, so the sheet follows the user's terminal palette, with dark and light variants that only differ where ANSI colors would lose contrast. A color scheme (FromPalette) draws the same roles in the scheme's colors, corrected for contrast, on its own background.

func FromPalette

func FromPalette(p Palette) Theme

FromPalette draws the roles in a color scheme's colors. The roles are New's, on the ANSI slots; each slot becomes the scheme's color. Then, so every scheme reads well:

  • the selection uses the scheme's selection color when it has one;
  • the menu and status bars are bands of the background moved toward the text color, and the column header row is filled with the header color;
  • a background role too close to the screen's is moved apart;
  • text that falls short of its contrast minimum (4.5:1 for text, 3:1 for hints and lines, 2:1 for unavailable items) against its background is moved toward the scheme's text color just far enough to meet it, or toward black or white.

func Monochrome added in v0.3.0

func Monochrome(t Theme) Theme

Monochrome returns t with every color of every role replaced by one gray, as a terminal without color, or a reader who can't tell the colors apart, sees it: what's left to tell states apart is text, glyphs and attributes (bold, italic, underline styles, reverse video). Tests draw with it to check that every state reads without color (see docs/contributing/ux.md#visual-rules).

func New

func New(dark bool) Theme

New returns the terminal theme's dark or light variant.

func Resolve

func Resolve(name string, dark bool, dir string) (Theme, error)

Resolve returns the theme called name: the terminal theme's or the high-contrast scheme's variant for a dark or light terminal, or a scheme found by Lookup in dir. An unknown scheme gives the terminal theme and the error.

func (*Theme) Chip

func (t *Theme) Chip(label string) string

Chip draws a key name as a key cap, e.g. "Ctrl+S".

func (*Theme) Chips

func (t *Theme) Chips(keys []string) string

Chips renders keys as key chips, e.g. [Ctrl+/] [F1].

func (*Theme) Frame

func (t *Theme) Frame(inner int, title, footer string, rows []string) []string

Frame draws a border around rows. A title sits in the top border and a footer at the right of the bottom border.

func (*Theme) ImageID

func (t *Theme) ImageID(id int) lipgloss.Style

ImageID is the style of an image's Unicode placeholders: the foreground color is not a color but the image's id, in the 256-color palette, which is how the terminal knows which image to draw there.

func (*Theme) KeyHints

func (t *Theme) KeyHints(pairs ...string) string

KeyHints renders key and description pairs, e.g. "Enter accept", each key as a chip.

func (*Theme) PeerCell added in v0.5.0

func (t *Theme) PeerCell(i int) lipgloss.Style

PeerCell is the role of a cell under another's pointer: their color, double-underlined.

func (*Theme) Rule added in v0.2.0

func (t *Theme) Rule(st sheet.RuleStyle) lipgloss.Style

Rule is the base style of a cell a single-color rule formats: its fill and text color, with text readable on the fill. Text styles are added by Text.

func (*Theme) RuleShade added in v0.2.0

func (t *Theme) RuleShade(st sheet.RuleStyle) Shade

RuleShade is Rule's style with its codes, kept per theme.

func (*Theme) ScaleFill added in v0.2.0

func (t *Theme) ScaleFill(from, to sheet.Color, pos float64, rgb func(slot int) color.Color) Shade

ScaleFill is the fill of a color scale's cell, pos (0 to 1) of the way from one point's color to the next's, with text readable on it. The colors are the scheme's, or for the terminal theme rgb's (the terminal's palette as it reports it). Shades are kept per theme.

func (*Theme) Text

func (t *Theme) Text(base lipgloss.Style, st sheet.Style) lipgloss.Style

Text adds a cell's bold, italic, underline and strikethrough to base, one of the cell roles (cell, pointer, selection, errorCell), so text styles show through the pointer and selection colors.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL