cli + tui to publish to leaflet (wip) & manage tasks, notes & watch/read lists 馃崈
charm leaflet readability golang
29
fork

Configure Feed

Select the types of activity you want to include in your feed.

at d631904bbdd17c4c85e83012b4eae79459a04a9c 397 lines 12 kB view raw
1package main 2 3import ( 4 "strings" 5 6 "github.com/spf13/cobra" 7 "github.com/stormlightlabs/noteleaf/internal/handlers" 8) 9 10// TaskCommand implements CommandGroup for task-related commands 11type TaskCommand struct { 12 handler *handlers.TaskHandler 13} 14 15// NewTaskCommand creates a new TaskCommands with the given handler 16func NewTaskCommand(handler *handlers.TaskHandler) *TaskCommand { 17 return &TaskCommand{handler: handler} 18} 19 20func (c *TaskCommand) Create() *cobra.Command { 21 root := &cobra.Command{Use: "todo", Aliases: []string{"task"}, Short: "task management"} 22 23 for _, init := range []func(*handlers.TaskHandler) *cobra.Command{ 24 addTaskCmd, listTaskCmd, viewTaskCmd, updateTaskCmd, editTaskCmd, 25 deleteTaskCmd, taskProjectsCmd, taskTagsCmd, taskContextsCmd, 26 taskCompleteCmd, taskStartCmd, taskStopCmd, timesheetViewCmd, 27 taskRecurCmd, taskDependCmd, 28 } { 29 cmd := init(c.handler) 30 root.AddCommand(cmd) 31 } 32 33 return root 34} 35 36func addTaskCmd(h *handlers.TaskHandler) *cobra.Command { 37 cmd := &cobra.Command{ 38 Use: "add [description]", 39 Short: "Add a new task", 40 Aliases: []string{"create", "new"}, 41 Args: cobra.MinimumNArgs(1), 42 RunE: func(c *cobra.Command, args []string) error { 43 description := strings.Join(args, " ") 44 priority, _ := c.Flags().GetString("priority") 45 project, _ := c.Flags().GetString("project") 46 context, _ := c.Flags().GetString("context") 47 due, _ := c.Flags().GetString("due") 48 recur, _ := c.Flags().GetString("recur") 49 until, _ := c.Flags().GetString("until") 50 parent, _ := c.Flags().GetString("parent") 51 dependsOn, _ := c.Flags().GetString("depends-on") 52 tags, _ := c.Flags().GetStringSlice("tags") 53 54 defer h.Close() 55 return h.Create(c.Context(), description, priority, project, context, due, recur, until, parent, dependsOn, tags) 56 }, 57 } 58 addCommonTaskFlags(cmd) 59 addDueDateFlag(cmd) 60 addRecurrenceFlags(cmd) 61 addParentFlag(cmd) 62 addDependencyFlags(cmd) 63 64 return cmd 65} 66 67func listTaskCmd(h *handlers.TaskHandler) *cobra.Command { 68 cmd := &cobra.Command{ 69 Use: "list", 70 Short: "List tasks", 71 Aliases: []string{"ls"}, 72 Long: `List tasks with optional filtering and display modes. 73 74By default, shows tasks in an interactive TaskWarrior-like interface. 75Use --static to show a simple text list instead. 76Use --all to show all tasks, otherwise only pending tasks are shown.`, 77 RunE: func(c *cobra.Command, args []string) error { 78 static, _ := c.Flags().GetBool("static") 79 showAll, _ := c.Flags().GetBool("all") 80 status, _ := c.Flags().GetString("status") 81 priority, _ := c.Flags().GetString("priority") 82 project, _ := c.Flags().GetString("project") 83 context, _ := c.Flags().GetString("context") 84 85 defer h.Close() 86 return h.List(c.Context(), static, showAll, status, priority, project, context) 87 }, 88 } 89 cmd.Flags().BoolP("interactive", "i", false, "Force interactive mode (default)") 90 cmd.Flags().Bool("static", false, "Use static text output instead of interactive") 91 cmd.Flags().BoolP("all", "a", false, "Show all tasks (default: pending only)") 92 cmd.Flags().String("status", "", "Filter by status") 93 cmd.Flags().String("priority", "", "Filter by priority") 94 cmd.Flags().String("project", "", "Filter by project") 95 cmd.Flags().String("context", "", "Filter by context") 96 97 return cmd 98} 99 100func viewTaskCmd(handler *handlers.TaskHandler) *cobra.Command { 101 viewCmd := &cobra.Command{ 102 Use: "view [task-id]", 103 Short: "View task by ID", 104 Args: cobra.ExactArgs(1), 105 RunE: func(cmd *cobra.Command, args []string) error { 106 format, _ := cmd.Flags().GetString("format") 107 jsonOutput, _ := cmd.Flags().GetBool("json") 108 noMetadata, _ := cmd.Flags().GetBool("no-metadata") 109 110 defer handler.Close() 111 return handler.View(cmd.Context(), args, format, jsonOutput, noMetadata) 112 }, 113 } 114 addOutputFlags(viewCmd) 115 116 return viewCmd 117} 118 119func updateTaskCmd(handler *handlers.TaskHandler) *cobra.Command { 120 updateCmd := &cobra.Command{ 121 Use: "update [task-id]", 122 Short: "Update task properties", 123 Args: cobra.ExactArgs(1), 124 RunE: func(cmd *cobra.Command, args []string) error { 125 taskID := args[0] 126 description, _ := cmd.Flags().GetString("description") 127 status, _ := cmd.Flags().GetString("status") 128 priority, _ := cmd.Flags().GetString("priority") 129 project, _ := cmd.Flags().GetString("project") 130 context, _ := cmd.Flags().GetString("context") 131 due, _ := cmd.Flags().GetString("due") 132 recur, _ := cmd.Flags().GetString("recur") 133 until, _ := cmd.Flags().GetString("until") 134 parent, _ := cmd.Flags().GetString("parent") 135 addTags, _ := cmd.Flags().GetStringSlice("add-tag") 136 removeTags, _ := cmd.Flags().GetStringSlice("remove-tag") 137 addDeps, _ := cmd.Flags().GetString("add-depends") 138 removeDeps, _ := cmd.Flags().GetString("remove-depends") 139 140 defer handler.Close() 141 return handler.Update(cmd.Context(), taskID, description, status, priority, project, context, due, recur, until, parent, addTags, removeTags, addDeps, removeDeps) 142 }, 143 } 144 updateCmd.Flags().String("description", "", "Update task description") 145 updateCmd.Flags().String("status", "", "Update task status") 146 addCommonTaskFlags(updateCmd) 147 addDueDateFlag(updateCmd) 148 addRecurrenceFlags(updateCmd) 149 addParentFlag(updateCmd) 150 updateCmd.Flags().StringSlice("add-tag", []string{}, "Add tags to task") 151 updateCmd.Flags().StringSlice("remove-tag", []string{}, "Remove tags from task") 152 updateCmd.Flags().String("add-depends", "", "Add task dependencies (comma-separated UUIDs)") 153 updateCmd.Flags().String("remove-depends", "", "Remove task dependencies (comma-separated UUIDs)") 154 155 return updateCmd 156} 157 158func taskProjectsCmd(h *handlers.TaskHandler) *cobra.Command { 159 cmd := &cobra.Command{ 160 Use: "projects", 161 Short: "List projects", 162 Aliases: []string{"proj"}, 163 RunE: func(c *cobra.Command, args []string) error { 164 static, _ := c.Flags().GetBool("static") 165 todoTxt, _ := c.Flags().GetBool("todo-txt") 166 167 defer h.Close() 168 return h.ListProjects(c.Context(), static, todoTxt) 169 }, 170 } 171 cmd.Flags().Bool("static", false, "Use static text output instead of interactive") 172 cmd.Flags().Bool("todo-txt", false, "Format output with +project prefix for todo.txt compatibility") 173 174 return cmd 175} 176 177func taskTagsCmd(h *handlers.TaskHandler) *cobra.Command { 178 cmd := &cobra.Command{ 179 Use: "tags", 180 Short: "List tags", 181 Aliases: []string{"t"}, 182 RunE: func(c *cobra.Command, args []string) error { 183 static, _ := c.Flags().GetBool("static") 184 defer h.Close() 185 return h.ListTags(c.Context(), static) 186 }, 187 } 188 cmd.Flags().Bool("static", false, "Use static text output instead of interactive") 189 return cmd 190} 191 192func taskStartCmd(h *handlers.TaskHandler) *cobra.Command { 193 cmd := &cobra.Command{ 194 Use: "start [task-id]", 195 Short: "Start time tracking for a task", 196 Args: cobra.ExactArgs(1), 197 RunE: func(c *cobra.Command, args []string) error { 198 taskID := args[0] 199 description, _ := c.Flags().GetString("note") 200 201 defer h.Close() 202 return h.Start(c.Context(), taskID, description) 203 }, 204 } 205 cmd.Flags().StringP("note", "n", "", "Add a note to the time entry") 206 return cmd 207} 208 209func taskStopCmd(h *handlers.TaskHandler) *cobra.Command { 210 return &cobra.Command{ 211 Use: "stop [task-id]", 212 Short: "Stop time tracking for a task", 213 Args: cobra.ExactArgs(1), 214 RunE: func(c *cobra.Command, args []string) error { 215 taskID := args[0] 216 defer h.Close() 217 return h.Stop(c.Context(), taskID) 218 }, 219 } 220} 221 222func timesheetViewCmd(h *handlers.TaskHandler) *cobra.Command { 223 cmd := &cobra.Command{ 224 Use: "timesheet", 225 Short: "Show time tracking summary", 226 Long: `Show time tracking summary for tasks. 227 228By default shows time entries for the last 7 days. 229Use --task to show timesheet for a specific task. 230Use --days to change the date range.`, 231 RunE: func(c *cobra.Command, args []string) error { 232 days, _ := c.Flags().GetInt("days") 233 taskID, _ := c.Flags().GetString("task") 234 235 defer h.Close() 236 return h.Timesheet(c.Context(), days, taskID) 237 }, 238 } 239 cmd.Flags().IntP("days", "d", 7, "Number of days to show in timesheet") 240 cmd.Flags().StringP("task", "t", "", "Show timesheet for specific task ID") 241 return cmd 242} 243 244func editTaskCmd(h *handlers.TaskHandler) *cobra.Command { 245 return &cobra.Command{ 246 Use: "edit [task-id]", 247 Short: "Edit task interactively with status picker and priority toggle", 248 Aliases: []string{"e"}, 249 Args: cobra.ExactArgs(1), 250 RunE: func(c *cobra.Command, args []string) error { 251 taskID := args[0] 252 defer h.Close() 253 return h.EditInteractive(c.Context(), taskID) 254 }, 255 } 256} 257 258func deleteTaskCmd(h *handlers.TaskHandler) *cobra.Command { 259 return &cobra.Command{ 260 Use: "delete [task-id]", 261 Short: "Delete a task", 262 Args: cobra.ExactArgs(1), 263 RunE: func(c *cobra.Command, args []string) error { 264 defer h.Close() 265 return h.Delete(c.Context(), args) 266 }, 267 } 268} 269 270func taskContextsCmd(h *handlers.TaskHandler) *cobra.Command { 271 cmd := &cobra.Command{ 272 Use: "contexts", 273 Short: "List contexts (locations)", 274 Aliases: []string{"con", "loc", "ctx", "locations"}, 275 RunE: func(c *cobra.Command, args []string) error { 276 static, _ := c.Flags().GetBool("static") 277 todoTxt, _ := c.Flags().GetBool("todo-txt") 278 279 defer h.Close() 280 return h.ListContexts(c.Context(), static, todoTxt) 281 }, 282 } 283 cmd.Flags().Bool("static", false, "Use static text output instead of interactive") 284 cmd.Flags().Bool("todo-txt", false, "Format output with @context prefix for todo.txt compatibility") 285 return cmd 286} 287 288func taskCompleteCmd(h *handlers.TaskHandler) *cobra.Command { 289 return &cobra.Command{ 290 Use: "done [task-id]", 291 Short: "Mark task as completed", 292 Aliases: []string{"complete"}, 293 Args: cobra.ExactArgs(1), 294 RunE: func(c *cobra.Command, args []string) error { 295 defer h.Close() 296 return h.Done(c.Context(), args) 297 }, 298 } 299} 300 301func taskRecurCmd(h *handlers.TaskHandler) *cobra.Command { 302 root := &cobra.Command{ 303 Use: "recur", 304 Short: "Manage task recurrence", 305 Aliases: []string{"repeat"}, 306 } 307 308 setCmd := &cobra.Command{ 309 Use: "set [task-id]", 310 Short: "Set recurrence rule for a task", 311 Args: cobra.ExactArgs(1), 312 RunE: func(c *cobra.Command, args []string) error { 313 rule, _ := c.Flags().GetString("rule") 314 until, _ := c.Flags().GetString("until") 315 defer h.Close() 316 return h.SetRecur(c.Context(), args[0], rule, until) 317 }, 318 } 319 setCmd.Flags().String("rule", "", "Recurrence rule (e.g., FREQ=DAILY)") 320 setCmd.Flags().String("until", "", "Recurrence end date (YYYY-MM-DD)") 321 322 clearCmd := &cobra.Command{ 323 Use: "clear [task-id]", 324 Short: "Clear recurrence rule from a task", 325 Args: cobra.ExactArgs(1), 326 RunE: func(c *cobra.Command, args []string) error { 327 defer h.Close() 328 return h.ClearRecur(c.Context(), args[0]) 329 }, 330 } 331 332 showCmd := &cobra.Command{ 333 Use: "show [task-id]", 334 Short: "Show recurrence details for a task", 335 Args: cobra.ExactArgs(1), 336 RunE: func(c *cobra.Command, args []string) error { 337 defer h.Close() 338 return h.ShowRecur(c.Context(), args[0]) 339 }, 340 } 341 342 root.AddCommand(setCmd, clearCmd, showCmd) 343 return root 344} 345 346func taskDependCmd(h *handlers.TaskHandler) *cobra.Command { 347 root := &cobra.Command{ 348 Use: "depend", 349 Short: "Manage task dependencies", 350 Aliases: []string{"dep", "deps"}, 351 } 352 353 addCmd := &cobra.Command{ 354 Use: "add [task-id] [depends-on-uuid]", 355 Short: "Add a dependency to a task", 356 Args: cobra.ExactArgs(2), 357 RunE: func(c *cobra.Command, args []string) error { 358 defer h.Close() 359 return h.AddDep(c.Context(), args[0], args[1]) 360 }, 361 } 362 363 removeCmd := &cobra.Command{ 364 Use: "remove [task-id] [depends-on-uuid]", 365 Short: "Remove a dependency from a task", 366 Aliases: []string{"rm"}, 367 Args: cobra.ExactArgs(2), 368 RunE: func(c *cobra.Command, args []string) error { 369 defer h.Close() 370 return h.RemoveDep(c.Context(), args[0], args[1]) 371 }, 372 } 373 374 listCmd := &cobra.Command{ 375 Use: "list [task-id]", 376 Short: "List dependencies for a task", 377 Aliases: []string{"ls"}, 378 Args: cobra.ExactArgs(1), 379 RunE: func(c *cobra.Command, args []string) error { 380 defer h.Close() 381 return h.ListDeps(c.Context(), args[0]) 382 }, 383 } 384 385 blockedByCmd := &cobra.Command{ 386 Use: "blocked-by [task-id]", 387 Short: "Show tasks blocked by this task", 388 Args: cobra.ExactArgs(1), 389 RunE: func(c *cobra.Command, args []string) error { 390 defer h.Close() 391 return h.BlockedByDep(c.Context(), args[0]) 392 }, 393 } 394 395 root.AddCommand(addCmd, removeCmd, listCmd, blockedByCmd) 396 return root 397}