package main import ( "bufio" "context" "fmt" "log/slog" "os" "strconv" "strings" "gitea.kleinsense.nl/DariusKlein/kleinTodo/common" "github.com/urfave/cli/v3" ) // Todo Command func Todo() *cli.Command { return &cli.Command{ Name: "todo", Usage: "print todo items and allow for updating", Action: todo, HideHelpCommand: true, } } func todo(context context.Context, c *cli.Command) error { // bufio.Scanner is a great way to read user input line by line. scanner := bufio.NewScanner(os.Stdin) store, err := common.GetTodoDataStore() if err != nil { return err } todos := store.GetTodoList(cfg.Server.Credentials.Username) if err != nil { return err } // This is the main application loop for the interactive mode. for { clearScreen() printTodos(todos) fmt.Print("What would you like to do? (update, delete, add, quit) [u/d/a/q]: ") // Wait for and read the user's next command. scanner.Scan() command := strings.ToLower(strings.TrimSpace(scanner.Text())) switch command { case "u", "update": todos = handleUpdate(scanner, todos, store) case "d", "delete": todos = handleDelete(scanner, todos, store) case "a", "add": todos = handleAdd(scanner, todos, store) case "q", "quit": fmt.Println("Goodbye!") return nil // Exit the program default: fmt.Println("Invalid command. Please try again.") } } } func clearScreen() { fmt.Print("\033[H\033[2J") } func printTodos(todos []common.Todo) { fmt.Printf("Todo items:\n") for i, t := range todos { t.PrintIndexed(i + 1) } } // handleDelete prompts for an index and removes the item. func handleDelete(scanner *bufio.Scanner, todos []common.Todo, store *common.BoltStore) []common.Todo { fmt.Print("Enter the number of the item to delete: ") scanner.Scan() input := strings.TrimSpace(scanner.Text()) index, err := strconv.Atoi(input) if err != nil || index < 1 || index > len(todos) { fmt.Println("Invalid number. Returning to main menu.") return todos } removedItem := todos[index-1] err = store.RemoveValueFromBucket(cfg.Server.Credentials.Username, removedItem.Name) if err != nil { slog.Error(err.Error()) return todos } fmt.Printf("Item '%s' deleted.\n", removedItem.Name) todos = append(todos[:index-1], todos[index:]...) return todos } // handleUpdate prompts for an index and new values. func handleUpdate(scanner *bufio.Scanner, todos []common.Todo, store *common.BoltStore) []common.Todo { fmt.Print("Enter the number of the item to update: ") scanner.Scan() input := strings.TrimSpace(scanner.Text()) index, err := strconv.Atoi(input) if err != nil || index < 1 || index > len(todos) { fmt.Println("Invalid number. Returning to main menu.") return todos } // Adjust for 0-based slice index itemToUpdate := todos[index-1] fmt.Printf("Updating '%s'. Press Enter to keep current value.\n", itemToUpdate.Name) fmt.Printf("New name [%s]: ", itemToUpdate.Name) scanner.Scan() newName := strings.TrimSpace(scanner.Text()) if newName != "" { itemToUpdate.Name = newName } fmt.Printf("New description [%s]: ", itemToUpdate.Description) scanner.Scan() newDescription := strings.TrimSpace(scanner.Text()) if newDescription != "" { itemToUpdate.Description = newDescription } fmt.Printf("New status [%s]: ", itemToUpdate.Status) scanner.Scan() newStatus := strings.TrimSpace(scanner.Text()) if newStatus != "" { itemToUpdate.Status = newStatus } err = itemToUpdate.Store(store, cfg.Server.Credentials.Username) if err != nil { slog.Error(err.Error()) return todos } fmt.Println("Item updated.") todos[index-1] = itemToUpdate return todos } // handleAdd prompts for the details of a new item. func handleAdd(scanner *bufio.Scanner, todos []common.Todo, store *common.BoltStore) []common.Todo { fmt.Print("Enter the name of the new task: ") scanner.Scan() name := strings.TrimSpace(scanner.Text()) fmt.Print("Enter the description: ") scanner.Scan() description := strings.TrimSpace(scanner.Text()) newTodo := common.Todo{ Name: name, Description: description, Status: common.NotStarted, Owner: cfg.Server.Credentials.Username, } err := newTodo.Store(store, cfg.Server.Credentials.Username) if err != nil { slog.Error(err.Error()) return todos } fmt.Println("New item added.") return append(todos, newTodo) }