lune
created pr with
124.1
changed status to
closed
Closing as superceded by 126
cmds
checkout latest patchset:
ssh pr.pico.sh print 124 | git am -3checkout any patchset in a patch request:
ssh pr.pico.sh print 124.[rev] | git am -3add changes to patch request:
git format-patch main --stdout | ssh pr.pico.sh pr add 124set PR to open (enables RSS notifications):
ssh pr.pico.sh pr open 124set PR to draft (stops RSS notifications):
ssh pr.pico.sh pr draft 124
Patchset
124.1
listing real name of tasks
juan
construction of db for management of decrypted names of tasks
2026-04-21T03:21:16Zjuan
fix UTF8 chracteres
2026-04-21T05:43:09Zjuan
→ filter by status and coloring types of status
2026-04-21T21:13:24Zjuan
update help
2026-04-21T21:18:53Zjuan
list areas names
2026-04-21T21:21:36Zjuan
adjust table tasks to truncate name and list area
2026-04-21T21:44:53Zjuan
partial implementation of listing tasks by areas
2026-04-21T21:56:40Zjuan
final implementation of listing tasks by areas with UTF-8 chracteres
2026-04-21T22:05:20Zjuan
sort on task list to show first do now
2026-04-21T22:10:20Zjuan
update with 8 char of id and db.go
2026-04-21T22:33:29Zjuan
partial implementation of TUI menu on task update
2026-04-21T23:27:54Zjuan
task name correcion on TUI menu of Update task
2026-04-21T23:35:35Zjuan
TUI menu for update task with others flags
2026-04-21T23:38:19Zjuan
helper for TUI update task
2026-04-21T23:43:02Zjuan
search by first 8 char of note id for editing it
2026-04-21T23:49:56Zjuan
partial implementation on note TUI menu for update
2026-04-22T00:00:17Zjuan
TUI menu notebook just with tags
2026-04-22T00:05:46Zjuan
Note update now let you insert only the first 8 char of notebook id in update
2026-04-22T00:20:55Zjuan
implementation of (lune note notebook-list) for listing all notebooks and its ID
2026-04-22T00:25:53Zjuan
partial implementation of lune note show-content ID
2026-04-22T01:10:51Zjuan
convert \n in new line and \ in space for lune note show-content ID
2026-04-22T02:01:11Zjuan
2026-04-22T02:18:42Z
filter by status and coloring types of status
juan
2026-04-21T21:18:53ZSemantic diff summary
1 added,
7 modified,
1 signature changed,
0 removed
across 2 analyzed files
cmd/task/list.go
-
function_declarationinitmodified -
function_declarationrunListmodified -
function_declarationmustGetStringFlagmodified -
function_declarationresolveAreaFiltermodified -
function_declarationresolveScheduledFilteradded -
function_declarationapplyFiltersEnrichedsignature changed -
function_declarationoutputJSONEnrichedmodified -
function_declarationoutputTableEnrichedmodified
+62
-19
cmd/task/list.go
#
| ... | ... | @@ -47,6 +47,7 @@ are not available through the API. Only metadata is shown.`, | |
| 47 | 47 | func init() { | |
| 48 | 48 | ListCmd.Flags().StringP("area", "a", "", "Filter by area key") | |
| 49 | 49 | ListCmd.Flags().StringP("status", "s", "", "Filter by status") | |
| 50 | + | ListCmd.Flags().StringP("scheduled", "d", "", "Filter by scheduled date (today, tomorrow, or YYYY-MM-DD)") | |
| 50 | 51 | ListCmd.Flags().Bool("all", false, "Show all tasks including completed") | |
| 51 | 52 | ListCmd.Flags().Bool("json", false, "Output as JSON") | |
| 52 | 53 |
| ... | ... | @@ -87,8 +88,13 @@ func runList(cmd *cobra.Command, _ []string) error { | |
| 87 | 88 | return err | |
| 88 | 89 | } | |
| 89 | 90 | ||
| 91 | + | scheduledFilter, err := resolveScheduledFilter(cmd) | |
| 92 | + | if err != nil { | |
| 93 | + | return err | |
| 94 | + | } | |
| 95 | + | ||
| 90 | 96 | showAll := mustGetBoolFlag(cmd, "all") | |
| 91 | - | filtered := applyFiltersEnriched(enriched, areaID, statusFilter, showAll) | |
| 97 | + | filtered := applyFiltersEnriched(enriched, areaID, statusFilter, scheduledFilter, showAll) | |
| 92 | 98 | ||
| 93 | 99 | if len(filtered) == 0 { | |
| 94 | 100 | fmt.Fprintln(cmd.OutOrStdout(), "No tasks found") |
| ... | ... | @@ -103,8 +109,6 @@ func runList(cmd *cobra.Command, _ []string) error { | |
| 103 | 109 | return outputTableEnriched(cmd, filtered) | |
| 104 | 110 | } | |
| 105 | 111 | ||
| 106 | - | // mustGetStringFlag returns the string flag value. Panics if flag doesn't exist | |
| 107 | - | // (indicates a programming error—flags are defined in init). | |
| 108 | 112 | func mustGetStringFlag(cmd *cobra.Command, name string) string { | |
| 109 | 113 | f := cmd.Flags().Lookup(name) | |
| 110 | 114 | if f == nil { |
| ... | ... | @@ -114,7 +118,6 @@ func mustGetStringFlag(cmd *cobra.Command, name string) string { | |
| 114 | 118 | return f.Value.String() | |
| 115 | 119 | } | |
| 116 | 120 | ||
| 117 | - | // mustGetBoolFlag returns the bool flag value. Panics if flag doesn't exist. | |
| 118 | 121 | func mustGetBoolFlag(cmd *cobra.Command, name string) bool { | |
| 119 | 122 | f := cmd.Flags().Lookup(name) | |
| 120 | 123 | if f == nil { |
| ... | ... | @@ -129,19 +132,15 @@ func resolveAreaFilter(cmd *cobra.Command) (string, error) { | |
| 129 | 132 | ||
| 130 | 133 | cfg, err := config.Load() | |
| 131 | 134 | if err != nil { | |
| 132 | - | // Config not required if no area flag and we just skip default | |
| 133 | 135 | if errors.Is(err, config.ErrNotFound) { | |
| 134 | 136 | if areaKey != "" { | |
| 135 | 137 | return "", err | |
| 136 | 138 | } | |
| 137 | - | ||
| 138 | 139 | return "", nil | |
| 139 | 140 | } | |
| 140 | - | ||
| 141 | 141 | return "", err | |
| 142 | 142 | } | |
| 143 | 143 | ||
| 144 | - | // Use default area if no explicit flag | |
| 145 | 144 | if areaKey == "" { | |
| 146 | 145 | areaKey = cfg.Defaults.Area | |
| 147 | 146 | } |
| ... | ... | @@ -172,8 +171,30 @@ func resolveStatusFilter(cmd *cobra.Command) (string, error) { | |
| 172 | 171 | return string(s), nil | |
| 173 | 172 | } | |
| 174 | 173 | ||
| 175 | - | func applyFiltersEnriched(tasks []enrichedTask, areaID, statusFilter string, showAll bool) []enrichedTask { | |
| 176 | - | // Extract basic tasks for library filter | |
| 174 | + | func resolveScheduledFilter(cmd *cobra.Command) (string, error) { | |
| 175 | + | val := mustGetStringFlag(cmd, "scheduled") | |
| 176 | + | if val == "" { | |
| 177 | + | return "", nil | |
| 178 | + | } | |
| 179 | + | ||
| 180 | + | today := time.Now().Format("2006-01-02") | |
| 181 | + | tomorrow := time.Now().AddDate(0, 0, 1).Format("2006-01-02") | |
| 182 | + | ||
| 183 | + | switch val { | |
| 184 | + | case "today": | |
| 185 | + | return today, nil | |
| 186 | + | case "tomorrow": | |
| 187 | + | return tomorrow, nil | |
| 188 | + | default: | |
| 189 | + | _, err := time.Parse("2006-01-02", val) | |
| 190 | + | if err != nil { | |
| 191 | + | return "", fmt.Errorf("invalid date format for --scheduled, use YYYY-MM-DD: %w", err) | |
| 192 | + | } | |
| 193 | + | return val, nil | |
| 194 | + | } | |
| 195 | + | } | |
| 196 | + | ||
| 197 | + | func applyFiltersEnriched(tasks []enrichedTask, areaID, statusFilter, scheduledFilter string, showAll bool) []enrichedTask { | |
| 177 | 198 | baseTasks := make([]lunatask.Task, len(tasks)) | |
| 178 | 199 | for i, t := range tasks { | |
| 179 | 200 | baseTasks[i] = t.Task |
| ... | ... | @@ -193,9 +214,18 @@ func applyFiltersEnriched(tasks []enrichedTask, areaID, statusFilter string, sho | |
| 193 | 214 | ||
| 194 | 215 | filteredBase := lunatask.FilterTasks(baseTasks, opts) | |
| 195 | 216 | ||
| 196 | - | // Map back to enriched | |
| 197 | 217 | res := make([]enrichedTask, 0, len(filteredBase)) | |
| 198 | 218 | for _, fb := range filteredBase { | |
| 219 | + | if scheduledFilter != "" { | |
| 220 | + | taskDate := "" | |
| 221 | + | if fb.ScheduledOn != nil { | |
| 222 | + | taskDate = fb.ScheduledOn.Time.Format("2006-01-02") | |
| 223 | + | } | |
| 224 | + | if taskDate != scheduledFilter { | |
| 225 | + | continue | |
| 226 | + | } | |
| 227 | + | } | |
| 228 | + | ||
| 199 | 229 | for _, et := range tasks { | |
| 200 | 230 | if et.ID == fb.ID { | |
| 201 | 231 | res = append(res, et) |
| ... | ... | @@ -209,12 +239,7 @@ func applyFiltersEnriched(tasks []enrichedTask, areaID, statusFilter string, sho | |
| 209 | 239 | func outputJSONEnriched(cmd *cobra.Command, tasks []enrichedTask) error { | |
| 210 | 240 | enc := json.NewEncoder(cmd.OutOrStdout()) | |
| 211 | 241 | enc.SetIndent("", " ") | |
| 212 | - | ||
| 213 | - | if err := enc.Encode(tasks); err != nil { | |
| 214 | - | return fmt.Errorf("encoding JSON: %w", err) | |
| 215 | - | } | |
| 216 | - | ||
| 217 | - | return nil | |
| 242 | + | return enc.Encode(tasks) | |
| 218 | 243 | } | |
| 219 | 244 | ||
| 220 | 245 | func outputTableEnriched(cmd *cobra.Command, tasks []enrichedTask) error { |
| ... | ... | @@ -247,11 +272,29 @@ func outputTableEnriched(cmd *cobra.Command, tasks []enrichedTask) error { | |
| 247 | 272 | return ui.TableHeaderStyle() | |
| 248 | 273 | } | |
| 249 | 274 | ||
| 275 | + | if row >= 0 && row < len(tasks) { | |
| 276 | + | t := tasks[row] | |
| 277 | + | if t.Status != nil { | |
| 278 | + | switch *t.Status { | |
| 279 | + | case lunatask.StatusLater: | |
| 280 | + | return ui.StatusLater | |
| 281 | + | case lunatask.StatusNext: | |
| 282 | + | return ui.StatusNext | |
| 283 | + | case lunatask.StatusInProgress: | |
| 284 | + | return ui.StatusInProgress | |
| 285 | + | case lunatask.StatusWaiting: | |
| 286 | + | return ui.StatusWaiting | |
| 287 | + | case lunatask.StatusCompleted: | |
| 288 | + | return ui.StatusCompleted | |
| 289 | + | } | |
| 290 | + | } | |
| 291 | + | } | |
| 292 | + | ||
| 250 | 293 | return lipgloss.NewStyle() | |
| 251 | 294 | }). | |
| 252 | - | Border(ui.TableBorder()) | |
| 295 | + | Border(ui.TableBorder()). | |
| 296 | + | BorderRow(true) | |
| 253 | 297 | ||
| 254 | 298 | fmt.Fprintln(cmd.OutOrStdout(), tbl.Render()) | |
| 255 | - | ||
| 256 | 299 | return nil | |
| 257 | 300 | } |
+9
-0
internal/ui/styles.go
#
| ... | ... | @@ -61,6 +61,15 @@ var ( | |
| 61 | 61 | Padding(0, 1)} | |
| 62 | 62 | ) | |
| 63 | 63 | ||
| 64 | + | // Task status colors. | |
| 65 | + | var ( | |
| 66 | + | StatusLater = lipgloss.NewStyle().Foreground(lipgloss.Color("8")) // Gray | |
| 67 | + | StatusNext = lipgloss.NewStyle().Foreground(lipgloss.Color("12")) // Light Blue | |
| 68 | + | StatusInProgress = lipgloss.NewStyle().Foreground(lipgloss.Color("4")) // Blue | |
| 69 | + | StatusWaiting = lipgloss.NewStyle().Foreground(lipgloss.Color("5")) // Magenta | |
| 70 | + | StatusCompleted = lipgloss.NewStyle().Foreground(lipgloss.Color("2")) // Green | |
| 71 | + | ) | |
| 72 | + | ||
| 64 | 73 | // FormatDate formats a time.Time as a date string using the user's locale. | |
| 65 | 74 | // Locale is auto-detected from LC_TIME, LC_ALL, or LANG environment variables. | |
| 66 | 75 | func FormatDate(t time.Time) string { |