summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Chausse <benjamin@chausse.xyz>2024-11-25 16:45:33 -0500
committerGitHub <noreply@github.com>2024-11-25 16:45:33 -0500
commit821c198fe6700a9e9e9eb07ab6922e7bde7f2bfb (patch)
tree33f696ab2dfa433bc1513fd44b313419b74cc812
parentbad902e67b98a2630ff4396f846a223e3eed6a7a (diff)
Accept initial color using -c flag (#14)
-rw-r--r--flags.go6
-rw-r--r--internal/switcher/switcher.go21
-rw-r--r--internal/userinput/userinput.go78
-rw-r--r--main.go36
4 files changed, 136 insertions, 5 deletions
diff --git a/flags.go b/flags.go
index 660c053..57607de 100644
--- a/flags.go
+++ b/flags.go
@@ -13,4 +13,10 @@ var AppFlags []cli.Flag = []cli.Flag{
Usage: "Log file",
Value: "/dev/null", // Don't log by default
},
+ &cli.StringFlag{
+ Name: "color",
+ Aliases: []string{"c"},
+ Usage: "Initial color",
+ Value: "",
+ },
}
diff --git a/internal/switcher/switcher.go b/internal/switcher/switcher.go
index fce242c..ec5c47a 100644
--- a/internal/switcher/switcher.go
+++ b/internal/switcher/switcher.go
@@ -51,8 +51,29 @@ func (m *Model) Prev() int {
return m.active
}
+func (m *Model) SetActive(i int) {
+ m.active = m.fixSel(i)
+}
+
+func (m *Model) UpdatePicker(i int, c colors.ColorSpace) {
+ m.pickers[i].SetColor(c)
+}
+
+func (m *Model) NewNotice(msg string) tea.Cmd {
+ return m.notices.New(msg)
+}
+
func (m Model) Init() tea.Cmd {
cmds := []tea.Cmd{}
+
+ // Make a backup of notices received before the program starts
+ // then reinitialize them with a proper expiration time.
+ noticeBackup := m.notices.Notices
+ m.notices = notices.New()
+ for _, v := range noticeBackup {
+ cmds = append(cmds, m.NewNotice(v))
+ }
+
for _, p := range m.pickers {
cmds = append(cmds, p.Init())
}
diff --git a/internal/userinput/userinput.go b/internal/userinput/userinput.go
new file mode 100644
index 0000000..8f1ecdc
--- /dev/null
+++ b/internal/userinput/userinput.go
@@ -0,0 +1,78 @@
+package userinput
+
+import (
+ "errors"
+ "fmt"
+ "strings"
+
+ "github.com/ChausseBenjamin/termpicker/internal/colors"
+)
+
+var (
+ errUnknownColorFormat = errors.New("Unrecognized color format")
+ errHexParsing = errors.New("Failed to parse hex color")
+ errRGBParsing = errors.New("Failed to parse RGB color")
+ errHSLParsing = errors.New("Failed to parse HSL color")
+ errCMYKParsing = errors.New("Failed to parse CMYK color")
+)
+
+func sanitize(s string) string {
+ s = strings.ReplaceAll(s, "\"", "")
+ s = strings.ReplaceAll(s, "%", "")
+ s = strings.ReplaceAll(s, "°", "")
+ s = strings.TrimSpace(s)
+ s = strings.ToLower(s)
+ return s
+}
+
+func ParseColor(s string) (colors.ColorSpace, error) {
+ s = sanitize(s)
+ switch {
+ case strings.Contains(s, "#"):
+ return parseHex(s)
+ case strings.Contains(s, "rgb"):
+ return parseRGB(s)
+ case strings.Contains(s, "hsl"):
+ return parseHSL(s)
+ case strings.Contains(s, "cmyk"):
+ return parseCMYK(s)
+ default:
+ return nil, errUnknownColorFormat
+ }
+}
+
+func parseRGB(s string) (colors.ColorSpace, error) {
+ var r, g, b int
+ _, err := fmt.Sscanf(s, "rgb(%d,%d,%d)", &r, &g, &b)
+ if err != nil {
+ return nil, errors.Join(errRGBParsing, err)
+ }
+ return colors.RGB{R: r, G: g, B: b}, nil
+}
+
+func parseHex(s string) (colors.ColorSpace, error) {
+ var r, g, b int
+ _, err := fmt.Sscanf(s, "#%02x%02x%02x", &r, &g, &b)
+ if err != nil {
+ return nil, errors.Join(errHexParsing, err)
+ }
+ return colors.RGB{R: r, G: g, B: b}, nil
+}
+
+func parseCMYK(s string) (colors.ColorSpace, error) {
+ var c, m, y, k int
+ _, err := fmt.Sscanf(s, "cmyk(%d,%d,%d,%d)", &c, &m, &y, &k)
+ if err != nil {
+ return nil, errors.Join(errCMYKParsing, err)
+ }
+ return colors.CMYK{C: c, M: m, Y: y, K: k}, nil
+}
+
+func parseHSL(str string) (colors.ColorSpace, error) {
+ var h, s, l int
+ _, err := fmt.Sscanf(str, "hsl(%d,%d,%d)", &h, &s, &l)
+ if err != nil {
+ return nil, errors.Join(errHSLParsing, err)
+ }
+ return colors.HSL{H: h, S: s, L: l}, nil
+}
diff --git a/main.go b/main.go
index 241adcf..4f61c75 100644
--- a/main.go
+++ b/main.go
@@ -4,8 +4,10 @@ import (
"log/slog"
"os"
+ "github.com/ChausseBenjamin/termpicker/internal/colors"
"github.com/ChausseBenjamin/termpicker/internal/picker"
"github.com/ChausseBenjamin/termpicker/internal/switcher"
+ "github.com/ChausseBenjamin/termpicker/internal/userinput"
"github.com/ChausseBenjamin/termpicker/internal/util"
tea "github.com/charmbracelet/bubbletea"
"github.com/urfave/cli/v2"
@@ -23,10 +25,34 @@ func AppAction(ctx *cli.Context) error {
slog.SetDefault(slog.New(handler))
slog.Info("Starting Termpicker")
- rgb := picker.RGB()
- cmyk := picker.CMYK()
- hsl := picker.HSL()
- sw := switcher.New([]picker.Model{*rgb, *cmyk, *hsl})
+
+ sw := switcher.New([]picker.Model{
+ *picker.RGB(),
+ *picker.CMYK(),
+ *picker.HSL(),
+ })
+
+ if colorStr := ctx.String("color"); colorStr != "" {
+ color, err := userinput.ParseColor(colorStr)
+ if err != nil {
+ slog.Error("Failed to parse color", util.ErrKey, err)
+ sw.NewNotice(err.Error())
+ } else {
+ pc := color.ToPrecise()
+ switch color.(type) {
+ case colors.RGB:
+ sw.UpdatePicker(0, pc)
+ sw.SetActive(0)
+ case colors.CMYK:
+ sw.UpdatePicker(1, pc)
+ sw.SetActive(1)
+ case colors.HSL:
+ sw.UpdatePicker(2, pc)
+ sw.SetActive(2)
+ }
+ }
+ }
+
p := tea.NewProgram(sw)
if _, err := p.Run(); err != nil {
return err
@@ -36,7 +62,7 @@ func AppAction(ctx *cli.Context) error {
func main() {
app := &cli.App{
- Name: "TermPicker",
+ Name: "Termpicker",
Usage: "A terminal-based color picker",
Action: AppAction,
Flags: AppFlags,