diff options
Diffstat (limited to 'internal')
-rw-r--r-- | internal/parse/userinput.go (renamed from internal/userinput/userinput.go) | 20 | ||||
-rw-r--r-- | internal/picker/keys.go | 4 | ||||
-rw-r--r-- | internal/switcher/keys.go | 54 | ||||
-rw-r--r-- | internal/switcher/misc.go | 54 | ||||
-rw-r--r-- | internal/switcher/switcher.go | 79 |
5 files changed, 154 insertions, 57 deletions
diff --git a/internal/userinput/userinput.go b/internal/parse/userinput.go index 8f1ecdc..d61a185 100644 --- a/internal/userinput/userinput.go +++ b/internal/parse/userinput.go @@ -1,4 +1,4 @@ -package userinput +package parse import ( "errors" @@ -25,23 +25,23 @@ func sanitize(s string) string { return s } -func ParseColor(s string) (colors.ColorSpace, error) { +func Color(s string) (colors.ColorSpace, error) { s = sanitize(s) switch { case strings.Contains(s, "#"): - return parseHex(s) + return hex(s) case strings.Contains(s, "rgb"): - return parseRGB(s) + return rgb(s) case strings.Contains(s, "hsl"): - return parseHSL(s) + return hsl(s) case strings.Contains(s, "cmyk"): - return parseCMYK(s) + return cmyk(s) default: return nil, errUnknownColorFormat } } -func parseRGB(s string) (colors.ColorSpace, error) { +func rgb(s string) (colors.ColorSpace, error) { var r, g, b int _, err := fmt.Sscanf(s, "rgb(%d,%d,%d)", &r, &g, &b) if err != nil { @@ -50,7 +50,7 @@ func parseRGB(s string) (colors.ColorSpace, error) { return colors.RGB{R: r, G: g, B: b}, nil } -func parseHex(s string) (colors.ColorSpace, error) { +func hex(s string) (colors.ColorSpace, error) { var r, g, b int _, err := fmt.Sscanf(s, "#%02x%02x%02x", &r, &g, &b) if err != nil { @@ -59,7 +59,7 @@ func parseHex(s string) (colors.ColorSpace, error) { return colors.RGB{R: r, G: g, B: b}, nil } -func parseCMYK(s string) (colors.ColorSpace, error) { +func cmyk(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 { @@ -68,7 +68,7 @@ func parseCMYK(s string) (colors.ColorSpace, error) { return colors.CMYK{C: c, M: m, Y: y, K: k}, nil } -func parseHSL(str string) (colors.ColorSpace, error) { +func hsl(str string) (colors.ColorSpace, error) { var h, s, l int _, err := fmt.Sscanf(str, "hsl(%d,%d,%d)", &h, &s, &l) if err != nil { diff --git a/internal/picker/keys.go b/internal/picker/keys.go index e219878..1b7b558 100644 --- a/internal/picker/keys.go +++ b/internal/picker/keys.go @@ -1,6 +1,8 @@ package picker -import "github.com/charmbracelet/bubbles/key" +import ( + "github.com/charmbracelet/bubbles/key" +) type keybinds struct { next, prev key.Binding diff --git a/internal/switcher/keys.go b/internal/switcher/keys.go index 215a8e2..73ba710 100644 --- a/internal/switcher/keys.go +++ b/internal/switcher/keys.go @@ -1,9 +1,20 @@ package switcher -import "github.com/charmbracelet/bubbles/key" +import ( + "strings" + + "github.com/charmbracelet/bubbles/key" +) + +const ( + cpHex = "x" + cpRGB = "r" + cpHSL = "s" + cpCMYK = "c" +) type keybinds struct { - next, prev, cpHex, cpRgb, cpHsl, cpCmyk, help, quit key.Binding + next, prev, copy, help, insert, esc, confirm, quit key.Binding } func newKeybinds() keybinds { @@ -14,28 +25,33 @@ func newKeybinds() keybinds { ), prev: key.NewBinding( key.WithKeys("shift+tab"), - key.WithHelp("shift+tab", "prev. picker"), - ), - cpHex: key.NewBinding( - key.WithKeys("x"), - key.WithHelp("x", "copy hex"), - ), - cpRgb: key.NewBinding( - key.WithKeys("r"), - key.WithHelp("r", "copy rgb"), + key.WithHelp("shift+tab", "prev picker"), ), - cpHsl: key.NewBinding( - key.WithKeys("s"), - key.WithHelp("s", "copy hsl"), - ), - cpCmyk: key.NewBinding( - key.WithKeys("c"), - key.WithHelp("c", "copy cmyk"), + copy: key.NewBinding( + key.WithKeys(cpHex, cpRGB, cpHSL, cpCMYK), + key.WithHelp( + strings.Join([]string{cpHex, cpRGB, cpHSL, cpCMYK}, "/"), + "copy color", + ), ), help: key.NewBinding( key.WithKeys("?"), key.WithHelp("?", "help"), ), + insert: key.NewBinding( + key.WithKeys("i", ":"), + key.WithHelp("i", "manual input"), + ), + esc: key.NewBinding( + key.WithKeys("esc"), + key.WithHelp("esc", "exit manual input"), + key.WithDisabled(), + ), + confirm: key.NewBinding( + key.WithKeys("enter"), + key.WithHelp("enter", "confirm manual input"), + key.WithDisabled(), + ), quit: key.NewBinding( key.WithKeys("q", "ctrl+c"), key.WithHelp("q", "quit"), @@ -45,7 +61,7 @@ func newKeybinds() keybinds { func Keys() []key.Binding { k := newKeybinds() - return []key.Binding{k.next, k.prev, k.cpHex, k.cpRgb, k.cpHsl, k.cpCmyk, k.help, k.quit} + return []key.Binding{k.next, k.prev, k.copy, k.insert, k.esc, k.confirm, k.help, k.quit} } func shortKeys() [][]key.Binding { diff --git a/internal/switcher/misc.go b/internal/switcher/misc.go new file mode 100644 index 0000000..e87f219 --- /dev/null +++ b/internal/switcher/misc.go @@ -0,0 +1,54 @@ +package switcher + +import ( + "log/slog" + + "github.com/ChausseBenjamin/termpicker/internal/colors" + "github.com/ChausseBenjamin/termpicker/internal/parse" + "github.com/ChausseBenjamin/termpicker/internal/util" +) + +const ( + okCpMsg = "Copied %s to clipboard as %s" +) + +func (m Model) copyColor(format string) string { + pc := m.pickers[m.active].GetColor().ToPrecise() + switch format { + case cpHex: + return util.Copy(colors.Hex(m.pickers[m.active].GetColor())) + case cpRGB: + rgb := colors.RGB{}.FromPrecise(pc).(colors.RGB) + return util.Copy(rgb.String()) + case cpHSL: + hsl := colors.HSL{}.FromPrecise(pc).(colors.HSL) + return util.Copy(hsl.String()) + case cpCMYK: + cmyk := colors.CMYK{}.FromPrecise(pc).(colors.CMYK) + return util.Copy(cmyk.String()) + default: + return "Copy format not supported" + } +} + +func (m *Model) SetColorFromText(colorStr string) string { + color, err := parse.Color(colorStr) + if err != nil { + slog.Error("Failed to parse color", util.ErrKey, err) + return err.Error() + } else { + pc := color.ToPrecise() + switch color.(type) { + case colors.RGB: + m.UpdatePicker(IndexRgb, pc) + m.SetActive(IndexRgb) + case colors.CMYK: + m.UpdatePicker(IndexCmyk, pc) + m.SetActive(IndexCmyk) + case colors.HSL: + m.UpdatePicker(IndexHsl, pc) + m.SetActive(IndexHsl) + } + return "Color set to " + colorStr + } +} diff --git a/internal/switcher/switcher.go b/internal/switcher/switcher.go index 860bf81..74f0d6b 100644 --- a/internal/switcher/switcher.go +++ b/internal/switcher/switcher.go @@ -9,30 +9,43 @@ import ( "github.com/ChausseBenjamin/termpicker/internal/picker" "github.com/ChausseBenjamin/termpicker/internal/preview" "github.com/ChausseBenjamin/termpicker/internal/quit" - "github.com/ChausseBenjamin/termpicker/internal/util" "github.com/charmbracelet/bubbles/help" "github.com/charmbracelet/bubbles/key" + "github.com/charmbracelet/bubbles/textinput" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" ) +const ( + IndexRgb int = iota + IndexCmyk + IndexHsl +) + type Model struct { active int pickers []picker.Model preview preview.Model help help.Model - fullHelp bool // When false, only show help for the switcher (not children) + input textinput.Model notices notices.Model + fullHelp bool // When false, only show help for the switcher (not children) } -func New(pickers []picker.Model) Model { +func New() Model { + pickers := []picker.Model{ // Order MUST match the Index* constants + *picker.RGB(), + *picker.CMYK(), + *picker.HSL(), + } return Model{ active: 0, pickers: pickers, preview: *preview.New(colors.Hex(pickers[0].GetColor())), help: help.New(), - fullHelp: false, + input: textinput.New(), notices: notices.New(), + fullHelp: false, } } @@ -110,14 +123,20 @@ func (m Model) View() string { // helpstr = m.help.FullHelpView([][]key.Binding{m.AllKeys()[0]}) helpstr = m.help.FullHelpView(shortKeys()) } - helpstr = boxStyle.Render(helpstr) - return fmt.Sprintf("%s\n%s\n%s\n%v\n%v", + inputStr := "" + if m.input.Focused() { + boxStyle = boxStyle.Border(lipgloss.RoundedBorder(), true, true, true, true).Width(w) + inputStr = boxStyle.Render(m.input.View()) + } + + return fmt.Sprintf("%s\n%s\n%s\n%v\n%v\n%v", tabs, pickerView, previewStr, helpstr, + inputStr, m.notices.View(), ) } @@ -131,7 +150,28 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { newNotices, cmd := m.notices.Update(msg) m.notices = newNotices.(notices.Model) cmds = append(cmds, cmd) + case tea.KeyMsg: + + if m.input.Focused() { + keys.esc.SetEnabled(true) + keys.confirm.SetEnabled(true) + if key.Matches(msg, keys.esc) { + m.input.Blur() + } else if key.Matches(msg, keys.confirm) { + m.input.Blur() + cmds = append( + cmds, + m.NewNotice(m.SetColorFromText(m.input.Value())), + m.Init(), // Will force a slider update/animation + ) + } + newInput, cmd := m.input.Update(msg) + m.input = newInput + cmds = append(cmds, cmd) + return m, tea.Batch(cmds...) + } + switch { case key.Matches(msg, keys.next): cs := m.pickers[m.active].GetColor() @@ -143,31 +183,17 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.Prev() m.pickers[m.active].SetColor(cs) - case key.Matches(msg, keys.cpHex): - cmd := m.notices.New(util.Copy(colors.Hex(m.pickers[m.active].GetColor()))) - cmds = append(cmds, cmd) - - case key.Matches(msg, keys.cpRgb): - pc := m.pickers[m.active].GetColor().ToPrecise() - rgb := colors.RGB{}.FromPrecise(pc).(colors.RGB) - cmd := m.notices.New(util.Copy(rgb.String())) - cmds = append(cmds, cmd) - - case key.Matches(msg, keys.cpHsl): - pc := m.pickers[m.active].GetColor().ToPrecise() - hsl := colors.HSL{}.FromPrecise(pc).(colors.HSL) - cmd := m.notices.New(util.Copy(hsl.String())) - cmds = append(cmds, cmd) - - case key.Matches(msg, keys.cpCmyk): - pc := m.pickers[m.active].GetColor().ToPrecise() - cmyk := colors.CMYK{}.FromPrecise(pc).(colors.CMYK) - cmd := m.notices.New(util.Copy(cmyk.String())) + case key.Matches(msg, keys.copy): + cmd := m.notices.New(m.copyColor(msg.String())) cmds = append(cmds, cmd) case key.Matches(msg, keys.help): m.fullHelp = !m.fullHelp + case key.Matches(msg, keys.insert): + cmd := m.input.Focus() + cmds = append(cmds, cmd) + case key.Matches(msg, keys.quit): return quit.Model{}, tea.Quit @@ -183,7 +209,6 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { newNotices, cmd := m.notices.Update(msg) m.notices = newNotices.(notices.Model) cmds = append(cmds, cmd) - return m, tea.Batch(cmds...) } default: |