tangled
alpha
login
or
join now
desertthunder.dev
/
noteleaf
cli + tui to publish to leaflet (wip) & manage tasks, notes & watch/read lists ๐
charm
leaflet
readability
golang
29
fork
atom
overview
issues
2
pulls
pipelines
build: reorganize main
desertthunder.dev
5 months ago
f1b9a48d
d9ec13f0
+249
-205
5 changed files
expand all
collapse all
unified
split
cmd
cli
commands.go
main.go
codecov.yml
internal
ui
logo.go
ui_test.go
+225
cmd/cli/commands.go
···
1
1
+
package main
2
2
+
3
3
+
import (
4
4
+
"fmt"
5
5
+
"strings"
6
6
+
7
7
+
"github.com/spf13/cobra"
8
8
+
"github.com/stormlightlabs/noteleaf/cmd/handlers"
9
9
+
"github.com/stormlightlabs/noteleaf/internal/ui"
10
10
+
)
11
11
+
12
12
+
func rootCmd() *cobra.Command {
13
13
+
return &cobra.Command{
14
14
+
Use: "noteleaf",
15
15
+
Long: ui.Colossal.ColoredInViewport(),
16
16
+
Short: "A TaskWarrior-inspired CLI with notes, media queues and reading lists",
17
17
+
Run: func(cmd *cobra.Command, args []string) {
18
18
+
if len(args) == 0 {
19
19
+
cmd.Help()
20
20
+
} else {
21
21
+
output := strings.Join(args, " ")
22
22
+
fmt.Println(output)
23
23
+
}
24
24
+
},
25
25
+
}
26
26
+
}
27
27
+
28
28
+
func todoCmd() *cobra.Command {
29
29
+
root := &cobra.Command{
30
30
+
Use: "todo",
31
31
+
Short: "task management",
32
32
+
}
33
33
+
34
34
+
root.AddCommand(&cobra.Command{
35
35
+
Use: "add [description]",
36
36
+
Short: "Add a new task",
37
37
+
Args: cobra.MinimumNArgs(1),
38
38
+
RunE: func(cmd *cobra.Command, args []string) error {
39
39
+
description := args[0]
40
40
+
fmt.Printf("Adding task: %s\n", description)
41
41
+
// TODO: Implement task creation
42
42
+
return nil
43
43
+
},
44
44
+
})
45
45
+
46
46
+
root.AddCommand(&cobra.Command{
47
47
+
Use: "list",
48
48
+
Short: "List tasks",
49
49
+
Aliases: []string{"ls"},
50
50
+
RunE: func(cmd *cobra.Command, args []string) error {
51
51
+
fmt.Println("Listing tasks...")
52
52
+
// TODO: Implement task listing
53
53
+
return nil
54
54
+
},
55
55
+
})
56
56
+
57
57
+
root.AddCommand(&cobra.Command{
58
58
+
Use: "done [task-id]",
59
59
+
Short: "Mark task as completed",
60
60
+
Args: cobra.ExactArgs(1),
61
61
+
RunE: func(cmd *cobra.Command, args []string) error {
62
62
+
taskID := args[0]
63
63
+
fmt.Printf("Marking task %s as done\n", taskID)
64
64
+
// TODO: Implement task completion
65
65
+
return nil
66
66
+
},
67
67
+
})
68
68
+
69
69
+
return root
70
70
+
}
71
71
+
72
72
+
func movieCmd() *cobra.Command {
73
73
+
root := &cobra.Command{
74
74
+
Use: "movie",
75
75
+
Short: "Manage movie watch queue",
76
76
+
}
77
77
+
78
78
+
root.AddCommand(&cobra.Command{
79
79
+
Use: "add [title]",
80
80
+
Short: "Add movie to watch queue",
81
81
+
Args: cobra.MinimumNArgs(1),
82
82
+
RunE: func(cmd *cobra.Command, args []string) error {
83
83
+
title := args[0]
84
84
+
fmt.Printf("Adding movie: %s\n", title)
85
85
+
// TODO: Implement movie addition
86
86
+
return nil
87
87
+
},
88
88
+
})
89
89
+
90
90
+
root.AddCommand(&cobra.Command{
91
91
+
Use: "list",
92
92
+
Short: "List movies in queue",
93
93
+
RunE: func(cmd *cobra.Command, args []string) error {
94
94
+
fmt.Println("Listing movies...")
95
95
+
// TODO: Implement movie listing
96
96
+
return nil
97
97
+
},
98
98
+
})
99
99
+
100
100
+
return root
101
101
+
}
102
102
+
103
103
+
func tvCmd() *cobra.Command {
104
104
+
root := &cobra.Command{
105
105
+
Use: "tv",
106
106
+
Short: "Manage TV show watch queue",
107
107
+
}
108
108
+
109
109
+
root.AddCommand(&cobra.Command{
110
110
+
Use: "add [title]",
111
111
+
Short: "Add TV show to watch queue",
112
112
+
Args: cobra.MinimumNArgs(1),
113
113
+
RunE: func(cmd *cobra.Command, args []string) error {
114
114
+
title := args[0]
115
115
+
fmt.Printf("Adding TV show: %s\n", title)
116
116
+
// TODO: Implement TV show addition
117
117
+
return nil
118
118
+
},
119
119
+
})
120
120
+
121
121
+
root.AddCommand(&cobra.Command{
122
122
+
Use: "list",
123
123
+
Short: "List TV shows in queue",
124
124
+
RunE: func(cmd *cobra.Command, args []string) error {
125
125
+
fmt.Println("Listing TV shows...")
126
126
+
// TODO: Implement TV show listing
127
127
+
return nil
128
128
+
},
129
129
+
})
130
130
+
131
131
+
return root
132
132
+
}
133
133
+
134
134
+
func bookCmd() *cobra.Command {
135
135
+
root := &cobra.Command{
136
136
+
Use: "book",
137
137
+
Short: "Manage reading list",
138
138
+
}
139
139
+
140
140
+
root.AddCommand(&cobra.Command{
141
141
+
Use: "add [title]",
142
142
+
Short: "Add book to reading list",
143
143
+
Args: cobra.MinimumNArgs(1),
144
144
+
RunE: func(cmd *cobra.Command, args []string) error {
145
145
+
title := args[0]
146
146
+
fmt.Printf("Adding book: %s\n", title)
147
147
+
// TODO: Implement book addition
148
148
+
return nil
149
149
+
},
150
150
+
})
151
151
+
152
152
+
root.AddCommand(&cobra.Command{
153
153
+
Use: "list",
154
154
+
Short: "List books in reading list",
155
155
+
RunE: func(cmd *cobra.Command, args []string) error {
156
156
+
fmt.Println("Listing books...")
157
157
+
// TODO: Implement book listing
158
158
+
return nil
159
159
+
},
160
160
+
})
161
161
+
162
162
+
return root
163
163
+
}
164
164
+
165
165
+
func noteCmd() *cobra.Command {
166
166
+
root := &cobra.Command{
167
167
+
Use: "note",
168
168
+
Short: "Manage notes",
169
169
+
}
170
170
+
171
171
+
root.AddCommand(&cobra.Command{
172
172
+
Use: "create [title] [content...]",
173
173
+
Short: "Create a new note",
174
174
+
Aliases: []string{"new"},
175
175
+
RunE: func(cmd *cobra.Command, args []string) error {
176
176
+
return handlers.Create(cmd.Context(), args)
177
177
+
},
178
178
+
})
179
179
+
180
180
+
return root
181
181
+
}
182
182
+
183
183
+
func statusCmd() *cobra.Command {
184
184
+
return &cobra.Command{
185
185
+
Use: "status",
186
186
+
Short: "Show application status and configuration",
187
187
+
RunE: func(cmd *cobra.Command, args []string) error {
188
188
+
return handlers.Status(cmd.Context(), args)
189
189
+
},
190
190
+
}
191
191
+
}
192
192
+
193
193
+
func resetCmd() *cobra.Command {
194
194
+
return &cobra.Command{
195
195
+
Use: "reset",
196
196
+
Short: "Reset the application (removes all data)",
197
197
+
RunE: func(cmd *cobra.Command, args []string) error {
198
198
+
return handlers.Reset(cmd.Context(), args)
199
199
+
},
200
200
+
}
201
201
+
}
202
202
+
203
203
+
func setupCmd() *cobra.Command {
204
204
+
return &cobra.Command{
205
205
+
Use: "setup",
206
206
+
Short: "Initialize the application database and configuration",
207
207
+
RunE: func(cmd *cobra.Command, args []string) error {
208
208
+
return handlers.Setup(cmd.Context(), args)
209
209
+
},
210
210
+
}
211
211
+
}
212
212
+
213
213
+
func confCmd() *cobra.Command {
214
214
+
return &cobra.Command{
215
215
+
Use: "config [key] [value]",
216
216
+
Short: "Manage configuration",
217
217
+
Args: cobra.ExactArgs(2),
218
218
+
RunE: func(cmd *cobra.Command, args []string) error {
219
219
+
key, value := args[0], args[1]
220
220
+
fmt.Printf("Setting config %s = %s\n", key, value)
221
221
+
// TODO: Implement config management
222
222
+
return nil
223
223
+
},
224
224
+
}
225
225
+
}
+15
-193
cmd/cli/main.go
···
4
4
"context"
5
5
"fmt"
6
6
"os"
7
7
-
"strings"
8
7
9
8
"github.com/charmbracelet/fang"
10
9
"github.com/spf13/cobra"
11
11
-
"github.com/stormlightlabs/noteleaf/cmd/handlers"
12
10
"github.com/stormlightlabs/noteleaf/internal/store"
13
11
"github.com/stormlightlabs/noteleaf/internal/ui"
14
12
"github.com/stormlightlabs/noteleaf/internal/utils"
···
27
25
return nil, fmt.Errorf("failed to initialize database: %w", err)
28
26
}
29
27
30
30
-
config, err := store.LoadConfig()
31
31
-
if err != nil {
28
28
+
if config, err := store.LoadConfig(); err != nil {
32
29
return nil, fmt.Errorf("failed to load configuration: %w", err)
30
30
+
} else {
31
31
+
return &App{db: db, config: config}, nil
33
32
}
34
34
-
35
35
-
return &App{
36
36
-
db: db,
37
37
-
config: config,
38
38
-
}, nil
39
33
}
40
34
41
35
// Close cleans up application resources
···
56
50
}
57
51
defer app.Close()
58
52
59
59
-
rootCmd := &cobra.Command{
60
60
-
Use: "noteleaf",
61
61
-
Short: "A TaskWarrior-inspired CLI with media queues and reading lists",
62
62
-
Run: func(cmd *cobra.Command, args []string) {
63
63
-
if len(args) == 0 {
64
64
-
fmt.Println(ui.Collosal.ColoredInViewport())
65
65
-
cmd.Help()
66
66
-
return
67
67
-
}
68
68
-
69
69
-
output := strings.Join(args, " ")
70
70
-
fmt.Println(output)
71
71
-
},
72
72
-
}
73
73
-
74
74
-
rootCmd.AddCommand(&cobra.Command{
75
75
-
Use: "setup",
76
76
-
Short: "Initialize the application database and configuration",
77
77
-
RunE: func(cmd *cobra.Command, args []string) error {
78
78
-
return handlers.Setup(cmd.Context(), args)
79
79
-
},
80
80
-
})
81
81
-
82
82
-
rootCmd.AddCommand(&cobra.Command{
83
83
-
Use: "reset",
84
84
-
Short: "Reset the application (removes all data)",
85
85
-
RunE: func(cmd *cobra.Command, args []string) error {
86
86
-
return handlers.Reset(cmd.Context(), args)
87
87
-
},
88
88
-
})
89
89
-
90
90
-
rootCmd.AddCommand(&cobra.Command{
91
91
-
Use: "status",
92
92
-
Short: "Show application status and configuration",
93
93
-
RunE: func(cmd *cobra.Command, args []string) error {
94
94
-
return handlers.Status(cmd.Context(), args)
95
95
-
},
96
96
-
})
97
97
-
98
98
-
rootCmd.AddCommand(&cobra.Command{
99
99
-
Use: "add [description]",
100
100
-
Short: "Add a new task",
101
101
-
Args: cobra.MinimumNArgs(1),
102
102
-
RunE: func(cmd *cobra.Command, args []string) error {
103
103
-
description := args[0]
104
104
-
fmt.Printf("Adding task: %s\n", description)
105
105
-
// TODO: Implement task creation
106
106
-
return nil
107
107
-
},
108
108
-
})
109
109
-
110
110
-
rootCmd.AddCommand(&cobra.Command{
111
111
-
Use: "list",
112
112
-
Short: "List tasks",
113
113
-
Aliases: []string{"ls"},
114
114
-
RunE: func(cmd *cobra.Command, args []string) error {
115
115
-
fmt.Println("Listing tasks...")
116
116
-
// TODO: Implement task listing
117
117
-
return nil
118
118
-
},
119
119
-
})
120
120
-
121
121
-
rootCmd.AddCommand(&cobra.Command{
122
122
-
Use: "done [task-id]",
123
123
-
Short: "Mark task as completed",
124
124
-
Args: cobra.ExactArgs(1),
125
125
-
RunE: func(cmd *cobra.Command, args []string) error {
126
126
-
taskID := args[0]
127
127
-
fmt.Printf("Marking task %s as done\n", taskID)
128
128
-
// TODO: Implement task completion
129
129
-
return nil
130
130
-
},
131
131
-
})
132
132
-
133
133
-
movieCmd := &cobra.Command{
134
134
-
Use: "movie",
135
135
-
Short: "Manage movie watch queue",
136
136
-
}
137
137
-
138
138
-
movieCmd.AddCommand(&cobra.Command{
139
139
-
Use: "add [title]",
140
140
-
Short: "Add movie to watch queue",
141
141
-
Args: cobra.MinimumNArgs(1),
142
142
-
RunE: func(cmd *cobra.Command, args []string) error {
143
143
-
title := args[0]
144
144
-
fmt.Printf("Adding movie: %s\n", title)
145
145
-
// TODO: Implement movie addition
146
146
-
return nil
147
147
-
},
148
148
-
})
149
149
-
150
150
-
movieCmd.AddCommand(&cobra.Command{
151
151
-
Use: "list",
152
152
-
Short: "List movies in queue",
153
153
-
RunE: func(cmd *cobra.Command, args []string) error {
154
154
-
fmt.Println("Listing movies...")
155
155
-
// TODO: Implement movie listing
156
156
-
return nil
157
157
-
},
158
158
-
})
159
159
-
160
160
-
rootCmd.AddCommand(movieCmd)
161
161
-
162
162
-
tvCmd := &cobra.Command{
163
163
-
Use: "tv",
164
164
-
Short: "Manage TV show watch queue",
53
53
+
root := rootCmd()
54
54
+
commands := []func() *cobra.Command{
55
55
+
setupCmd, resetCmd, statusCmd, todoCmd,
56
56
+
movieCmd, noteCmd, tvCmd, bookCmd, confCmd,
165
57
}
166
58
167
167
-
tvCmd.AddCommand(&cobra.Command{
168
168
-
Use: "add [title]",
169
169
-
Short: "Add TV show to watch queue",
170
170
-
Args: cobra.MinimumNArgs(1),
171
171
-
RunE: func(cmd *cobra.Command, args []string) error {
172
172
-
title := args[0]
173
173
-
fmt.Printf("Adding TV show: %s\n", title)
174
174
-
// TODO: Implement TV show addition
175
175
-
return nil
176
176
-
},
177
177
-
})
178
178
-
179
179
-
tvCmd.AddCommand(&cobra.Command{
180
180
-
Use: "list",
181
181
-
Short: "List TV shows in queue",
182
182
-
RunE: func(cmd *cobra.Command, args []string) error {
183
183
-
fmt.Println("Listing TV shows...")
184
184
-
// TODO: Implement TV show listing
185
185
-
return nil
186
186
-
},
187
187
-
})
188
188
-
189
189
-
rootCmd.AddCommand(tvCmd)
190
190
-
191
191
-
bookCmd := &cobra.Command{
192
192
-
Use: "book",
193
193
-
Short: "Manage reading list",
59
59
+
for _, cmdFunc := range commands {
60
60
+
cmd := cmdFunc()
61
61
+
root.AddCommand(cmd)
194
62
}
195
63
196
196
-
bookCmd.AddCommand(&cobra.Command{
197
197
-
Use: "add [title]",
198
198
-
Short: "Add book to reading list",
199
199
-
Args: cobra.MinimumNArgs(1),
200
200
-
RunE: func(cmd *cobra.Command, args []string) error {
201
201
-
title := args[0]
202
202
-
fmt.Printf("Adding book: %s\n", title)
203
203
-
// TODO: Implement book addition
204
204
-
return nil
205
205
-
},
206
206
-
})
207
207
-
208
208
-
bookCmd.AddCommand(&cobra.Command{
209
209
-
Use: "list",
210
210
-
Short: "List books in reading list",
211
211
-
RunE: func(cmd *cobra.Command, args []string) error {
212
212
-
fmt.Println("Listing books...")
213
213
-
// TODO: Implement book listing
214
214
-
return nil
215
215
-
},
216
216
-
})
217
217
-
218
218
-
rootCmd.AddCommand(bookCmd)
219
219
-
220
220
-
noteCmd := &cobra.Command{
221
221
-
Use: "note",
222
222
-
Short: "Manage notes",
64
64
+
options := []fang.Option{
65
65
+
fang.WithVersion("0.1.0"),
66
66
+
fang.WithoutCompletions(),
67
67
+
fang.WithColorSchemeFunc(ui.NoteleafColorScheme),
223
68
}
224
69
225
225
-
noteCmd.AddCommand(&cobra.Command{
226
226
-
Use: "create [title] [content...]",
227
227
-
Short: "Create a new note",
228
228
-
Aliases: []string{"new"},
229
229
-
RunE: func(cmd *cobra.Command, args []string) error {
230
230
-
return handlers.Create(cmd.Context(), args)
231
231
-
},
232
232
-
})
233
233
-
234
234
-
rootCmd.AddCommand(noteCmd)
235
235
-
236
236
-
rootCmd.AddCommand(&cobra.Command{
237
237
-
Use: "config [key] [value]",
238
238
-
Short: "Manage configuration",
239
239
-
Args: cobra.ExactArgs(2),
240
240
-
RunE: func(cmd *cobra.Command, args []string) error {
241
241
-
key, value := args[0], args[1]
242
242
-
fmt.Printf("Setting config %s = %s\n", key, value)
243
243
-
// TODO: Implement config management
244
244
-
return nil
245
245
-
},
246
246
-
})
247
247
-
248
248
-
if err := fang.Execute(context.Background(), rootCmd, fang.WithVersion("0.1.0")); err != nil {
70
70
+
if err := fang.Execute(context.Background(), root, options...); err != nil {
249
71
os.Exit(1)
250
72
}
251
73
}
+1
-1
codecov.yml
···
20
20
- "**/*_test.go"
21
21
- "**/testdata/**"
22
22
- "**/vendor/**"
23
23
-
- "cmd/cli/main.go" # Main entry point typically has minimal logic to test
23
23
+
- "cmd/cli/*.go"
+6
-9
internal/ui/logo.go
···
12
12
type Logo int
13
13
14
14
const (
15
15
-
Collosal Logo = iota
15
15
+
Colossal Logo = iota
16
16
Georgia
17
17
Alligator
18
18
ANSI
19
19
ANSIShadow
20
20
)
21
21
22
22
-
const collosal string = `
22
22
+
const colossal string = `
23
23
888b 888 888 888 .d888
24
24
8888b 888 888 888 d88P"
25
25
88888b 888 888 888 888
···
62
62
63
63
func (l Logo) String() string {
64
64
switch l {
65
65
-
case Collosal:
66
66
-
return collosal
65
65
+
case Colossal:
66
66
+
return colossal
67
67
case Georgia:
68
68
return georgia
69
69
case Alligator:
···
73
73
case ANSIShadow:
74
74
return ansiShadow
75
75
default:
76
76
-
return collosal
76
76
+
return colossal
77
77
}
78
78
}
79
79
···
130
130
vp := viewport.New(maxWidth+4, len(lines))
131
131
vp.SetContent(coloredLogo)
132
132
133
133
-
style := lipgloss.NewStyle().
134
134
-
Border(lipgloss.RoundedBorder()).
135
135
-
BorderForeground(lipgloss.Color("#6b7280")).
136
136
-
Padding(1)
133
133
+
style := lipgloss.NewStyle().Border(lipgloss.RoundedBorder()).BorderForeground(lipgloss.Color("#6b7280")).PaddingLeft(1)
137
134
138
135
if len(renderer) > 0 && renderer[0] != nil {
139
136
style = style.Renderer(renderer[0])
+2
-2
internal/ui/ui_test.go
···
270
270
name string
271
271
contains string
272
272
}{
273
273
-
{Collosal, "Collosal", "888b 888"},
273
273
+
{Colossal, "Collosal", "888b 888"},
274
274
{Georgia, "Georgia", "`7MN. `7MF'"},
275
275
{Alligator, "Alligator", ":::: ::: ::::::::"},
276
276
{ANSI, "ANSI", "โโโ โโ"},
···
308
308
309
309
t.Run("Colored in Viewport", func(t *testing.T) {
310
310
withColor(t, func(r *lipgloss.Renderer) {
311
311
-
logo := Collosal
311
311
+
logo := Colossal
312
312
viewport := logo.ColoredInViewport(r)
313
313
t.Logf("viewport output:\n%s", viewport)
314
314