Skip to content

Commit e6853be

Browse files
authored
add notification on missing clipboard availablility (#50)
* add clipboard check, notification & additional key binding * update config stuff * clean up * add test * bump packages * update README * remove unneeded file
1 parent 91772d4 commit e6853be

File tree

9 files changed

+91
-154
lines changed

9 files changed

+91
-154
lines changed

README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,13 @@ Since v2.1.3 it is possible to pipe the password from stdin and skip the input q
3434
## Keys
3535

3636
```text
37-
↑/k up
38-
↓/j down
39-
/ filter
40-
enter show/hide token
41-
u show/hide usernames
42-
c copy
43-
q quit
37+
↑/k up
38+
↓/j down
39+
/ filter
40+
enter toggle token visibility
41+
u toggle usernames visibility
42+
c/y yank token to system clipboard
43+
q quit
4444
```
4545

4646
## Clipboard config

go.mod

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,32 @@
11
module github.com/tjblackheart/andcli/v2
22

3-
go 1.24
3+
go 1.25
44

55
require (
66
github.com/ProtonMail/gopenpgp/v3 v3.3.0
77
github.com/charmbracelet/bubbles v0.21.0
8-
github.com/charmbracelet/bubbletea v1.3.6
8+
github.com/charmbracelet/bubbletea v1.3.8
99
github.com/charmbracelet/lipgloss v1.1.0
1010
github.com/goccy/go-yaml v1.18.0
1111
github.com/grijul/go-andotp v1.0.23
12-
github.com/spf13/pflag v1.0.7
12+
github.com/spf13/pflag v1.0.10
1313
github.com/tobischo/gokeepasslib/v3 v3.6.1
1414
github.com/xlzd/gotp v0.1.0
15-
golang.org/x/crypto v0.40.0
16-
golang.org/x/term v0.33.0
15+
golang.org/x/crypto v0.42.0
16+
golang.org/x/term v0.35.0
1717
)
1818

1919
require (
2020
github.com/ProtonMail/go-crypto v1.3.0 // indirect
2121
github.com/atotto/clipboard v0.1.4 // indirect
2222
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
23-
github.com/charmbracelet/colorprofile v0.3.1 // indirect
24-
github.com/charmbracelet/x/ansi v0.9.3 // indirect
23+
github.com/charmbracelet/colorprofile v0.3.2 // indirect
24+
github.com/charmbracelet/x/ansi v0.10.1 // indirect
2525
github.com/charmbracelet/x/cellbuf v0.0.13 // indirect
2626
github.com/charmbracelet/x/term v0.2.1 // indirect
2727
github.com/cloudflare/circl v1.6.1 // indirect
2828
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
29-
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
29+
github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
3030
github.com/mattn/go-isatty v0.0.20 // indirect
3131
github.com/mattn/go-localereader v0.0.1 // indirect
3232
github.com/mattn/go-runewidth v0.0.16 // indirect
@@ -37,7 +37,7 @@ require (
3737
github.com/sahilm/fuzzy v0.1.1 // indirect
3838
github.com/tobischo/argon2 v0.1.0 // indirect
3939
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
40-
golang.org/x/sync v0.16.0 // indirect
41-
golang.org/x/sys v0.34.0 // indirect
42-
golang.org/x/text v0.27.0 // indirect
40+
golang.org/x/sync v0.17.0 // indirect
41+
golang.org/x/sys v0.36.0 // indirect
42+
golang.org/x/text v0.29.0 // indirect
4343
)

go.sum

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,18 @@ github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u
1212
github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg=
1313
github.com/charmbracelet/bubbletea v1.3.6 h1:VkHIxPJQeDt0aFJIsVxw8BQdh/F/L2KKZGsK6et5taU=
1414
github.com/charmbracelet/bubbletea v1.3.6/go.mod h1:oQD9VCRQFF8KplacJLo28/jofOI2ToOfGYeFgBBxHOc=
15+
github.com/charmbracelet/bubbletea v1.3.8 h1:DJlh6UUPhobzomqCtnLJRmhBSxwUJoPPi6iCToUDr4g=
16+
github.com/charmbracelet/bubbletea v1.3.8/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4=
1517
github.com/charmbracelet/colorprofile v0.3.1 h1:k8dTHMd7fgw4bnFd7jXTLZrSU/CQrKnL3m+AxCzDz40=
1618
github.com/charmbracelet/colorprofile v0.3.1/go.mod h1:/GkGusxNs8VB/RSOh3fu0TJmQ4ICMMPApIIVn0KszZ0=
19+
github.com/charmbracelet/colorprofile v0.3.2 h1:9J27WdztfJQVAQKX2WOlSSRB+5gaKqqITmrvb1uTIiI=
20+
github.com/charmbracelet/colorprofile v0.3.2/go.mod h1:mTD5XzNeWHj8oqHb+S1bssQb7vIHbepiebQ2kPKVKbI=
1721
github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
1822
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
1923
github.com/charmbracelet/x/ansi v0.9.3 h1:BXt5DHS/MKF+LjuK4huWrC6NCvHtexww7dMayh6GXd0=
2024
github.com/charmbracelet/x/ansi v0.9.3/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE=
25+
github.com/charmbracelet/x/ansi v0.10.1 h1:rL3Koar5XvX0pHGfovN03f5cxLbCF2YvLeyz7D2jVDQ=
26+
github.com/charmbracelet/x/ansi v0.10.1/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE=
2127
github.com/charmbracelet/x/cellbuf v0.0.13 h1:/KBBKHuVRbq1lYx5BzEHBAFBP8VcQzJejZ/IA3iR28k=
2228
github.com/charmbracelet/x/cellbuf v0.0.13/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
2329
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ=
@@ -40,6 +46,8 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0
4046
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
4147
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
4248
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
49+
github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag=
50+
github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
4351
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
4452
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
4553
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
@@ -61,6 +69,8 @@ github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA=
6169
github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
6270
github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M=
6371
github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
72+
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
73+
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
6474
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
6575
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
6676
github.com/tobischo/argon2 v0.1.0 h1:mwAx/9DK/4rP0xzNifb/XMAf43dU3eG1B3aeF88qu4Y=
@@ -74,24 +84,34 @@ github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJu
7484
golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
7585
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
7686
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
87+
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
88+
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
7789
golang.org/x/exp v0.0.0-20230105202349-8879d0199aa3 h1:fJwx88sMf5RXwDwziL0/Mn9Wqs+efMSo/RYcL+37W9c=
7890
golang.org/x/exp v0.0.0-20230105202349-8879d0199aa3/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
7991
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
8092
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
8193
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
94+
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
95+
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
8296
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
8397
golang.org/x/sys v0.0.0-20210601080250-7ecdf8ef093b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
8498
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
8599
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
86100
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
87101
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
102+
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
103+
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
88104
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
89105
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
90106
golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg=
91107
golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0=
108+
golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ=
109+
golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
92110
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
93111
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
94112
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
113+
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
114+
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
95115
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
96116
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
97117
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

internal/config/config.go

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,16 @@ type (
3333
// plus given flags into a current app config. Missing dirs apart
3434
// from the default system config directory will be created in the process.
3535
func Create() (*Config, error) {
36-
37-
userDir, err := os.UserConfigDir()
36+
dir, err := os.UserConfigDir()
3837
if err != nil {
39-
return nil, fmt.Errorf("can not read directory: %s", err)
38+
return nil, fmt.Errorf("unable to read user directory: %s", err)
4039
}
41-
42-
return create(userDir)
40+
return create(dir)
4341
}
4442

4543
func create(dir string) (*Config, error) {
46-
path, err := createDirectories(filepath.Join(dir, buildinfo.AppName))
47-
if err != nil {
44+
path := filepath.Join(dir, buildinfo.AppName)
45+
if err := os.MkdirAll(path, os.ModePerm); err != nil {
4846
return nil, err
4947
}
5048

@@ -151,14 +149,3 @@ func (c *Config) validate() error {
151149

152150
return nil
153151
}
154-
155-
func createDirectories(path string) (string, error) {
156-
157-
if _, err := os.Stat(path); os.IsNotExist(err) {
158-
if err := os.MkdirAll(path, os.ModePerm); err != nil {
159-
return "", err
160-
}
161-
}
162-
163-
return path, nil
164-
}

internal/config/config_test.go

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -11,36 +11,6 @@ import (
1111
"github.com/tjblackheart/andcli/v2/internal/buildinfo"
1212
)
1313

14-
func Test_createDirectories(t *testing.T) {
15-
wantDir := filepath.Join(os.TempDir(), "andcli_test", "config", buildinfo.AppName)
16-
17-
tests := []struct {
18-
name string
19-
dir string
20-
fails bool
21-
}{
22-
{"creates directories", wantDir, false},
23-
}
24-
25-
for _, tt := range tests {
26-
t.Run(tt.name, func(t *testing.T) {
27-
got, err := createDirectories(tt.dir)
28-
if (err != nil) != tt.fails {
29-
t.Errorf("createDirectories() error = %v, wantErr %v", err, tt.fails)
30-
return
31-
}
32-
33-
if _, err := os.Stat(tt.dir); err != nil {
34-
t.Errorf("createDirectories() = %v, want %v", got, tt.dir)
35-
}
36-
37-
if err := os.RemoveAll(tt.dir); err != nil {
38-
t.Error(err)
39-
}
40-
})
41-
}
42-
}
43-
4414
func TestConfig_mergeExisting(t *testing.T) {
4515
path := filepath.Join(os.TempDir(), "andcli_test_config.yaml")
4616

internal/model/model.go

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -33,30 +33,28 @@ type (
3333
)
3434

3535
var (
36-
style *defaultStyle
37-
state *appState
38-
cb *clipboard.Clipboard
36+
style = newDefaultStyle()
37+
state = new(appState)
38+
cb = new(clipboard.Clipboard)
39+
copyOK = ns().Foreground(green).Render("✓")
40+
copyErr = ns().Foreground(red).Render("✕")
3941
)
4042

4143
func New(entries []vaults.Entry, cfg *config.Config) Model {
44+
state.showToken = cfg.Options.ShowTokens
45+
state.showUsernames = cfg.Options.ShowUsernames
46+
4247
items := make([]list.Item, 0)
4348
for _, e := range entries {
4449
items = append(items, e)
4550
}
4651

4752
cb = clipboard.New(cfg.ClipboardCmd)
48-
state = &appState{
49-
showToken: cfg.Options.ShowTokens,
50-
showUsernames: cfg.Options.ShowUsernames,
51-
}
52-
style = newDefaultStyle()
5353
title := fmt.Sprintf("%s: %s", buildinfo.AppName, filepath.Base(cfg.File))
54-
5554
keys := initKeys()
56-
d := &itemDelegate{style}
57-
list := initList(items, d, keys, title)
55+
dlg := &itemDelegate{style}
5856

59-
return Model{list: list}
57+
return Model{list: initList(items, dlg, keys, title)}
6058
}
6159

6260
func (m Model) Init() tea.Cmd {
@@ -78,16 +76,16 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
7876
state.showToken = !state.showToken
7977
case "u":
8078
state.showUsernames = !state.showUsernames
81-
case "c":
79+
case "c", "y":
8280
if !cb.IsInitialized() {
83-
break
81+
msg := fmt.Sprintf("%s No clipboard command available", copyErr)
82+
return m, m.list.NewStatusMessage(msg)
8483
}
8584

86-
msg := "Token copied to clipboard"
85+
msg := fmt.Sprintf("%s Token copied to clipboard", copyOK)
8786
if err := cb.Set([]byte(state.currentOTP)); err != nil {
88-
msg = fmt.Sprintf("%s: %s", cb.String(), err)
87+
msg = fmt.Sprintf("%s %s: %s", copyErr, cb.String(), err)
8988
}
90-
9189
return m, m.list.NewStatusMessage(msg)
9290
}
9391

@@ -115,16 +113,11 @@ func tick() tea.Cmd {
115113
}
116114

117115
func initKeys() []key.Binding {
118-
keys := []key.Binding{
119-
key.NewBinding(key.WithKeys("enter"), key.WithHelp("enter", "show/hide token")),
120-
key.NewBinding(key.WithKeys("u"), key.WithHelp("u", "show/hide usernames")),
116+
return []key.Binding{
117+
key.NewBinding(key.WithKeys("enter"), key.WithHelp("enter", "toggle token")),
118+
key.NewBinding(key.WithKeys("u"), key.WithHelp("u", "toggle usernames")),
119+
key.NewBinding(key.WithKeys("c", "y"), key.WithHelp("c/y", "yank to clipboard")),
121120
}
122-
123-
if cb != nil && cb.IsInitialized() {
124-
keys = append(keys, key.NewBinding(key.WithKeys("c"), key.WithHelp("c", "copy")))
125-
}
126-
127-
return keys
128121
}
129122

130123
func initList(i []list.Item, d *itemDelegate, k []key.Binding, title string) list.Model {

internal/model/model_test.go

Lines changed: 0 additions & 48 deletions
This file was deleted.

internal/model/style.go

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,26 +23,19 @@ var ns = lipgloss.NewStyle
2323

2424
func newDefaultStyle() *defaultStyle {
2525
return &defaultStyle{
26-
title: ns().Background(base).Padding(0, 1),
27-
28-
listItem: ns().PaddingLeft(2).Faint(true),
29-
26+
title: ns().Background(base).Padding(0, 1),
27+
listItem: ns().PaddingLeft(2).Faint(true),
28+
username: ns().Background(grey),
29+
filterPrompt: ns().Foreground(base),
30+
filterCursor: ns().Background(base),
31+
token: ns().Bold(true).Padding(0, 1, 0, 1),
32+
until: ns().Bold(true),
3033
activeItem: ns().
3134
Padding(0, 1).
3235
Bold(true).
3336
Background(grey).
3437
Border(lipgloss.ThickBorder(), false, false, false, true).
3538
BorderForeground(base).
3639
Faint(false),
37-
38-
username: ns().Background(grey),
39-
40-
filterPrompt: ns().Foreground(base),
41-
42-
filterCursor: ns().Background(base),
43-
44-
token: ns().Bold(true).Padding(0, 1, 0, 1),
45-
46-
until: ns().Bold(true),
4740
}
4841
}

0 commit comments

Comments
 (0)