2022-06-28 20:28:35 +03:00
|
|
|
package lipgloss
|
|
|
|
|
|
|
|
import (
|
2022-10-06 19:37:18 +03:00
|
|
|
"io"
|
2023-08-01 15:23:15 +03:00
|
|
|
"sync"
|
2022-10-06 19:37:18 +03:00
|
|
|
|
2022-06-28 20:28:35 +03:00
|
|
|
"github.com/muesli/termenv"
|
|
|
|
)
|
|
|
|
|
2023-03-09 21:23:40 +03:00
|
|
|
// We're manually creating the struct here to avoid initializing the output and
|
|
|
|
// query the terminal multiple times.
|
|
|
|
var renderer = &Renderer{
|
|
|
|
output: termenv.DefaultOutput(),
|
|
|
|
}
|
2022-06-28 20:28:35 +03:00
|
|
|
|
|
|
|
// Renderer is a lipgloss terminal renderer.
|
|
|
|
type Renderer struct {
|
|
|
|
output *termenv.Output
|
2022-10-03 20:11:44 +03:00
|
|
|
hasDarkBackground *bool
|
2023-08-01 15:23:15 +03:00
|
|
|
mtx sync.RWMutex
|
2022-06-28 20:28:35 +03:00
|
|
|
}
|
|
|
|
|
2023-03-08 22:51:26 +03:00
|
|
|
// RendererOption is a function that can be used to configure a [Renderer].
|
2022-06-28 20:28:35 +03:00
|
|
|
type RendererOption func(r *Renderer)
|
|
|
|
|
|
|
|
// DefaultRenderer returns the default renderer.
|
|
|
|
func DefaultRenderer() *Renderer {
|
|
|
|
return renderer
|
|
|
|
}
|
|
|
|
|
2023-03-03 00:53:19 +03:00
|
|
|
// SetDefaultRenderer sets the default global renderer.
|
|
|
|
func SetDefaultRenderer(r *Renderer) {
|
|
|
|
renderer = r
|
|
|
|
}
|
|
|
|
|
2022-06-28 20:28:35 +03:00
|
|
|
// NewRenderer creates a new Renderer.
|
2023-03-03 00:53:19 +03:00
|
|
|
//
|
|
|
|
// w will be used to determine the terminal's color capabilities.
|
|
|
|
func NewRenderer(w io.Writer, opts ...termenv.OutputOption) *Renderer {
|
2022-10-03 20:11:44 +03:00
|
|
|
r := &Renderer{
|
2023-03-03 00:53:19 +03:00
|
|
|
output: termenv.NewOutput(w, opts...),
|
2022-06-28 20:28:35 +03:00
|
|
|
}
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
2023-03-03 00:53:19 +03:00
|
|
|
// Output returns the termenv output.
|
|
|
|
func (r *Renderer) Output() *termenv.Output {
|
2023-08-01 15:23:15 +03:00
|
|
|
r.mtx.RLock()
|
|
|
|
defer r.mtx.RUnlock()
|
2023-03-03 00:53:19 +03:00
|
|
|
return r.output
|
2022-06-28 20:28:35 +03:00
|
|
|
}
|
|
|
|
|
2023-03-03 00:53:19 +03:00
|
|
|
// SetOutput sets the termenv output.
|
|
|
|
func (r *Renderer) SetOutput(o *termenv.Output) {
|
2023-08-01 15:23:15 +03:00
|
|
|
r.mtx.Lock()
|
|
|
|
defer r.mtx.Unlock()
|
2023-03-03 00:53:19 +03:00
|
|
|
r.output = o
|
2022-06-28 20:28:35 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// ColorProfile returns the detected termenv color profile.
|
|
|
|
func (r *Renderer) ColorProfile() termenv.Profile {
|
|
|
|
return r.output.Profile
|
|
|
|
}
|
|
|
|
|
|
|
|
// ColorProfile returns the detected termenv color profile.
|
|
|
|
func ColorProfile() termenv.Profile {
|
|
|
|
return renderer.ColorProfile()
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetColorProfile sets the color profile on the renderer. This function exists
|
|
|
|
// mostly for testing purposes so that you can assure you're testing against
|
|
|
|
// a specific profile.
|
|
|
|
//
|
|
|
|
// Outside of testing you likely won't want to use this function as the color
|
|
|
|
// profile will detect and cache the terminal's color capabilities and choose
|
|
|
|
// the best available profile.
|
|
|
|
//
|
|
|
|
// Available color profiles are:
|
|
|
|
//
|
2023-03-08 22:51:26 +03:00
|
|
|
// termenv.Ascii // no color, 1-bit
|
|
|
|
// termenv.ANSI //16 colors, 4-bit
|
|
|
|
// termenv.ANSI256 // 256 colors, 8-bit
|
|
|
|
// termenv.TrueColor // 16,777,216 colors, 24-bit
|
2022-06-28 20:28:35 +03:00
|
|
|
//
|
|
|
|
// This function is thread-safe.
|
|
|
|
func (r *Renderer) SetColorProfile(p termenv.Profile) {
|
2023-08-01 15:23:15 +03:00
|
|
|
r.mtx.Lock()
|
|
|
|
defer r.mtx.Unlock()
|
2022-06-28 20:28:35 +03:00
|
|
|
r.output.Profile = p
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetColorProfile sets the color profile on the default renderer. This
|
|
|
|
// function exists mostly for testing purposes so that you can assure you're
|
|
|
|
// testing against a specific profile.
|
|
|
|
//
|
|
|
|
// Outside of testing you likely won't want to use this function as the color
|
|
|
|
// profile will detect and cache the terminal's color capabilities and choose
|
|
|
|
// the best available profile.
|
|
|
|
//
|
|
|
|
// Available color profiles are:
|
|
|
|
//
|
2023-03-08 22:51:26 +03:00
|
|
|
// termenv.Ascii // no color, 1-bit
|
|
|
|
// termenv.ANSI //16 colors, 4-bit
|
|
|
|
// termenv.ANSI256 // 256 colors, 8-bit
|
|
|
|
// termenv.TrueColor // 16,777,216 colors, 24-bit
|
2022-06-28 20:28:35 +03:00
|
|
|
//
|
|
|
|
// This function is thread-safe.
|
|
|
|
func SetColorProfile(p termenv.Profile) {
|
|
|
|
renderer.SetColorProfile(p)
|
|
|
|
}
|
|
|
|
|
|
|
|
// HasDarkBackground returns whether or not the terminal has a dark background.
|
|
|
|
func HasDarkBackground() bool {
|
|
|
|
return renderer.HasDarkBackground()
|
|
|
|
}
|
|
|
|
|
2023-03-08 22:51:26 +03:00
|
|
|
// HasDarkBackground returns whether or not the renderer will render to a dark
|
|
|
|
// background. A dark background can either be auto-detected, or set explicitly
|
|
|
|
// on the renderer.
|
2022-10-03 20:11:44 +03:00
|
|
|
func (r *Renderer) HasDarkBackground() bool {
|
2023-08-01 15:23:15 +03:00
|
|
|
r.mtx.RLock()
|
|
|
|
defer r.mtx.RUnlock()
|
2022-10-03 20:11:44 +03:00
|
|
|
if r.hasDarkBackground != nil {
|
|
|
|
return *r.hasDarkBackground
|
|
|
|
}
|
|
|
|
return r.output.HasDarkBackground()
|
2022-06-28 20:28:35 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// SetHasDarkBackground sets the background color detection value for the
|
|
|
|
// default renderer. This function exists mostly for testing purposes so that
|
|
|
|
// you can assure you're testing against a specific background color setting.
|
|
|
|
//
|
|
|
|
// Outside of testing you likely won't want to use this function as the
|
|
|
|
// backgrounds value will be automatically detected and cached against the
|
|
|
|
// terminal's current background color setting.
|
|
|
|
//
|
|
|
|
// This function is thread-safe.
|
|
|
|
func SetHasDarkBackground(b bool) {
|
|
|
|
renderer.SetHasDarkBackground(b)
|
|
|
|
}
|
|
|
|
|
2022-10-03 20:11:44 +03:00
|
|
|
// SetHasDarkBackground sets the background color detection value on the
|
|
|
|
// renderer. This function exists mostly for testing purposes so that you can
|
|
|
|
// assure you're testing against a specific background color setting.
|
|
|
|
//
|
|
|
|
// Outside of testing you likely won't want to use this function as the
|
|
|
|
// backgrounds value will be automatically detected and cached against the
|
|
|
|
// terminal's current background color setting.
|
|
|
|
//
|
|
|
|
// This function is thread-safe.
|
|
|
|
func (r *Renderer) SetHasDarkBackground(b bool) {
|
2023-08-01 15:23:15 +03:00
|
|
|
r.mtx.Lock()
|
|
|
|
defer r.mtx.Unlock()
|
2022-10-03 20:11:44 +03:00
|
|
|
r.hasDarkBackground = &b
|
2022-06-28 20:28:35 +03:00
|
|
|
}
|