v0.1.2 moved xterm color functionality to color package, adapters added for compatibility
This commit is contained in:
@@ -6,15 +6,14 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/lixenwraith/color"
|
||||
"github.com/lixenwraith/terminal"
|
||||
"github.com/lixenwraith/terminal/inline"
|
||||
)
|
||||
|
||||
func main() {
|
||||
p := inline.New(os.Stdout)
|
||||
|
||||
name := inline.Fg(color.LightSkyBlue).Attr(terminal.AttrBold)
|
||||
okSt := inline.Fg(color.LimeGreen).Attr(terminal.AttrBold)
|
||||
name := inline.Fg(color.LightSkyBlue).Bold()
|
||||
okSt := inline.Fg(color.LimeGreen).Bold()
|
||||
dim := inline.Fg(color.IronGray)
|
||||
|
||||
pkgs := []string{"openssl", "zlib", "curl", "git", "go"}
|
||||
@@ -1,11 +1,6 @@
|
||||
package terminal
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/lixenwraith/color"
|
||||
)
|
||||
import "github.com/lixenwraith/color"
|
||||
|
||||
// ColorMode indicates terminal color capability
|
||||
type ColorMode uint8
|
||||
@@ -15,102 +10,14 @@ const (
|
||||
ColorModeTrueColor // 24-bit RGB
|
||||
)
|
||||
|
||||
// 6-bit quantized LUT for Redmean-based 256-color mapping
|
||||
// 64×64×64 = 262,144 bytes, fits in L2 cache
|
||||
const lut256Size = 64 * 64 * 64
|
||||
|
||||
// init() -> first-use build. Construction is ~63M Redmean evaluations
|
||||
// and 256 KiB resident; truecolor sessions never read the table.
|
||||
var (
|
||||
lut256Ptr atomic.Pointer[[lut256Size]uint8]
|
||||
lut256Once sync.Once
|
||||
)
|
||||
|
||||
// lut256 returns the palette LUT, building it on first use.
|
||||
// Fast path is an acquire load plus a predictable branch, and inlines into RGBTo256.
|
||||
func lut256() *[lut256Size]uint8 {
|
||||
if p := lut256Ptr.Load(); p != nil {
|
||||
return p
|
||||
}
|
||||
return lut256Build()
|
||||
// WarmPalette256 delegates to the color package's lazily evaluated 256-color LUT builder.
|
||||
// Exists to preserve terminal API backwards-compatibility.
|
||||
func WarmPalette256() {
|
||||
color.WarmXterm256()
|
||||
}
|
||||
|
||||
// lut256Build populates the table. Cold path, kept out of line so lut256 stays inlinable.
|
||||
// The release store publishes the fully written array to acquire loads in lut256.
|
||||
//
|
||||
//go:noinline
|
||||
func lut256Build() *[lut256Size]uint8 {
|
||||
lut256Once.Do(func() {
|
||||
t := new([lut256Size]uint8)
|
||||
for r := range 64 {
|
||||
for g := range 64 {
|
||||
for b := range 64 {
|
||||
// Expand 6-bit to 8-bit (shift left 2, add 2 for midpoint)
|
||||
c := color.RGB{
|
||||
R: uint8(r<<2 | 2),
|
||||
G: uint8(g<<2 | 2),
|
||||
B: uint8(b<<2 | 2),
|
||||
}
|
||||
t[r<<12|g<<6|b] = computeRedmean256(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
lut256Ptr.Store(t)
|
||||
})
|
||||
return lut256Ptr.Load()
|
||||
}
|
||||
|
||||
// WarmPalette256 forces LUT construction. Idempotent, safe for concurrent use.
|
||||
// Call before the first render when ColorMode is ColorMode256.
|
||||
// RGBTo256 runs on the render path under the terminal mutex; a lazy build there stalls the frame.
|
||||
func WarmPalette256() { _ = lut256() }
|
||||
|
||||
// computeRedmean256 finds the nearest 256-palette index using Redmean distance called from lut256Build, not init()
|
||||
func computeRedmean256(c color.RGB) uint8 {
|
||||
// Grayscale fast path
|
||||
if c.R == c.G && c.G == c.B {
|
||||
if c.R < 8 {
|
||||
return 16
|
||||
}
|
||||
if c.R > 238 {
|
||||
return 231
|
||||
}
|
||||
return uint8(232 + (int(c.R)-8)/10)
|
||||
}
|
||||
|
||||
bestIdx := uint8(16)
|
||||
minDist := 1 << 30
|
||||
|
||||
// Search 6×6×6 cube (indices 16-231)
|
||||
for i := range 216 {
|
||||
cand := color.RGB{
|
||||
R: cubeValues[i/36],
|
||||
G: cubeValues[(i/6)%6],
|
||||
B: cubeValues[i%6],
|
||||
}
|
||||
if d := color.RedmeanDistance(c, cand); d < minDist {
|
||||
minDist = d
|
||||
bestIdx = uint8(16 + i)
|
||||
}
|
||||
}
|
||||
|
||||
// Search grayscale ramp (indices 232-255)
|
||||
for i := range 24 {
|
||||
g := uint8(8 + i*10)
|
||||
if d := color.RedmeanDistance(c, color.RGB{R: g, G: g, B: g}); d < minDist {
|
||||
minDist = d
|
||||
bestIdx = uint8(232 + i)
|
||||
}
|
||||
}
|
||||
|
||||
return bestIdx
|
||||
}
|
||||
|
||||
// Color cube values for 6×6×6 palette (indices 16-231)
|
||||
var cubeValues = [6]uint8{0, 95, 135, 175, 215, 255}
|
||||
|
||||
// RGBTo256 converts RGB to nearest 256-color palette index.
|
||||
// O(1) via the Redmean LUT; the first call builds it (see WarmPalette256).
|
||||
// RGBTo256 delegates to the color package's perceptual quantizer.
|
||||
// Exists to preserve terminal API backwards-compatibility.
|
||||
func RGBTo256(c color.RGB) uint8 {
|
||||
return lut256()[int(c.R>>2)<<12|int(c.G>>2)<<6|int(c.B>>2)]
|
||||
return color.RGBTo256(c)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ module github.com/lixenwraith/terminal
|
||||
go 1.26.0
|
||||
|
||||
require (
|
||||
github.com/lixenwraith/color v0.0.0-20260715115131-49124ee97342
|
||||
github.com/lixenwraith/color v0.0.0-20260719094342-615e11bc7897
|
||||
golang.org/x/sys v0.47.0
|
||||
golang.org/x/term v0.45.0
|
||||
)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
github.com/lixenwraith/color v0.0.0-20260715115131-49124ee97342 h1:KhjVSKhsHrngqeQ6sIcXX7HMmocixQ7ZZCumycbEKBo=
|
||||
github.com/lixenwraith/color v0.0.0-20260715115131-49124ee97342/go.mod h1:p02MsAGqlmZu3sc6BPYCKmaedF+lqBoijnuu5cOrYeo=
|
||||
github.com/lixenwraith/color v0.0.0-20260719094342-615e11bc7897 h1:YkTK1vIzG6sqKRKaeUdkPyMT2laithY1d8tCqyId77U=
|
||||
github.com/lixenwraith/color v0.0.0-20260719094342-615e11bc7897/go.mod h1:p02MsAGqlmZu3sc6BPYCKmaedF+lqBoijnuu5cOrYeo=
|
||||
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
|
||||
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0=
|
||||
|
||||
+13
-16
@@ -6,8 +6,8 @@ keeps owning the terminal. Intended for CLI tools (package managers, service
|
||||
tooling, build scripts) that want color and live status without a full-screen
|
||||
TUI.
|
||||
|
||||
Unix only (`//go:build unix`). Depends on the parent `terminal` package for
|
||||
color types, capability detection, and RGB → 256 mapping.
|
||||
Cross-platform (Unix, Windows). Depends only on the `color` package for
|
||||
24-bit RGB inputs and 256-color automatic degradation.
|
||||
|
||||
## Model
|
||||
|
||||
@@ -43,17 +43,17 @@ Value type, zero value is unstyled, builder-composable:
|
||||
|
||||
| Function | Description |
|
||||
|---|---|
|
||||
| `Fg(c terminal.RGB) Style` | Starts a style with foreground color. |
|
||||
| `(s Style) Bg(c terminal.RGB) Style` | Adds background color. |
|
||||
| `(s Style) Attr(a terminal.Attr) Style` | Adds attribute bits (`AttrBold`, `AttrDim`, ...). |
|
||||
| `Fg(c color.RGB) Style` | Starts a style with foreground color. |
|
||||
| `(s Style) Bg(c color.RGB) Style` | Adds background color. |
|
||||
| `(s Style) Bold() Style` | Adds bold attribute (also: `Dim`, `Italic`, `Underline`, `Blink`, `Reverse`). |
|
||||
|
||||
```go
|
||||
warn := inline.Fg(terminal.Amber).Attr(terminal.AttrBold)
|
||||
warn := inline.Fg(color.Amber).Bold()
|
||||
p.Log("%s low disk space", p.Paint("warning:", warn))
|
||||
```
|
||||
|
||||
True color terminals get `38;2;R;G;B`; 256-color terminals get `38;5;N` via
|
||||
Redmean mapping — same degradation path as the parent package.
|
||||
Redmean mapping dynamically handled by the `color` package.
|
||||
|
||||
### Progress helpers
|
||||
|
||||
@@ -90,16 +90,16 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/lixenwraith/terminal"
|
||||
"github.com/lixenwraith/color"
|
||||
"github.com/lixenwraith/terminal/inline"
|
||||
)
|
||||
|
||||
func main() {
|
||||
p := inline.New(os.Stdout)
|
||||
|
||||
name := inline.Fg(terminal.LightSkyBlue).Attr(terminal.AttrBold)
|
||||
okSt := inline.Fg(terminal.LimeGreen).Attr(terminal.AttrBold)
|
||||
dim := inline.Fg(terminal.IronGray)
|
||||
name := inline.Fg(color.LightSkyBlue).Bold()
|
||||
okSt := inline.Fg(color.LimeGreen).Bold()
|
||||
dim := inline.Fg(color.IronGray)
|
||||
|
||||
pkgs := []string{"openssl", "zlib", "curl", "git", "go"}
|
||||
frame := 0
|
||||
@@ -123,14 +123,10 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
Run in a terminal: the two-line status block animates in place while
|
||||
completion lines accumulate above it. Piped (`go run . | cat`): only the
|
||||
completion lines and the final summary appear, unstyled.
|
||||
|
||||
## Notes
|
||||
|
||||
- Width is measured in runes (`unicode/utf8`); East Asian wide characters and
|
||||
combining marks are not width-aware — same limitation as `tui`.
|
||||
combining marks are not width-aware.
|
||||
- Live block lines must occupy one visual row each: no `\n`, tabs, or control
|
||||
characters. Lines are truncated to terminal width automatically; embedded
|
||||
SGR from `Paint` is preserved through truncation.
|
||||
@@ -139,3 +135,4 @@ completion lines and the final summary appear, unstyled.
|
||||
the format string.
|
||||
- Ctrl-C mid-update leaves the live block on screen but the terminal in a
|
||||
normal state — no raw mode or screen buffer to restore.
|
||||
|
||||
|
||||
+17
-11
@@ -1,5 +1,3 @@
|
||||
//go:build unix
|
||||
|
||||
// Package inline renders styled text and in-place progress in the normal
|
||||
// terminal scrollback: no raw mode, no alternate screen, no input handling,
|
||||
// no cursor hiding. Intended for CLI tools that want color and live status
|
||||
@@ -13,7 +11,7 @@
|
||||
// unless overridden with SetColor(true), Log and Done print plainly.
|
||||
//
|
||||
// Width is measured in runes (unicode/utf8); wide and combining characters
|
||||
// are not width-aware — same documented limitation as tui.
|
||||
// are not width-aware.
|
||||
package inline
|
||||
|
||||
import (
|
||||
@@ -23,7 +21,15 @@ import (
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/lixenwraith/terminal"
|
||||
"github.com/lixenwraith/color"
|
||||
)
|
||||
|
||||
// Internal color capability representation
|
||||
type colorMode uint8
|
||||
|
||||
const (
|
||||
colorMode256 colorMode = iota
|
||||
colorModeTrueColor
|
||||
)
|
||||
|
||||
// Printer manages styled output and the live block. Safe for concurrent use.
|
||||
@@ -32,25 +38,25 @@ type Printer struct {
|
||||
w *bufio.Writer
|
||||
tty *os.File // non-nil when output is a terminal
|
||||
color bool
|
||||
mode terminal.ColorMode
|
||||
mode colorMode
|
||||
live []string // desired live block content
|
||||
drawn int // lines currently on screen (may be clamped below len(live))
|
||||
}
|
||||
|
||||
// New creates a Printer for w. Terminal detection via WindowSize probe;
|
||||
// New creates a Printer for w. Terminal detection via size probe;
|
||||
// styling defaults on for terminals with NO_COLOR unset.
|
||||
func New(w io.Writer) *Printer {
|
||||
p := &Printer{w: bufio.NewWriter(w)}
|
||||
if f, isFile := w.(*os.File); isFile {
|
||||
if _, _, ok := terminal.WindowSize(f); ok {
|
||||
if _, _, ok := windowSize(f); ok {
|
||||
p.tty = f
|
||||
}
|
||||
}
|
||||
p.color = p.tty != nil && os.Getenv("NO_COLOR") == ""
|
||||
p.mode = terminal.DetectColorMode()
|
||||
p.mode = detectColorMode()
|
||||
// Keep the LUT build out of the first Paint call
|
||||
if p.color && p.mode == terminal.ColorMode256 {
|
||||
terminal.WarmPalette256()
|
||||
if p.color && p.mode == colorMode256 {
|
||||
color.WarmXterm256()
|
||||
}
|
||||
return p
|
||||
}
|
||||
@@ -66,7 +72,7 @@ func (p *Printer) SetColor(on bool) {
|
||||
// Size returns terminal dimensions, 80×24 when unknown
|
||||
func (p *Printer) Size() (w, h int) {
|
||||
if p.tty != nil {
|
||||
if w, h, ok := terminal.WindowSize(p.tty); ok {
|
||||
if w, h, ok := windowSize(p.tty); ok {
|
||||
return w, h
|
||||
}
|
||||
}
|
||||
|
||||
+1
-3
@@ -1,5 +1,3 @@
|
||||
//go:build unix
|
||||
|
||||
package inline
|
||||
|
||||
import "strings"
|
||||
@@ -36,7 +34,7 @@ func Bar(width int, pct float64, chars [3]rune) string {
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// Braille frames; intentionally duplicated from tui (no tui dependency)
|
||||
// Braille frames; standard monotonic iteration.
|
||||
var spinnerFrames = [...]string{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"}
|
||||
|
||||
// Spinner returns the frame for a monotonic counter
|
||||
|
||||
+40
-16
@@ -1,5 +1,3 @@
|
||||
//go:build unix
|
||||
|
||||
package inline
|
||||
|
||||
import (
|
||||
@@ -8,15 +6,27 @@ import (
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/lixenwraith/color"
|
||||
"github.com/lixenwraith/terminal"
|
||||
)
|
||||
|
||||
// Attribute represents visual text modifiers for inline styling
|
||||
type Attribute uint8
|
||||
|
||||
const (
|
||||
AttributeNone Attribute = 0
|
||||
Bold Attribute = 1 << 0
|
||||
Dim Attribute = 1 << 1
|
||||
Italic Attribute = 1 << 2
|
||||
Underline Attribute = 1 << 3
|
||||
Blink Attribute = 1 << 4
|
||||
Reverse Attribute = 1 << 5
|
||||
)
|
||||
|
||||
// Style describes text appearance; zero value is unstyled.
|
||||
// Composable: inline.Fg(terminal.Amber).Attr(terminal.AttrBold)
|
||||
// Composable: inline.Fg(color.Amber).Bold().Underline()
|
||||
type Style struct {
|
||||
fg, bg color.RGB
|
||||
hasFg, hasBg bool
|
||||
attr terminal.Attr
|
||||
attr Attribute
|
||||
}
|
||||
|
||||
// Fg starts a style with foreground color
|
||||
@@ -25,8 +35,23 @@ func Fg(c color.RGB) Style { return Style{fg: c, hasFg: true} }
|
||||
// Bg sets background color
|
||||
func (s Style) Bg(c color.RGB) Style { s.bg, s.hasBg = c, true; return s }
|
||||
|
||||
// Attr adds attribute bits
|
||||
func (s Style) Attr(a terminal.Attr) Style { s.attr |= a; return s }
|
||||
// Bold applies the bold attribute
|
||||
func (s Style) Bold() Style { s.attr |= Bold; return s }
|
||||
|
||||
// Dim applies the dim/faint attribute
|
||||
func (s Style) Dim() Style { s.attr |= Dim; return s }
|
||||
|
||||
// Italic applies the italic attribute
|
||||
func (s Style) Italic() Style { s.attr |= Italic; return s }
|
||||
|
||||
// Underline applies the underline attribute
|
||||
func (s Style) Underline() Style { s.attr |= Underline; return s }
|
||||
|
||||
// Blink applies the blink attribute
|
||||
func (s Style) Blink() Style { s.attr |= Blink; return s }
|
||||
|
||||
// Reverse applies the reverse video attribute
|
||||
func (s Style) Reverse() Style { s.attr |= Reverse; return s }
|
||||
|
||||
// Paint returns s styled for the detected terminal, unchanged when color
|
||||
// is disabled. Composes with Log: p.Log("%s %s", p.Paint("ok", st), name)
|
||||
@@ -44,36 +69,35 @@ func (p *Printer) Paint(s string, st Style) string {
|
||||
func (p *Printer) writeSGR(b *strings.Builder, s Style) {
|
||||
b.WriteString("\x1b[0")
|
||||
for _, m := range [...]struct {
|
||||
bit terminal.Attr
|
||||
bit Attribute
|
||||
code string
|
||||
}{
|
||||
{terminal.AttrBold, ";1"}, {terminal.AttrDim, ";2"},
|
||||
{terminal.AttrItalic, ";3"}, {terminal.AttrUnderline, ";4"},
|
||||
{terminal.AttrBlink, ";5"}, {terminal.AttrReverse, ";7"},
|
||||
{Bold, ";1"}, {Dim, ";2"},
|
||||
{Italic, ";3"}, {Underline, ";4"},
|
||||
{Blink, ";5"}, {Reverse, ";7"},
|
||||
} {
|
||||
if s.attr&m.bit != 0 {
|
||||
b.WriteString(m.code)
|
||||
}
|
||||
}
|
||||
if s.hasFg {
|
||||
if p.mode == terminal.ColorModeTrueColor {
|
||||
if p.mode == colorModeTrueColor {
|
||||
fmt.Fprintf(b, ";38;2;%d;%d;%d", s.fg.R, s.fg.G, s.fg.B)
|
||||
} else {
|
||||
fmt.Fprintf(b, ";38;5;%d", terminal.RGBTo256(s.fg))
|
||||
fmt.Fprintf(b, ";38;5;%d", color.RGBTo256(s.fg))
|
||||
}
|
||||
}
|
||||
if s.hasBg {
|
||||
if p.mode == terminal.ColorModeTrueColor {
|
||||
if p.mode == colorModeTrueColor {
|
||||
fmt.Fprintf(b, ";48;2;%d;%d;%d", s.bg.R, s.bg.G, s.bg.B)
|
||||
} else {
|
||||
fmt.Fprintf(b, ";48;5;%d", terminal.RGBTo256(s.bg))
|
||||
fmt.Fprintf(b, ";48;5;%d", color.RGBTo256(s.bg))
|
||||
}
|
||||
}
|
||||
b.WriteByte('m')
|
||||
}
|
||||
|
||||
// --- Width handling (internal, rune-count semantics) ---
|
||||
// Handles only 'm'-terminated escapes — this package's own SGR output.
|
||||
|
||||
// visibleLen counts runes excluding SGR sequences
|
||||
func visibleLen(s string) int {
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
//go:build unix
|
||||
|
||||
package inline
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func detectColorMode() colorMode {
|
||||
colorterm := os.Getenv("COLORTERM")
|
||||
if colorterm == "truecolor" || colorterm == "24bit" {
|
||||
return colorModeTrueColor
|
||||
}
|
||||
|
||||
if os.Getenv("KITTY_WINDOW_ID") != "" ||
|
||||
os.Getenv("KONSOLE_VERSION") != "" ||
|
||||
os.Getenv("ITERM_SESSION_ID") != "" ||
|
||||
os.Getenv("ALACRITTY_WINDOW_ID") != "" ||
|
||||
os.Getenv("ALACRITTY_LOG") != "" ||
|
||||
os.Getenv("WEZTERM_PANE") != "" {
|
||||
return colorModeTrueColor
|
||||
}
|
||||
|
||||
term := os.Getenv("TERM")
|
||||
if strings.Contains(term, "truecolor") ||
|
||||
strings.Contains(term, "24bit") ||
|
||||
strings.Contains(term, "direct") {
|
||||
return colorModeTrueColor
|
||||
}
|
||||
|
||||
return colorMode256
|
||||
}
|
||||
|
||||
func windowSize(f *os.File) (w, h int, ok bool) {
|
||||
ws, err := unix.IoctlGetWinsize(int(f.Fd()), unix.TIOCGWINSZ)
|
||||
if err != nil || ws.Col == 0 {
|
||||
return 0, 0, false
|
||||
}
|
||||
return int(ws.Col), int(ws.Row), true
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
//go:build !unix && !windows
|
||||
|
||||
package inline
|
||||
|
||||
import "os"
|
||||
|
||||
func detectColorMode() colorMode {
|
||||
return colorMode256
|
||||
}
|
||||
|
||||
func windowSize(f *os.File) (w, h int, ok bool) {
|
||||
return 0, 0, false
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
//go:build windows
|
||||
|
||||
package inline
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func detectColorMode() colorMode {
|
||||
if os.Getenv("WT_SESSION") != "" || os.Getenv("WT_PROFILE_ID") != "" {
|
||||
return colorModeTrueColor
|
||||
}
|
||||
if ct := os.Getenv("COLORTERM"); ct == "truecolor" || ct == "24bit" {
|
||||
return colorModeTrueColor
|
||||
}
|
||||
return colorMode256
|
||||
}
|
||||
|
||||
func windowSize(f *os.File) (w, h int, ok bool) {
|
||||
var info windows.ConsoleScreenBufferInfo
|
||||
if err := windows.GetConsoleScreenBufferInfo(windows.Handle(f.Fd()), &info); err != nil {
|
||||
return 0, 0, false
|
||||
}
|
||||
width := int(info.Window.Right-info.Window.Left) + 1
|
||||
height := int(info.Window.Bottom-info.Window.Top) + 1
|
||||
if width < 1 || height < 1 {
|
||||
return 0, 0, false
|
||||
}
|
||||
return width, height, true
|
||||
}
|
||||
+38
-77
@@ -1,93 +1,54 @@
|
||||
package terminal
|
||||
|
||||
// Generic xterm 256-color palette indices without game semantics
|
||||
// Game systems reference these via aliases in their own parameter files
|
||||
//
|
||||
// Color cube: index = 16 + 36*r + 6*g + b where r,g,b ∈ [0,5]
|
||||
// Grayscale ramp: indices 232-255, level = 8 + 10*(index-232)
|
||||
//
|
||||
// Ordered dark-to-light within each hue group
|
||||
import "github.com/lixenwraith/color"
|
||||
|
||||
// Generic xterm 256-color constants proxied to the central color package
|
||||
// to maintain backwards compatibility for the terminal package.
|
||||
|
||||
const (
|
||||
// --- Blue ---
|
||||
P256DeepNavy uint8 = 17 // (0,0,1)
|
||||
P256DarkBlue uint8 = 18 // (0,0,2)
|
||||
P256SteelBlue uint8 = 75 // (1,3,5)
|
||||
P256LightBlue uint8 = 81 // (1,4,5)
|
||||
|
||||
// --- Teal / Cyan ---
|
||||
P256DeepTeal uint8 = 23 // (0,1,1)
|
||||
P256Teal uint8 = 44 // (0,4,4)
|
||||
P256Green uint8 = 46 // (0,5,0)
|
||||
P256Cyan uint8 = 51 // (0,5,5)
|
||||
P256LightCyan uint8 = 87 // (1,5,5)
|
||||
|
||||
// --- Blue / Purple ---
|
||||
P256CobaltBlue uint8 = 33 // (0,2,5)
|
||||
P256DarkPurpleBlue uint8 = 54 // (1,0,2)
|
||||
P256Indigo uint8 = 63 // (1,1,5)
|
||||
P256Purple uint8 = 129 // (3,0,5)
|
||||
P256Violet uint8 = 134 // (3,1,4)
|
||||
P256MediumPurple uint8 = 135 // (3,1,5)
|
||||
P256Orchid uint8 = 176 // (4,2,4)
|
||||
|
||||
// --- Green / Yellow-Green ---
|
||||
P256YellowGreen uint8 = 154 // (3,5,0)
|
||||
|
||||
// --- Red ---
|
||||
P256Maroon uint8 = 52 // (1,0,0)
|
||||
P256DarkCrimson uint8 = 88 // (2,0,0)
|
||||
P256Crimson uint8 = 160 // (4,0,0)
|
||||
|
||||
// --- Red / Orange / Yellow ---
|
||||
P256Red uint8 = 196 // (5,0,0)
|
||||
P256Rose uint8 = 198 // (5,0,2)
|
||||
P256RedOrange uint8 = 202 // (5,1,0)
|
||||
P256Orange uint8 = 208 // (5,2,0)
|
||||
P256Amber uint8 = 214 // (5,3,0)
|
||||
P256Gold uint8 = 220 // (5,4,0)
|
||||
P256Yellow uint8 = 226 // (5,5,0)
|
||||
|
||||
// --- Orange / Brown ---
|
||||
P256DarkAmber uint8 = 94 // (2,1,0)
|
||||
|
||||
// --- Grayscale ---
|
||||
P256Gray uint8 = 240 // Grayscale step 8, level ~88
|
||||
P256DeepNavy = color.P256DeepNavy
|
||||
P256DarkBlue = color.P256DarkBlue
|
||||
P256SteelBlue = color.P256SteelBlue
|
||||
P256LightBlue = color.P256LightBlue
|
||||
P256DeepTeal = color.P256DeepTeal
|
||||
P256Teal = color.P256Teal
|
||||
P256Green = color.P256Green
|
||||
P256Cyan = color.P256Cyan
|
||||
P256LightCyan = color.P256LightCyan
|
||||
P256CobaltBlue = color.P256CobaltBlue
|
||||
P256DarkPurpleBlue = color.P256DarkPurpleBlue
|
||||
P256Indigo = color.P256Indigo
|
||||
P256Purple = color.P256Purple
|
||||
P256Violet = color.P256Violet
|
||||
P256MediumPurple = color.P256MediumPurple
|
||||
P256Orchid = color.P256Orchid
|
||||
P256YellowGreen = color.P256YellowGreen
|
||||
P256Maroon = color.P256Maroon
|
||||
P256DarkCrimson = color.P256DarkCrimson
|
||||
P256Crimson = color.P256Crimson
|
||||
P256Red = color.P256Red
|
||||
P256Rose = color.P256Rose
|
||||
P256RedOrange = color.P256RedOrange
|
||||
P256Orange = color.P256Orange
|
||||
P256Amber = color.P256Amber
|
||||
P256Gold = color.P256Gold
|
||||
P256Yellow = color.P256Yellow
|
||||
P256DarkAmber = color.P256DarkAmber
|
||||
P256Gray = color.P256Gray
|
||||
)
|
||||
|
||||
// Cube256 returns the xterm 256-palette index for an RGB cube coordinate.
|
||||
// r, g, b must be in [0,5]. Values outside that range are clamped.
|
||||
func Cube256(r, g, b uint8) uint8 {
|
||||
if r > 5 {
|
||||
r = 5
|
||||
}
|
||||
if g > 5 {
|
||||
g = 5
|
||||
}
|
||||
if b > 5 {
|
||||
b = 5
|
||||
}
|
||||
return 16 + 36*r + 6*g + b
|
||||
return color.Cube256(r, g, b)
|
||||
}
|
||||
|
||||
// CubeRGB256 returns the (r, g, b) cube coordinates for a 256-palette color cube index.
|
||||
// Index must be in [16,231]. Returns (0,0,0) for out-of-range indices.
|
||||
func CubeRGB256(index uint8) (r, g, b uint8) {
|
||||
if index < 16 || index > 231 {
|
||||
return 0, 0, 0
|
||||
}
|
||||
n := index - 16
|
||||
r = n / 36
|
||||
g = (n % 36) / 6
|
||||
b = n % 6
|
||||
return r, g, b
|
||||
return color.CubeRGB256(index)
|
||||
}
|
||||
|
||||
// Gray256 returns the xterm 256-palette index for a grayscale step.
|
||||
// step must be in [0,23] (maps to indices 232-255, levels 8-238).
|
||||
func Gray256(step uint8) uint8 {
|
||||
if step > 23 {
|
||||
step = 23
|
||||
}
|
||||
return 232 + step
|
||||
}
|
||||
return color.Gray256(step)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user