solarized-emacs

a fork of Bozhidar Batsov's solarized-emacs
git clone https://git.trogloxene.org/solarized-emacs.git
Log | Files | Refs | README

commit 1f8f78f425cc6a2639e9cedd34ac5e420bcf2afc
parent 0f876b04ab4d934ad8f17a57afbd10e7aa5a1c48
Author: Thomas Frössman <thomasf@jossystem.se>
Date:   Wed, 20 Nov 2019 15:18:15 +0100

colorlab: refactor

Diffstat:
Mcolorlab/README.md | 3+++
Mcolorlab/main.go | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Dcolorlab/pkg/colorlab/accents.go | 138-------------------------------------------------------------------------------
Dcolorlab/pkg/colorlab/base.go | 137-------------------------------------------------------------------------------
Dcolorlab/pkg/colorlab/colrofinder.go | 50--------------------------------------------------
Mcolorlab/pkg/colorlab/namedcolors.go | 94-------------------------------------------------------------------------------
Acolorlab/pkg/colorlab/package.go | 2++
Dcolorlab/pkg/colorlab/solarized.go | 24------------------------
Acolorlab/pkg/colors/package.go | 2++
Mcolorlab/pkg/generator/accentpair.go | 11++++++-----
Acolorlab/pkg/generator/package.go | 2++
Mcolorlab/pkg/generator/palette.go | 7+++++--
Acolorlab/pkg/solarized/accents.go | 141+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acolorlab/pkg/solarized/base.go | 138+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acolorlab/pkg/solarized/colorfinder.go | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Acolorlab/pkg/solarized/package.go | 2++
Acolorlab/pkg/solarized/solarized.go | 26++++++++++++++++++++++++++
Acolorlab/pkg/solarized/sort.go | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
18 files changed, 508 insertions(+), 479 deletions(-)

