style.go (view raw)
1package main
2
3import (
4 "fmt"
5 "regexp"
6
7 todo "github.com/1set/todotxt"
8 "github.com/charmbracelet/lipgloss"
9
10 catppuccin "github.com/catppuccin/go"
11)
12
13var DATETIME_FORMAT = "02-01-2006 15:03"
14var DATE_FORMAT = "02-01-2006"
15
16var Catppuccin catppuccin.Flavor = catppuccin.Mocha
17
18type Style struct {
19 Task TaskStyle
20 Priority PriorityStyle
21 Date DateStyle
22 Check lipgloss.Style
23 Context lipgloss.Style
24 Project lipgloss.Style
25 KeyValue lipgloss.Style
26}
27
28type TaskStyle struct {
29 Todo lipgloss.Style
30 Completed lipgloss.Style
31 Futur lipgloss.Style
32}
33
34type PriorityStyle struct {
35 A lipgloss.Style
36 B lipgloss.Style
37 C lipgloss.Style
38}
39
40type DateStyle struct {
41 done lipgloss.Style
42 today lipgloss.Style
43 overdue lipgloss.Style
44 futur lipgloss.Style
45}
46
47func NewTextStyle() Style {
48
49 taskStyle := TaskStyle{
50 Todo: lipgloss.NewStyle().Foreground(lipgloss.Color(Catppuccin.Text().Hex)),
51 Completed: lipgloss.NewStyle().Strikethrough(true).Foreground(lipgloss.Color(Catppuccin.Overlay2().Hex)),
52 Futur: lipgloss.NewStyle().Foreground(lipgloss.Color(Catppuccin.Overlay1().Hex)),
53 }
54
55 priorityStyle := PriorityStyle{
56 A: lipgloss.NewStyle().Foreground(lipgloss.Color(Catppuccin.Red().Hex)),
57 B: lipgloss.NewStyle().Foreground(lipgloss.Color(Catppuccin.Peach().Hex)),
58 C: lipgloss.NewStyle().Foreground(lipgloss.Color(Catppuccin.Green().Hex)),
59 }
60
61 dateBaseStyle := lipgloss.NewStyle()
62 dateStyle := DateStyle{
63 done: dateBaseStyle.Foreground(lipgloss.Color(Catppuccin.Overlay0().Hex)),
64 today: dateBaseStyle.Foreground(lipgloss.Color(Catppuccin.Crust().Hex)).Background(lipgloss.Color(Catppuccin.Blue().Hex)),
65 overdue: dateBaseStyle.Foreground(lipgloss.Color(Catppuccin.Crust().Hex)).Background(lipgloss.Color(Catppuccin.Red().Hex)),
66 futur: dateBaseStyle.Foreground(lipgloss.Color(Catppuccin.Blue().Hex)),
67 }
68
69 style := Style{
70 Priority: priorityStyle,
71 Task: taskStyle,
72 Date: dateStyle,
73 Check: lipgloss.NewStyle().Foreground(lipgloss.Color(Catppuccin.Blue().Hex)),
74 Context: lipgloss.NewStyle().Foreground(lipgloss.Color(Catppuccin.Blue().Hex)),
75 Project: lipgloss.NewStyle().Foreground(lipgloss.Color(Catppuccin.Mauve().Hex)),
76 KeyValue: lipgloss.NewStyle().Foreground(lipgloss.Color(Catppuccin.Flamingo().Hex)),
77 }
78 return style
79}
80
81func (s Style) getTaskStyle(task todo.Task, checked bool) string {
82
83 todoText := task.Original
84
85 checkedRegex := regexp.MustCompile(`^x (\d{4}-\d{2}-\d{2} )? ?`)
86 priorityRegex := regexp.MustCompile(`^\([A-Z]\) `)
87 contextRegex := regexp.MustCompile(`@\w+`)
88 projectRegex := regexp.MustCompile(`\+\w+`)
89 dueDateRegex := regexp.MustCompile(`due:\d{4}-\d{2}-\d{2}`)
90 keyValueRegex := regexp.MustCompile(`\w+:.+`)
91
92 todoText = checkedRegex.ReplaceAllString(todoText, "")
93 todoText = priorityRegex.ReplaceAllString(todoText, "")
94 todoText = dueDateRegex.ReplaceAllString(todoText, "")
95
96 checkString := " "
97 if checked {
98 checkString = "✓"
99 }
100
101 switch task.Completed {
102 case true:
103 dateString := s.Date.done.Render(task.CompletedDate.Local().Format(DATETIME_FORMAT))
104 return fmt.Sprintf("%s %s %s %s", s.Check.Render(checkString), s.getPriorityStyle(task.Priority), s.Task.Completed.Render(todoText), dateString)
105 default:
106 todoText = contextRegex.ReplaceAllStringFunc(todoText, func(match string) string {
107 return s.Context.Render(match)
108 })
109 todoText = projectRegex.ReplaceAllStringFunc(todoText, func(match string) string {
110 return s.Project.Render(match)
111 })
112 todoText = keyValueRegex.ReplaceAllStringFunc(todoText, func(match string) string {
113 return s.KeyValue.Render(match)
114 })
115 var dueDateString string
116 if task.HasDueDate() {
117 formatedDueDate := task.DueDate.Format(DATE_FORMAT)
118 switch {
119 case task.IsDueToday():
120 dueDateString = s.Date.today.Render(formatedDueDate)
121 case task.IsOverdue():
122 dueDateString = s.Date.overdue.Render(formatedDueDate)
123 default:
124 dueDateString = s.Date.futur.Render(formatedDueDate)
125 }
126 }
127
128 todoTextRender := s.Task.Todo
129 if task.AdditionalTags["freq"] != "" && !task.IsOverdue() && !task.IsDueToday() {
130 todoTextRender = s.Task.Futur
131 }
132
133 return fmt.Sprintf("%s %s %s %s", s.Check.Render(checkString), s.getPriorityStyle(task.Priority), todoTextRender.Render(todoText), dueDateString)
134 }
135}
136
137func (s Style) getPriorityStyle(priority string) string {
138 switch priority {
139 case "":
140 return " "
141 case "A":
142 return s.Priority.A.Render(priority)
143 case "B":
144 return s.Priority.B.Render(priority)
145 case "C":
146 return s.Priority.C.Render(priority)
147 default:
148 return priority
149 }
150}