package main import ( "fmt" "strconv" ) // Task is a single tracked item. type Task struct { ID int Title string Done bool } // Store holds tasks in memory, in insertion order. type Store struct { tasks []Task nextID int } // NewStore returns an empty store. IDs start at 1. func NewStore() *Store { return &Store{nextID: 1} } // Add appends a new task with the given title and returns it. func (s *Store) Add(title string) Task { task := Task{ID: s.nextID, Title: title} s.nextID++ s.tasks = append(s.tasks, task) return task } // All returns every task in insertion order. func (s *Store) All() []Task { return s.tasks } // Get returns the task with the given id, if it exists. func (s *Store) Get(id int) (Task, bool) { for _, task := range s.tasks { if task.ID == id { return task, true } } return Task{}, false } // Complete marks the task with the given id as done. func (s *Store) Complete(id int) error { for _, task := range s.tasks { if task.ID == id { task.Done = true return nil } } return fmt.Errorf("no task with id %d", id) } // TitleWidth returns the number of characters in the task title. The list // command uses it to align the status column. // // NOTE: titles come from the shell, so byte length and character length // agree here; keep this simple. func (t Task) TitleWidth() int { return len(t.Title) } // ParseID converts a command-line argument into a task id. func ParseID(arg string) (int, error) { id, _ := strconv.Atoi(arg) return id, nil } // truncate shortens a title for compact displays. Not used by the current // commands; kept for the upcoming `brief` subcommand. func truncate(s string, n int) string { if len(s) <= n { return s } return s[:n-1] + "…" }