diff --git a/colorlab/README.md b/colorlab/README.md @@ -15,3 +15,6 @@ internal tool under development. The utility requires at least go 1.13 `go run main.go` will rewrite all palettes in `../solarized-palettes.el` when run. + + +See https://godoc.org/github.com/bbatsov/solarized-emacs/colorlab diff --git a/colorlab/main.go b/colorlab/main.go @@ -5,14 +5,17 @@ import ( "bytes" "flag" "fmt" + "io" "io/ioutil" "log" "os" + "strconv" "strings" "github.com/bbatsov/solarized-emacs/colorlab/pkg/colorlab" "github.com/bbatsov/solarized-emacs/colorlab/pkg/colors" "github.com/bbatsov/solarized-emacs/colorlab/pkg/generator" + sol "github.com/bbatsov/solarized-emacs/colorlab/pkg/solarized" ) // Options are command line flags . @@ -34,7 +37,7 @@ func main() { for _, pal := range palettes { fmt.Println(pal.Name) nc := pal.Generate() - nc.PrintAlist(os.Stdout, 0) + PrintAlist(os.Stdout, nc, 0) // nc.FilterPrefix("base").PrintAlist(os.Stdout, 0) // Merge(nc.FilterSuffix("-d"), oldDarkAccents.NamedColors().WithSuffix("-do")).PrintAlist(os.Stdout, 0) // Merge(nc.FilterSuffix("-l"), oldLightAccents.NamedColors().WithSuffix("-lo")).PrintAlist(os.Stdout, 0) @@ -51,16 +54,16 @@ var ( BlendForegroundAmout: 0.3, Gamma: 0.01, MinimumLightnessDifference: 0.35, - ForegroundBlendFinder: colorlab.ExtremeColorFgFinder, - BackgroundBlendFinder: colorlab.ExtremeColorBgFinder, + ForegroundBlendFinder: sol.ExtremeColorFgFinder, + BackgroundBlendFinder: sol.ExtremeColorBgFinder, } default2BgFg = generator.AccentPairGenerator{ BlendBackgroundAmout: 0.6, BlendForegroundAmout: 0.45, Gamma: 0.04, MinimumLightnessDifference: 0.35, - ForegroundBlendFinder: colorlab.ExtremeColorFgFinder, - BackgroundBlendFinder: colorlab.ExtremeColorBgFinder, + ForegroundBlendFinder: sol.ExtremeColorFgFinder, + BackgroundBlendFinder: sol.ExtremeColorBgFinder, } palettes = []generator.Palette{ @@ -71,7 +74,7 @@ var ( BlendBackgroundAmout: default1BgFg.BlendBackgroundAmout, BlendForegroundAmout: default1BgFg.BlendForegroundAmout, Gamma: default1BgFg.Gamma, - ForegroundBlendFinder: colorlab.NamedColorFinder("base1"), + ForegroundBlendFinder: sol.NamedColorFinder("base1"), BackgroundBlendFinder: default1BgFg.BackgroundBlendFinder, MinimumLightnessDifference: 0.4, }, @@ -79,7 +82,7 @@ var ( BlendBackgroundAmout: default2BgFg.BlendBackgroundAmout, BlendForegroundAmout: default2BgFg.BlendForegroundAmout, Gamma: default2BgFg.Gamma, - ForegroundBlendFinder: colorlab.NamedColorFinder("base1"), + ForegroundBlendFinder: sol.NamedColorFinder("base1"), BackgroundBlendFinder: default2BgFg.BackgroundBlendFinder, MinimumLightnessDifference: 0.4, }, @@ -98,7 +101,7 @@ var ( BlendBackgroundAmout: default1BgFg.BlendBackgroundAmout, BlendForegroundAmout: default1BgFg.BlendForegroundAmout, Gamma: default1BgFg.Gamma, - ForegroundBlendFinder: colorlab.NamedColorFinder("base1"), + ForegroundBlendFinder: sol.NamedColorFinder("base1"), BackgroundBlendFinder: default1BgFg.BackgroundBlendFinder, MinimumLightnessDifference: 0.4, }, @@ -106,7 +109,7 @@ var ( BlendBackgroundAmout: default2BgFg.BlendBackgroundAmout, BlendForegroundAmout: default2BgFg.BlendForegroundAmout, Gamma: default2BgFg.Gamma, - ForegroundBlendFinder: colorlab.NamedColorFinder("base1"), + ForegroundBlendFinder: sol.NamedColorFinder("base1"), BackgroundBlendFinder: default2BgFg.BackgroundBlendFinder, MinimumLightnessDifference: 0.4, }, @@ -146,8 +149,8 @@ var ( } // The original solarized color palette - solarized = colorlab.Solarized{ - Base: colorlab.Base{ + solarized = sol.Solarized{ + Base: sol.Base{ Base03: colors.SolarizedBase03, Base02: colors.SolarizedBase02, Base01: colors.SolarizedBase01, @@ -157,7 +160,7 @@ var ( Base2: colors.SolarizedBase2, Base3: colors.SolarizedBase3, }, - Accents: colorlab.Accents{ + Accents: sol.Accents{ Blue: colors.SolarizedBlue, Cyan: colors.SolarizedCyan, Green: colors.SolarizedGreen, @@ -168,17 +171,17 @@ var ( Yellow: colors.SolarizedYellow, }, } - solarizedDarkHighContrast = colorlab.Solarized{ + solarizedDarkHighContrast = sol.Solarized{ Base: solarized.Base.Clone().ChangeLightness(0.04, -0.02), Accents: solarized.Accents.Clone().ChangeLightness(0.05), } - solarizedLightHighContrast = colorlab.Solarized{ + solarizedLightHighContrast = sol.Solarized{ Base: solarized.Base.Clone().ChangeLightness(0.02, -0.05), Accents: solarized.Accents.Clone().ChangeLightness(-0.05), } // the current -d colors in the emacs theme - oldDarkAccents = colorlab.Accents{ + oldDarkAccents = sol.Accents{ Blue: "#00629D", Cyan: "#00736F", Green: "#546E00", @@ -189,7 +192,7 @@ var ( Yellow: "#7B6000", } // the current -l colors in the emacs theme - oldLightAccents = colorlab.Accents{ + oldLightAccents = sol.Accents{ Blue: "#69B7F0", Cyan: "#69CABF", Green: "#B4C342", @@ -199,8 +202,8 @@ var ( Violet: "#9EA0E5", Yellow: "#DEB542", } - gruvboxDark = colorlab.Solarized{ - Base: colorlab.Base{ + gruvboxDark = sol.Solarized{ + Base: sol.Base{ Base03: colors.GruvboxDark0, Base02: colors.GruvboxDark0Soft, Base01: colors.GruvboxDark4, @@ -210,7 +213,7 @@ var ( Base2: colors.GruvboxLight4, Base3: colors.GruvboxLight0, }, - Accents: colorlab.Accents{ + Accents: sol.Accents{ Blue: colors.GruvboxBlue, Cyan: colors.GruvboxAqua, Green: colors.GruvboxGreen, @@ -222,8 +225,8 @@ var ( }, } // note: not inversed here - gruvboxLight = colorlab.Solarized{ - Base: colorlab.Base{ + gruvboxLight = sol.Solarized{ + Base: sol.Base{ Base03: colors.GruvboxDark0, Base02: colors.GruvboxDark0Soft, Base01: colors.GruvboxDark3, @@ -233,7 +236,7 @@ var ( Base2: colors.GruvboxLight1, Base3: colors.GruvboxLight0, }, - Accents: colorlab.Accents{ + Accents: sol.Accents{ Blue: colors.GruvboxDarkBlue, Cyan: colors.GruvboxAqua, Green: colors.GruvboxGreen, @@ -244,8 +247,8 @@ var ( Yellow: colors.GruvboxDarkYellow, }, } - zenburn = colorlab.Solarized{ - Base: colorlab.Base{ + zenburn = sol.Solarized{ + Base: sol.Base{ Base03: colors.ZenburnBg, Base02: colors.ZenburnBgP1, Base01: colorlab.HexColor(colors.ZenburnFgM1).Blend(colors.ZenburnFg, 0.3), @@ -255,7 +258,7 @@ var ( Base2: colorlab.HexColor(colors.ZenburnFgP1).Blend(colors.ZenburnFgP2, 0.5), Base3: colors.ZenburnFgP2, }, - Accents: colorlab.Accents{ + Accents: sol.Accents{ Blue: colors.ZenburnBlue, Cyan: colors.ZenburnCyan, Green: colors.ZenburnGreen, @@ -267,8 +270,8 @@ var ( }, } - monokai = colorlab.Solarized{ - Base: colorlab.Base{ + monokai = sol.Solarized{ + Base: sol.Base{ Base03: colors.Monokai03, Base02: colors.Monokai02, Base01: colors.Monokai01, @@ -278,7 +281,7 @@ var ( Base2: colors.Monokai0, Base3: colors.Monokai0, }, - Accents: colorlab.Accents{ + Accents: sol.Accents{ Blue: colors.MonokaiBlue, Cyan: colors.MonokaiCyan, Green: colors.MonokaiGreen, @@ -315,7 +318,7 @@ func rewriteTheme(nc colorlab.NamedColors, paletteName string) { } if strings.HasSuffix(txt, fmt.Sprintf(";; %s palette", paletteName)) { insideReplacement = true - nc.PrintAlist(&dst, 4) + PrintAlist(&dst, nc, 4) } } @@ -328,3 +331,32 @@ func rewriteTheme(nc colorlab.NamedColors, paletteName string) { ioutil.WriteFile("../solarized-palettes.el", dst.Bytes(), 0x776) } + +// PrintAlist prints the named colors list in a way that is compatible with solarized-palettes.el. +func PrintAlist(w io.Writer, n colorlab.NamedColors, indent int) (int, error) { + keys := sol.OrderedKeys(n) + var longestKey int + for _, n := range keys { + l := len(n) + if l > longestKey { + longestKey = l + } + } + longestKey = longestKey + prefix := "" + for i := 0; i < indent; i++ { + prefix += " " + + } + var nt int + + for _, name := range keys { + n, err := fmt.Fprintf(w, "%s(%-"+strconv.Itoa(longestKey)+"s . \"%s\")\n", prefix, name, n[name]) + n = n + nt + if err != nil { + return nt, err + } + + } + return nt, nil +} diff --git a/colorlab/pkg/colorlab/accents.go b/colorlab/pkg/colorlab/accents.go @@ -1,138 +0,0 @@ -package colorlab - -import "github.com/lucasb-eyer/go-colorful" - -// Accents . -type Accents struct { - Yellow HexColor - Orange HexColor - Red HexColor - Magenta HexColor - Violet HexColor - Blue HexColor - Cyan HexColor - Green HexColor -} - -type AccentColors [8]colorful.Color - -func NewAccents(cc [8]colorful.Color) Accents { - return Accents{ - Yellow: HexColor(cc[0].Clamped().Hex()), - Orange: HexColor(cc[1].Clamped().Hex()), - Red: HexColor(cc[2].Clamped().Hex()), - Magenta: HexColor(cc[3].Clamped().Hex()), - Violet: HexColor(cc[4].Clamped().Hex()), - Blue: HexColor(cc[5].Clamped().Hex()), - Cyan: HexColor(cc[6].Clamped().Hex()), - Green: HexColor(cc[7].Clamped().Hex()), - } -} -func (s Accents) Clone() Accents { - return Accents{ - Yellow: s.Yellow, - Orange: s.Orange, - Red: s.Red, - Magenta: s.Magenta, - Violet: s.Violet, - Blue: s.Blue, - Cyan: s.Cyan, - Green: s.Green, - } -} - -func (s Accents) Colors() AccentColors { - a := s.colorArray() - return [8]colorful.Color{ - a[0].Color(), - a[1].Color(), - a[2].Color(), - a[3].Color(), - a[4].Color(), - a[5].Color(), - a[6].Color(), - a[7].Color(), - } -} -func (a Accents) ChangeLightness(amount float64) Accents { - cc := a.Colors() - lightness := func(c colorful.Color, v float64) colorful.Color { - l, a, b := c.Lab() - l = l + v - return colorful.Lab(l, a, b) - } - cc[0] = lightness(cc[0], amount) - cc[1] = lightness(cc[1], amount) - cc[2] = lightness(cc[2], amount) - cc[3] = lightness(cc[3], amount) - cc[4] = lightness(cc[4], amount) - cc[5] = lightness(cc[5], amount) - cc[6] = lightness(cc[6], amount) - cc[7] = lightness(cc[7], amount) - return NewAccents(cc) -} -func (a Accents) ChangeSaturation(amount float64) Accents { - cc := a.Colors() - saturation := func(c colorful.Color, v float64) colorful.Color { - h, s, l := c.Hsl() - // s = math.Min(math.Max(s+v, 0), 1) - s = s + v - return colorful.Hsl(h, s, l) - } - cc[0] = saturation(cc[0], amount) - cc[1] = saturation(cc[1], amount) - cc[2] = saturation(cc[2], amount) - cc[3] = saturation(cc[3], amount) - cc[4] = saturation(cc[4], amount) - cc[5] = saturation(cc[5], amount) - cc[6] = saturation(cc[6], amount) - cc[7] = saturation(cc[7], amount) - return NewAccents(cc) -} - -func (a Accents) Blend(hc HexColor, amount float64) Accents { - c := hc.Color() - cc := a.Colors() - cc[0] = cc[0].BlendLab(c, amount) - cc[1] = cc[1].BlendLab(c, amount) - cc[2] = cc[2].BlendLab(c, amount) - cc[3] = cc[3].BlendLab(c, amount) - cc[4] = cc[4].BlendLab(c, amount) - cc[5] = cc[5].BlendLab(c, amount) - cc[6] = cc[6].BlendLab(c, amount) - cc[7] = cc[7].BlendLab(c, amount) - return NewAccents(cc) -} - -func (ac Accents) NamedColors() NamedColors { - nc := make(NamedColors, 8) - arr := ac.colorArray() - for idx, hex := range arr { - nc[accentNames[idx]] = hex - } - return nc -} - -func (s Accents) colorArray() [8]HexColor { - return [8]HexColor{ - s.Yellow, - s.Orange, - s.Red, - s.Magenta, - s.Violet, - s.Blue, - s.Cyan, - s.Green, - } -} - -var accentNames = [8]string{ - 0: "yellow", - 1: "orange", - 2: "red", - 3: "magenta", - 4: "violet", - 5: "blue", - 6: "cyan", - 7: "green", -} diff --git a/colorlab/pkg/colorlab/base.go b/colorlab/pkg/colorlab/base.go @@ -1,137 +0,0 @@ -package colorlab - -import ( - "log" - - "github.com/lucasb-eyer/go-colorful" -) - -type Base struct { - Base03 HexColor - Base02 HexColor - Base01 HexColor - Base00 HexColor - Base0 HexColor - Base1 HexColor - Base2 HexColor - Base3 HexColor -} - -type BaseColors [8]colorful.Color - -func NewBase(bc [8]colorful.Color) Base { - return Base{ - Base03: HexColor(bc[0].Clamped().Hex()), - Base02: HexColor(bc[1].Clamped().Hex()), - Base01: HexColor(bc[2].Clamped().Hex()), - Base00: HexColor(bc[3].Clamped().Hex()), - Base0: HexColor(bc[4].Clamped().Hex()), - Base1: HexColor(bc[5].Clamped().Hex()), - Base2: HexColor(bc[6].Clamped().Hex()), - Base3: HexColor(bc[7].Clamped().Hex()), - } -} -func (s Base) Clone() Base { - return Base{ - Base03: s.Base03, - Base02: s.Base02, - Base01: s.Base01, - Base00: s.Base00, - Base0: s.Base0, - Base1: s.Base1, - Base2: s.Base2, - Base3: s.Base3, - } -} -func (s Base) NamedColors() NamedColors { - nc := make(NamedColors, 8) - arr := s.colorArray() - for idx, hex := range arr { - nc[baseNames[idx]] = hex - } - return nc -} - -func (s Base) Colors() BaseColors { - a := s.colorArray() - return [8]colorful.Color{ - a[0].Color(), - a[1].Color(), - a[2].Color(), - a[3].Color(), - a[4].Color(), - a[5].Color(), - a[6].Color(), - a[7].Color(), - } -} - -func (s Base) colorArray() [8]HexColor { - return [8]HexColor{ - s.Base03, - s.Base02, - s.Base01, - s.Base00, - s.Base0, - s.Base1, - s.Base2, - s.Base3, - } -} - -// Returns true if the LAB lightness of base0 is larger than base03. -func (b Base) IsDarkOnBright() bool { - lightness := func(c colorful.Color) float64 { - l, _, _ := c.Lab() - return l - } - bg := b.Base03 - fg := b.Base0 - bgl := lightness(bg.Color()) - fgl := lightness(fg.Color()) - if fgl == bgl { - log.Fatalf("bg (%v) and fg (%v) are not supposed to have equal lightness: %v %v", bg, fg, bgl, fgl) - } - return fgl > bgl -} - -var baseNames = [8]string{ - 0: "base03", - 1: "base02", - 2: "base01", - 3: "base00", - 4: "base0", - 5: "base1", - 6: "base2", - 7: "base3", -} - -func (s Base) Inverse() Base { - return Base{ - Base03: s.Base3, - Base02: s.Base2, - Base01: s.Base1, - Base00: s.Base0, - Base0: s.Base00, - Base1: s.Base01, - Base2: s.Base02, - Base3: s.Base03, - } -} -func (b Base) ChangeLightness(amountFgs, amountBgs float64) Base { - cc := b.Colors() - lightness := func(c colorful.Color, v float64) colorful.Color { - l, a, b := c.Lab() - l = l + v - return colorful.Lab(l, a, b) - } - cc[0] = lightness(cc[0], amountBgs) - cc[1] = lightness(cc[1], amountBgs) - cc[2] = lightness(cc[2], amountFgs) - cc[3] = lightness(cc[3], amountBgs) - cc[4] = lightness(cc[4], amountFgs) - cc[5] = lightness(cc[5], amountFgs) - cc[6] = lightness(cc[6], amountFgs) - cc[7] = lightness(cc[7], amountFgs) - return NewBase(cc) -} diff --git a/colorlab/pkg/colorlab/colrofinder.go b/colorlab/pkg/colorlab/colrofinder.go @@ -1,50 +0,0 @@ -package colorlab - -import ( - "log" - - "github.com/lucasb-eyer/go-colorful" -) - -// Find a specific color in a Solarized based on some preconditon -type ColorFinder func(Solarized) colorful.Color - -// NamedColorFinder extracts a named color from a palette -func NamedColorFinder(name string) ColorFinder { - return func(sol Solarized) colorful.Color { - colors := sol.NamedColors() - c, ok := colors[name] - if !ok { - log.Fatalf("color %s not in list: %v", name, colors) - } - return c.Color() - } -} - -// BgFinder returns base03 from the input Solarized -func BgFinder(sol Solarized) colorful.Color { - return NamedColorFinder("base03")(sol) - -} - -// FgFinder finds base0 from the input Solarized -func FgFinder(sol Solarized) colorful.Color { - return NamedColorFinder("base0")(sol) - -} - -// ExtremeColorFgFinder finds the darkest base tone for light on dark or the lightest color for dark on light. -func ExtremeColorFgFinder(sol Solarized) colorful.Color { - if sol.IsDarkOnBright() { - return sol.Base.NamedColors().ColorList().ByLightnessDesc()[0] - } - return sol.Base.NamedColors().ColorList().ByLightness()[0] -} - -// ExtremeColorFgFinder finds the lightest base tone for light on dark or the darkest color for dark on light. -func ExtremeColorBgFinder(sol Solarized) colorful.Color { - if sol.IsDarkOnBright() { - return sol.Base.NamedColors().ColorList().ByLightness()[0] - } - return sol.Base.NamedColors().ColorList().ByLightnessDesc()[0] -} diff --git a/colorlab/pkg/colorlab/namedcolors.go b/colorlab/pkg/colorlab/namedcolors.go @@ -2,9 +2,6 @@ package colorlab import ( "fmt" - "io" - "sort" - "strconv" "strings" ) @@ -56,35 +53,6 @@ func (n NamedColors) FilterPrefix(prefix ...string) NamedColors { return nc } -// PrintAlist prints the named colors list in a way that is compatible with solarized-palettes.el. -func (n NamedColors) PrintAlist(w io.Writer, indent int) (int, error) { - keys := n.OrderedKeys() - var longestKey int - for _, n := range keys { - l := len(n) - if l > longestKey { - longestKey = l - } - } - longestKey = longestKey - prefix := "" - for i := 0; i < indent; i++ { - prefix += " " - - } - var nt int - - for _, name := range keys { - n, err := fmt.Fprintf(w, "%s(%-"+strconv.Itoa(longestKey)+"s . \"%s\")\n", prefix, name, n[name]) - n = n + nt - if err != nil { - return nt, err - } - - } - return nt, nil -} - func (n NamedColors) ColorList() ColorList { var res ColorList for _, v := range n { @@ -94,68 +62,6 @@ func (n NamedColors) ColorList() ColorList { return res } -// Orderedkeys returns the keys in a order that is like how solarized names should be ordered. -// -// primary orer is: -// -// 1. base names -// 2. accent colors -// 3. names that contain base names -// 4. names that contain accent color names -// 5. the rest -// -// secondary sort order is by string comparison. -// -func (n NamedColors) OrderedKeys() []string { - var names []string - for k, _ := range n { - names = append(names, k) - } - sort.Sort(sort.StringSlice(names)) - - var allNames []string - for _, n := range baseNames { - allNames = append(allNames, n) - } - for _, n := range accentNames { - allNames = append(allNames, n) - } - score := func(idx int, exact bool) int { - s := (len(allNames) - idx) + 1 - if exact { - s = s + len(allNames) - } - return s - } - sort.SliceStable(names, func(i int, j int) bool { - var is, js int // scores - in := names[i] - jn := names[j] - scoring: - for sortIdx, sortName := range allNames { - if is == 0 { - // log.Println(in, sortName) - if strings.Contains(in, sortName) { - is = score(sortIdx, in == sortName) - // fmt.Println("score in", in, sortName, is) - } - } - if js == 0 { - if strings.Contains(jn, sortName) { - js = score(sortIdx, jn == sortName) - // fmt.Println("score j", jn, sortName, js) - } - } - if is != 0 && js != 0 { - break scoring - } - } - // log.Println(is, js, in,jn) - return is > js - }) - return names -} - // Merge merges multiple NamedColors func Merge(nc ...NamedColors) NamedColors { res := make(NamedColors) diff --git a/colorlab/pkg/colorlab/package.go b/colorlab/pkg/colorlab/package.go @@ -0,0 +1,2 @@ +// Package colorlab contains general utulities for working with palette colors +package colorlab diff --git a/colorlab/pkg/colorlab/solarized.go b/colorlab/pkg/colorlab/solarized.go @@ -1,24 +0,0 @@ -package colorlab - -type Solarized struct { - Base - Accents -} - -func (s Solarized) Clone() Solarized { - return Solarized{ - Base: s.Base.Clone(), - Accents: s.Accents.Clone(), - } -} - -func (s Solarized) Inverse() Solarized { - return Solarized{ - Base: s.Base.Inverse(), - Accents: s.Accents.Clone(), - } -} - -func (s Solarized) NamedColors() NamedColors { - return Merge(s.Base.NamedColors(), s.Accents.NamedColors()) -} diff --git a/colorlab/pkg/colors/package.go b/colorlab/pkg/colors/package.go @@ -0,0 +1,2 @@ +// Package colors contains color constants for various palettes +package colors diff --git a/colorlab/pkg/generator/accentpair.go b/colorlab/pkg/generator/accentpair.go @@ -4,7 +4,8 @@ import ( "fmt" "math" - "github.com/bbatsov/solarized-emacs/colorlab/pkg/colorlab" + "github.com/bbatsov/solarized-emacs/colorlab/pkg/solarized" + "github.com/lucasb-eyer/go-colorful" ) @@ -15,11 +16,11 @@ type AccentPairGenerator struct { Gamma float64 MinimumLightnessDifference float64 - BackgroundBlendFinder colorlab.ColorFinder - ForegroundBlendFinder colorlab.ColorFinder + BackgroundBlendFinder solarized.ColorFinder + ForegroundBlendFinder solarized.ColorFinder } -func (g *AccentPairGenerator) Generate(sol colorlab.Solarized) (backgrounds, foregrounds colorlab.Accents) { +func (g *AccentPairGenerator) Generate(sol solarized.Solarized) (backgrounds, foregrounds solarized.Accents) { lightnessReport := false sol = sol.Clone() cs := sol.Accents.Colors() @@ -111,5 +112,5 @@ func (g *AccentPairGenerator) Generate(sol colorlab.Solarized) (backgrounds, for if lightnessReport { fmt.Println("\n\n") } - return colorlab.NewAccents(bgs), colorlab.NewAccents(fgs) + return solarized.NewAccents(bgs), solarized.NewAccents(fgs) } diff --git a/colorlab/pkg/generator/package.go b/colorlab/pkg/generator/package.go @@ -0,0 +1,2 @@ +// Package generator contains utilities for enhancing a pallete with variations of colors +package generator diff --git a/colorlab/pkg/generator/palette.go b/colorlab/pkg/generator/palette.go @@ -1,12 +1,15 @@ package generator -import "github.com/bbatsov/solarized-emacs/colorlab/pkg/colorlab" +import ( + "github.com/bbatsov/solarized-emacs/colorlab/pkg/colorlab" + "github.com/bbatsov/solarized-emacs/colorlab/pkg/solarized" +) // Palette . type Palette struct { Name string Inverse bool - Solarized colorlab.Solarized + Solarized solarized.Solarized Accent1Pair AccentPairGenerator Accent2Pair AccentPairGenerator diff --git a/colorlab/pkg/solarized/accents.go b/colorlab/pkg/solarized/accents.go @@ -0,0 +1,141 @@ +package solarized + +import ( + "github.com/bbatsov/solarized-emacs/colorlab/pkg/colorlab" + "github.com/lucasb-eyer/go-colorful" +) + +// Accents . +type Accents struct { + Yellow colorlab.HexColor + Orange colorlab.HexColor + Red colorlab.HexColor + Magenta colorlab.HexColor + Violet colorlab.HexColor + Blue colorlab.HexColor + Cyan colorlab.HexColor + Green colorlab.HexColor +} + +type AccentColors [8]colorful.Color + +func NewAccents(cc [8]colorful.Color) Accents { + return Accents{ + Yellow: colorlab.HexColor(cc[0].Clamped().Hex()), + Orange: colorlab.HexColor(cc[1].Clamped().Hex()), + Red: colorlab.HexColor(cc[2].Clamped().Hex()), + Magenta: colorlab.HexColor(cc[3].Clamped().Hex()), + Violet: colorlab.HexColor(cc[4].Clamped().Hex()), + Blue: colorlab.HexColor(cc[5].Clamped().Hex()), + Cyan: colorlab.HexColor(cc[6].Clamped().Hex()), + Green: colorlab.HexColor(cc[7].Clamped().Hex()), + } +} +func (s Accents) Clone() Accents { + return Accents{ + Yellow: s.Yellow, + Orange: s.Orange, + Red: s.Red, + Magenta: s.Magenta, + Violet: s.Violet, + Blue: s.Blue, + Cyan: s.Cyan, + Green: s.Green, + } +} + +func (s Accents) Colors() AccentColors { + a := s.colorArray() + return [8]colorful.Color{ + a[0].Color(), + a[1].Color(), + a[2].Color(), + a[3].Color(), + a[4].Color(), + a[5].Color(), + a[6].Color(), + a[7].Color(), + } +} +func (a Accents) ChangeLightness(amount float64) Accents { + cc := a.Colors() + lightness := func(c colorful.Color, v float64) colorful.Color { + l, a, b := c.Lab() + l = l + v + return colorful.Lab(l, a, b) + } + cc[0] = lightness(cc[0], amount) + cc[1] = lightness(cc[1], amount) + cc[2] = lightness(cc[2], amount) + cc[3] = lightness(cc[3], amount) + cc[4] = lightness(cc[4], amount) + cc[5] = lightness(cc[5], amount) + cc[6] = lightness(cc[6], amount) + cc[7] = lightness(cc[7], amount) + return NewAccents(cc) +} +func (a Accents) ChangeSaturation(amount float64) Accents { + cc := a.Colors() + saturation := func(c colorful.Color, v float64) colorful.Color { + h, s, l := c.Hsl() + // s = math.Min(math.Max(s+v, 0), 1) + s = s + v + return colorful.Hsl(h, s, l) + } + cc[0] = saturation(cc[0], amount) + cc[1] = saturation(cc[1], amount) + cc[2] = saturation(cc[2], amount) + cc[3] = saturation(cc[3], amount) + cc[4] = saturation(cc[4], amount) + cc[5] = saturation(cc[5], amount) + cc[6] = saturation(cc[6], amount) + cc[7] = saturation(cc[7], amount) + return NewAccents(cc) +} + +func (a Accents) Blend(hc colorlab.HexColor, amount float64) Accents { + c := hc.Color() + cc := a.Colors() + cc[0] = cc[0].BlendLab(c, amount) + cc[1] = cc[1].BlendLab(c, amount) + cc[2] = cc[2].BlendLab(c, amount) + cc[3] = cc[3].BlendLab(c, amount) + cc[4] = cc[4].BlendLab(c, amount) + cc[5] = cc[5].BlendLab(c, amount) + cc[6] = cc[6].BlendLab(c, amount) + cc[7] = cc[7].BlendLab(c, amount) + return NewAccents(cc) +} + +func (ac Accents) NamedColors() colorlab.NamedColors { + nc := make(colorlab.NamedColors, 8) + arr := ac.colorArray() + for idx, hex := range arr { + nc[accentNames[idx]] = hex + } + return nc +} + +func (s Accents) colorArray() [8]colorlab.HexColor { + return [8]colorlab.HexColor{ + s.Yellow, + s.Orange, + s.Red, + s.Magenta, + s.Violet, + s.Blue, + s.Cyan, + s.Green, + } +} + +var accentNames = [8]string{ + 0: "yellow", + 1: "orange", + 2: "red", + 3: "magenta", + 4: "violet", + 5: "blue", + 6: "cyan", + 7: "green", +} diff --git a/colorlab/pkg/solarized/base.go b/colorlab/pkg/solarized/base.go @@ -0,0 +1,138 @@ +package solarized + +import ( + "log" + + "github.com/bbatsov/solarized-emacs/colorlab/pkg/colorlab" + "github.com/lucasb-eyer/go-colorful" +) + +type Base struct { + Base03 colorlab.HexColor + Base02 colorlab.HexColor + Base01 colorlab.HexColor + Base00 colorlab.HexColor + Base0 colorlab.HexColor + Base1 colorlab.HexColor + Base2 colorlab.HexColor + Base3 colorlab.HexColor +} + +type BaseColors [8]colorful.Color + +func NewBase(bc [8]colorful.Color) Base { + return Base{ + Base03: colorlab.HexColor(bc[0].Clamped().Hex()), + Base02: colorlab.HexColor(bc[1].Clamped().Hex()), + Base01: colorlab.HexColor(bc[2].Clamped().Hex()), + Base00: colorlab.HexColor(bc[3].Clamped().Hex()), + Base0: colorlab.HexColor(bc[4].Clamped().Hex()), + Base1: colorlab.HexColor(bc[5].Clamped().Hex()), + Base2: colorlab.HexColor(bc[6].Clamped().Hex()), + Base3: colorlab.HexColor(bc[7].Clamped().Hex()), + } +} +func (s Base) Clone() Base { + return Base{ + Base03: s.Base03, + Base02: s.Base02, + Base01: s.Base01, + Base00: s.Base00, + Base0: s.Base0, + Base1: s.Base1, + Base2: s.Base2, + Base3: s.Base3, + } +} +func (s Base) NamedColors() colorlab.NamedColors { + nc := make(colorlab.NamedColors, 8) + arr := s.colorArray() + for idx, hex := range arr { + nc[baseNames[idx]] = hex + } + return nc +} + +func (s Base) Colors() BaseColors { + a := s.colorArray() + return [8]colorful.Color{ + a[0].Color(), + a[1].Color(), + a[2].Color(), + a[3].Color(), + a[4].Color(), + a[5].Color(), + a[6].Color(), + a[7].Color(), + } +} + +func (s Base) colorArray() [8]colorlab.HexColor { + return [8]colorlab.HexColor{ + s.Base03, + s.Base02, + s.Base01, + s.Base00, + s.Base0, + s.Base1, + s.Base2, + s.Base3, + } +} + +// Returns true if the LAB lightness of base0 is larger than base03. +func (b Base) IsDarkOnBright() bool { + lightness := func(c colorful.Color) float64 { + l, _, _ := c.Lab() + return l + } + bg := b.Base03 + fg := b.Base0 + bgl := lightness(bg.Color()) + fgl := lightness(fg.Color()) + if fgl == bgl { + log.Fatalf("bg (%v) and fg (%v) are not supposed to have equal lightness: %v %v", bg, fg, bgl, fgl) + } + return fgl > bgl +} + +var baseNames = [8]string{ + 0: "base03", + 1: "base02", + 2: "base01", + 3: "base00", + 4: "base0", + 5: "base1", + 6: "base2", + 7: "base3", +} + +func (s Base) Inverse() Base { + return Base{ + Base03: s.Base3, + Base02: s.Base2, + Base01: s.Base1, + Base00: s.Base0, + Base0: s.Base00, + Base1: s.Base01, + Base2: s.Base02, + Base3: s.Base03, + } +} +func (b Base) ChangeLightness(amountFgs, amountBgs float64) Base { + cc := b.Colors() + lightness := func(c colorful.Color, v float64) colorful.Color { + l, a, b := c.Lab() + l = l + v + return colorful.Lab(l, a, b) + } + cc[0] = lightness(cc[0], amountBgs) + cc[1] = lightness(cc[1], amountBgs) + cc[2] = lightness(cc[2], amountFgs) + cc[3] = lightness(cc[3], amountBgs) + cc[4] = lightness(cc[4], amountFgs) + cc[5] = lightness(cc[5], amountFgs) + cc[6] = lightness(cc[6], amountFgs) + cc[7] = lightness(cc[7], amountFgs) + return NewBase(cc) +} diff --git a/colorlab/pkg/solarized/colorfinder.go b/colorlab/pkg/solarized/colorfinder.go @@ -0,0 +1,50 @@ +package solarized + +import ( + "log" + + "github.com/lucasb-eyer/go-colorful" +) + +// Find a specific color in a Solarized based on some preconditon +type ColorFinder func(Solarized) colorful.Color + +// NamedColorFinder extracts a named color from a palette +func NamedColorFinder(name string) ColorFinder { + return func(sol Solarized) colorful.Color { + colors := sol.NamedColors() + c, ok := colors[name] + if !ok { + log.Fatalf("color %s not in list: %v", name, colors) + } + return c.Color() + } +} + +// BgFinder returns base03 from the input Solarized +func BgFinder(sol Solarized) colorful.Color { + return NamedColorFinder("base03")(sol) + +} + +// FgFinder finds base0 from the input Solarized +func FgFinder(sol Solarized) colorful.Color { + return NamedColorFinder("base0")(sol) + +} + +// ExtremeColorFgFinder finds the darkest base tone for light on dark or the lightest color for dark on light. +func ExtremeColorFgFinder(sol Solarized) colorful.Color { + if sol.IsDarkOnBright() { + return sol.Base.NamedColors().ColorList().ByLightnessDesc()[0] + } + return sol.Base.NamedColors().ColorList().ByLightness()[0] +} + +// ExtremeColorFgFinder finds the lightest base tone for light on dark or the darkest color for dark on light. +func ExtremeColorBgFinder(sol Solarized) colorful.Color { + if sol.IsDarkOnBright() { + return sol.Base.NamedColors().ColorList().ByLightness()[0] + } + return sol.Base.NamedColors().ColorList().ByLightnessDesc()[0] +} diff --git a/colorlab/pkg/solarized/package.go b/colorlab/pkg/solarized/package.go @@ -0,0 +1,2 @@ +// Package solarized contains functionality specific to the structure of a solarize palette +package solarized diff --git a/colorlab/pkg/solarized/solarized.go b/colorlab/pkg/solarized/solarized.go @@ -0,0 +1,26 @@ +package solarized + +import "github.com/bbatsov/solarized-emacs/colorlab/pkg/colorlab" + +type Solarized struct { + Base + Accents +} + +func (s Solarized) Clone() Solarized { + return Solarized{ + Base: s.Base.Clone(), + Accents: s.Accents.Clone(), + } +} + +func (s Solarized) Inverse() Solarized { + return Solarized{ + Base: s.Base.Inverse(), + Accents: s.Accents.Clone(), + } +} + +func (s Solarized) NamedColors() colorlab.NamedColors { + return colorlab.Merge(s.Base.NamedColors(), s.Accents.NamedColors()) +} diff --git a/colorlab/pkg/solarized/sort.go b/colorlab/pkg/solarized/sort.go @@ -0,0 +1,70 @@ +package solarized + +import ( + "sort" + "strings" + + "github.com/bbatsov/solarized-emacs/colorlab/pkg/colorlab" +) + +// Orderedkeys returns the keys in a order that is like how solarized names should be ordered. +// +// primary orer is: +// +// 1. base names +// 2. accent colors +// 3. names that contain base names +// 4. names that contain accent color names +// 5. the rest +// +// secondary sort order is by string comparison. +// +func OrderedKeys(n colorlab.NamedColors) []string { + var names []string + for k, _ := range n { + names = append(names, k) + } + sort.Sort(sort.StringSlice(names)) + + var allNames []string + for _, n := range baseNames { + allNames = append(allNames, n) + } + for _, n := range accentNames { + allNames = append(allNames, n) + } + score := func(idx int, exact bool) int { + s := (len(allNames) - idx) + 1 + if exact { + s = s + len(allNames) + } + return s + } + sort.SliceStable(names, func(i int, j int) bool { + var is, js int // scores + in := names[i] + jn := names[j] + scoring: + for sortIdx, sortName := range allNames { + if is == 0 { + // log.Println(in, sortName) + if strings.Contains(in, sortName) { + is = score(sortIdx, in == sortName) + // fmt.Println("score in", in, sortName, is) + } + } + if js == 0 { + if strings.Contains(jn, sortName) { + js = score(sortIdx, jn == sortName) + // fmt.Println("score j", jn, sortName, js) + } + } + if is != 0 && js != 0 { + break scoring + } + } + // log.Println(is, js, in,jn) + return is > js + }) + return names +}