github.com/wtfutil/wtf@v0.43.0/modules/todo/display.go (about) 1 package todo 2 3 import ( 4 "fmt" 5 "strings" 6 "time" 7 8 "github.com/rivo/tview" 9 "github.com/wtfutil/wtf/checklist" 10 "github.com/wtfutil/wtf/utils" 11 ) 12 13 func (widget *Widget) display() { 14 widget.Redraw(widget.content) 15 } 16 17 func (widget *Widget) content() (string, string, bool) { 18 str := "" 19 hidden := 0 20 if widget.settings.checkedPos == "last" { 21 str, hidden = widget.sortListByChecked(widget.list.UncheckedItems(), widget.list.CheckedItems()) 22 } else if widget.settings.checkedPos == "first" { 23 str, hidden = widget.sortListByChecked(widget.list.CheckedItems(), widget.list.UncheckedItems()) 24 } else { 25 str, hidden = widget.sortListByChecked(widget.list.Items, []*checklist.ChecklistItem{}) 26 } 27 28 if widget.Error != "" { 29 str = widget.Error 30 } 31 32 title := widget.CommonSettings().Title 33 if widget.showTagPrefix != "" { 34 title += " #" + widget.showTagPrefix 35 } 36 if widget.showFilter != "" { 37 title += fmt.Sprintf(" /%s", widget.showFilter) 38 } 39 if widget.settings.hiddenNumInTitle { 40 title += fmt.Sprintf(" (%d hidden)", hidden) 41 } 42 43 return title, str, false 44 } 45 46 func (widget *Widget) sortListByChecked(firstGroup []*checklist.ChecklistItem, secondGroup []*checklist.ChecklistItem) (string, int) { 47 str := "" 48 hidden := 0 49 newList := checklist.NewChecklist( 50 widget.settings.Sigils.Checkbox.Checked, 51 widget.settings.Sigils.Checkbox.Unchecked, 52 ) 53 54 offset := 0 55 selectedItem := widget.SelectedItem() 56 for idx, item := range firstGroup { 57 if widget.shouldShowItem(item) { 58 str += widget.formattedItemLine(idx, hidden, item) 59 } else { 60 hidden = hidden + 1 61 } 62 newList.Items = append(newList.Items, item) 63 offset++ 64 } 65 66 for idx, item := range secondGroup { 67 if widget.shouldShowItem(item) { 68 str += widget.formattedItemLine(idx+offset, hidden, item) 69 } else { 70 hidden = hidden + 1 71 } 72 newList.Items = append(newList.Items, item) 73 } 74 if idx, ok := newList.IndexByItem(selectedItem); ok { 75 widget.Selected = idx 76 } 77 78 widget.SetList(newList) 79 return str, hidden 80 } 81 82 func (widget *Widget) shouldShowItem(item *checklist.ChecklistItem) bool { 83 if widget.showFilter != "" && !strings.Contains(strings.ToLower(item.Text), widget.showFilter) { 84 return false 85 } 86 87 if !widget.settings.parseTags { 88 return true 89 } 90 91 if len(item.Tags) == 0 { 92 return widget.showTagPrefix == "" 93 } 94 95 for _, tag := range item.Tags { 96 for _, hideTag := range widget.settings.hideTags { 97 if widget.showTagPrefix == "" && tag == hideTag { 98 return false 99 } 100 } 101 if widget.showTagPrefix == "" || strings.HasPrefix(tag, widget.showTagPrefix) { 102 return true 103 } 104 } 105 106 return false 107 } 108 109 func (widget *Widget) RowColor(idx int, hidden int, checked bool) string { 110 if widget.View.HasFocus() && (idx == widget.Selected) { 111 foreground := widget.CommonSettings().Colors.RowTheme.HighlightedForeground 112 if checked { 113 foreground = widget.settings.Colors.CheckboxTheme.Checked 114 } 115 return fmt.Sprintf( 116 "%s:%s", 117 foreground, 118 widget.CommonSettings().Colors.RowTheme.HighlightedBackground, 119 ) 120 } 121 122 if checked { 123 return widget.settings.Colors.CheckboxTheme.Checked 124 } else { 125 return widget.CommonSettings().RowColor(idx - hidden) 126 } 127 } 128 129 func (widget *Widget) formattedItemLine(idx int, hidden int, currItem *checklist.ChecklistItem) string { 130 rowColor := widget.RowColor(idx, hidden, currItem.Checked) 131 132 todoDate := currItem.Date 133 row := fmt.Sprintf( 134 ` [%s]|%s| `, 135 rowColor, 136 currItem.CheckMark(), 137 ) 138 139 if widget.settings.parseDates && todoDate != nil { 140 row += fmt.Sprintf( 141 `[%s]%s `, 142 widget.settings.dateColor, 143 widget.getDateString(todoDate), 144 ) 145 } 146 147 tagsPart := "" 148 if len(currItem.Tags) > 0 { 149 tagsPart = fmt.Sprintf( 150 `[%s]%s[white]`, 151 widget.settings.tagColor, 152 currItem.TagString(), 153 ) 154 } 155 156 textPart := fmt.Sprintf( 157 `[%s]%s[white]`, 158 rowColor, 159 tview.Escape(currItem.Text), 160 ) 161 162 if widget.settings.parseTags && widget.settings.tagsAtEnd { 163 row += textPart + " " + tagsPart 164 } else if widget.settings.parseTags { 165 row += tagsPart + textPart 166 } else { 167 row += textPart 168 } 169 170 return utils.HighlightableHelper(widget.View, row, idx-hidden, len(currItem.Text)) 171 } 172 173 func (widget *Widget) getDateString(date *time.Time) string { 174 now := getNowDate() 175 diff := int(date.Sub(now).Hours() / 24) 176 if diff == 0 { 177 return "today" 178 } else if diff == 1 { 179 return "tomorrow" 180 } else if diff <= widget.settings.switchToInDaysIn { 181 return fmt.Sprintf("in %d days", diff) 182 } else { 183 dateStr := "" 184 y, m, d := date.Year(), date.Month(), date.Day() 185 switch widget.settings.dateFormat { 186 case "yyyy-mm-dd": 187 dateStr = fmt.Sprintf("%d-%02d-%02d", y, m, d) 188 case "yy-mm-dd": 189 dateStr = fmt.Sprintf("%d-%02d-%02d", y-2000, m, d) 190 case "dd-mm-yyyy": 191 dateStr = fmt.Sprintf("%02d-%02d-%d", d, m, y) 192 case "dd-mm-yy": 193 dateStr = fmt.Sprintf("%02d-%02d-%d", d, m, y-2000) 194 case "dd M yyyy": 195 dateStr = fmt.Sprintf("%02d %s %d", d, date.Month().String()[:3], y) 196 // date 197 case "dd M yy": 198 dateStr = fmt.Sprintf("%02d %s %d", d, date.Month().String()[:3], y-2000) 199 // dateStr = "aaasdada" 200 default: 201 dateStr = fmt.Sprintf("%d-%02d-%02d", y, m, d) 202 // dateStr = fmt.Sprintf("%d-%02d-%02d", y, m, d) 203 } 204 if widget.settings.hideYearIfCurrent && date.Year() == now.Year() { 205 if widget.settings.dateFormat[:1] == "y" { 206 dateStr = dateStr[strings.Index(dateStr, "-")+1:] 207 } else if widget.settings.dateFormat[3:4] == "-" { 208 dateStr = dateStr[:5] 209 } else { 210 parts := strings.Split(dateStr, " ") 211 dateStr = parts[0] + " " + parts[1] 212 } 213 } 214 return dateStr 215 } 216 } 217 218 func getNowDate() time.Time { 219 now := time.Now() 220 now = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Now().Location()) 221 return now 222 }