You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Currently, *Renderer type and name are misleading. It does not render styles, rather, it's a factory for new styles. The question becomes, do we need a style factory?
On a lower level, type Renderer does two things
Detect the color profile of the terminal
Detect the background color to determine whether it's light or dark
Some context before getting into the issue. A color profile is the terminal profile used to decide the terminal color capability i.e. whether it supports NoTTY (no colors or text decorations), Ascii (no colors), ANSI (4-bit), ANSI256 (16-bit), and TrueColor(RGB 24-bit).
The way Lip Gloss works right now is by having a global *Renderer for os.Stdout that is used for all new global styles i.e. lipgloss.NewStyle(). This may produce different styles on different environments. For example, Apple Terminal only supports the ANSI256 profile and defining a style such as lipgloss.NewStyle().Foreground(lipgloss.Color("#874BFD")) won't produce an RGB color ANSI sequence on Apple Terminal. Instead, Lip Gloss degrades the color to ANSI256 before generating the sequence.
The same goes for HasDarkBackground(), a style needs to know the terminal background color to decide between a light or a dark color for the AdaptiveColor type.
Why this is a problem?
This is not a problem for the average user. However, users who want to use Lip Gloss with Wish, or use it on a different output like os.Stderr might face issues detecting the appropriate profile and background color.
Name confusion, particularly type Renderer
Difficulty debugging things since detection is happening in the background auto-magically
Code complexity using Lip Gloss Renderers
How can we solve this?
// Profile is a color profile: NoTTY, Ascii, ANSI, ANSI256, or TrueColor.typeProfileintconst (
// TrueColor, 24-bit color profile, produce RGB colorsTrueColorProfile=iota// ANSI256, 8-bit color profile, degrades higher profile colors to 8-bitANSI256// ANSI, 4-bit color profile, degrades higher profile colors to 4-bitANSI// Ascii, disables style colorsAscii// nolint: revive// NoTTY, disables style colors and decorationsNoTTY
)
Given the introduction of color profiles in Lip Gloss, here's a proposal that might simplify this issue and make Lip Gloss "pure".
Embed the color profile and background color intype Style:
typeStylestruct {
colorProfileProfile// Defaults to `TrueColor`hasLightBackgroundbool// Terminals default to dark background i.e. hasLightBackground = false...// other props
}
func (sStyle) ColorProfile(pProfile) Style {
s.colorProfile=preturns
}
func (sStyle) HasLightBackground(vbool) Style {
s.hasLightBackground=vreturns
}
Then we would move the color profile and background detection to their functions
funcDetectColorProfile(output io.Writer, environ []string) ProfilefuncQueryHasLightBackground(in term.File, out term.File) bool
We can also introduce a global default color profile that new styles inherit from and can be overwritten by the above functions and helpers
var (
// ColorProfile is the color profile used by lipgloss.// This is the default color profile used to create new styles.// By default, it allows for 24-bit color (TrueColor), decorations, and// doesn't do color conversion.ColorProfileProfile// HasLightBackground is true if the terminal has a light background.// This is the default value used to create new styles.HasLightBackgroundboolonceStdDefaults sync.Once
)
// UseDefault will set the default color profile and background color detection// from the given terminal file descriptors and environment variables.funcUseDefault(in term.File, out term.File, env []string) {
ColorProfile=DetectColorProfile(out, env)
HasLightBackground=QueryHasLightBackground(in, out)
}
// UseStdDefaults will set the default color profile and background color// detection from the standard input, output, and OS environment variables.funcUseStdDefaults() {
UseDefault(os.Stdin, os.Stdout, os.Environ())
}
Then NewStyle can be defined as
// NewStyle returns a new, empty Style. While it's syntactic sugar for the// Style{} primitive, it's recommended to use this function for creating styles// in case the underlying implementation changes.funcNewStyle() Style {
onceStdDefaults.Do(UseStdDefaults)
returnStyle{
profile: ColorProfile,
hasLightBackground: HasLightBackground,
}
}
This users who wants to use a "pure" style can do lipgloss.Style{}.
The issue
Currently,
*Renderer
type and name are misleading. It does not render styles, rather, it's a factory for new styles. The question becomes, do we need a style factory?On a lower level,
type Renderer
does two thingsSome context before getting into the issue. A color profile is the terminal profile used to decide the terminal color capability i.e. whether it supports NoTTY (no colors or text decorations), Ascii (no colors), ANSI (4-bit), ANSI256 (16-bit), and TrueColor(RGB 24-bit).
The way Lip Gloss works right now is by having a global
*Renderer
foros.Stdout
that is used for all new global styles i.e.lipgloss.NewStyle()
. This may produce different styles on different environments. For example, Apple Terminal only supports the ANSI256 profile and defining a style such aslipgloss.NewStyle().Foreground(lipgloss.Color("#874BFD"))
won't produce an RGB color ANSI sequence on Apple Terminal. Instead, Lip Gloss degrades the color to ANSI256 before generating the sequence.The same goes for
HasDarkBackground()
, a style needs to know the terminal background color to decide between a light or a dark color for theAdaptiveColor
type.Why this is a problem?
This is not a problem for the average user. However, users who want to use Lip Gloss with Wish, or use it on a different output like
os.Stderr
might face issues detecting the appropriate profile and background color.type Renderer
How can we solve this?
Given the introduction of color profiles in Lip Gloss, here's a proposal that might simplify this issue and make Lip Gloss "pure".
Embed the color profile and background color in
type Style
:Then we would move the color profile and background detection to their functions
We can also introduce a global default color profile that new styles inherit from and can be overwritten by the above functions and helpers
Then
NewStyle
can be defined asThis users who wants to use a "pure" style can do
lipgloss.Style{}
.For more details checkout the beta branch
The text was updated successfully, but these errors were encountered: