1package todos
2
3import (
4 "slices"
5 "strings"
6
7 "charm.land/lipgloss/v2"
8 "github.com/charmbracelet/crush/internal/session"
9 "github.com/charmbracelet/crush/internal/tui/styles"
10 "github.com/charmbracelet/x/ansi"
11)
12
13func sortTodos(todos []session.Todo) {
14 slices.SortStableFunc(todos, func(a, b session.Todo) int {
15 return statusOrder(a.Status) - statusOrder(b.Status)
16 })
17}
18
19func statusOrder(s session.TodoStatus) int {
20 switch s {
21 case session.TodoStatusCompleted:
22 return 0
23 case session.TodoStatusInProgress:
24 return 1
25 default:
26 return 2
27 }
28}
29
30func FormatTodosList(todos []session.Todo, inProgressIcon string, t *styles.Theme, width int) string {
31 if len(todos) == 0 {
32 return ""
33 }
34
35 sorted := make([]session.Todo, len(todos))
36 copy(sorted, todos)
37 sortTodos(sorted)
38
39 var lines []string
40 for _, todo := range sorted {
41 var prefix string
42 var textStyle lipgloss.Style
43
44 switch todo.Status {
45 case session.TodoStatusCompleted:
46 prefix = t.S().Base.Foreground(t.Green).Render(styles.TodoCompletedIcon) + " "
47 textStyle = t.S().Base.Foreground(t.FgBase)
48 case session.TodoStatusInProgress:
49 prefix = t.S().Base.Foreground(t.GreenDark).Render(inProgressIcon + " ")
50 textStyle = t.S().Base.Foreground(t.FgBase)
51 default:
52 prefix = t.S().Base.Foreground(t.FgMuted).Render(styles.TodoPendingIcon) + " "
53 textStyle = t.S().Base.Foreground(t.FgBase)
54 }
55
56 text := todo.Content
57 if todo.Status == session.TodoStatusInProgress && todo.ActiveForm != "" {
58 text = todo.ActiveForm
59 }
60 line := prefix + textStyle.Render(text)
61 line = ansi.Truncate(line, width, "…")
62
63 lines = append(lines, line)
64 }
65
66 return strings.Join(lines, "\n")
67}