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
partial implementation of listing tasks by areas
juan
2026-04-21T22:05:20ZSemantic diff summary
2 added,
6 modified,
2 signature changed,
2 removed
across 5 analyzed files
+5
-3
cmd/area/list.go
#
| ... | ... | @@ -25,14 +25,16 @@ type displayArea struct { | |
| 25 | 25 | ||
| 26 | 26 | // ListCmd lists configured areas and their goals. | |
| 27 | 27 | var ListCmd = &cobra.Command{ | |
| 28 | - | Use: "list", | |
| 29 | - | Short: "List areas", | |
| 28 | + | Use: "list", | |
| 29 | + | Aliases: []string{"lista"}, | |
| 30 | + | Short: "List areas", | |
| 30 | 31 | Long: `List areas configured in lune or found in your local database. | |
| 31 | 32 | ||
| 32 | 33 | Proactive Features: | |
| 33 | 34 | - Local Database Discovery: Automatically lists all areas from your Lunatask | |
| 34 | 35 | database if experimental mode is enabled.`, | |
| 35 | - | RunE: runList, | |
| 36 | + | RunE: runList, | |
| 37 | + | SilenceUsage: true, | |
| 36 | 38 | } | |
| 37 | 39 | ||
| 38 | 40 | func init() { |
+48
-40
cmd/goal/list.go
#
| ... | ... | @@ -10,6 +10,7 @@ import ( | |
| 10 | 10 | ||
| 11 | 11 | "git.secluded.site/lune/internal/completion" | |
| 12 | 12 | "git.secluded.site/lune/internal/config" | |
| 13 | + | "git.secluded.site/lune/internal/db" | |
| 13 | 14 | "git.secluded.site/lune/internal/ui" | |
| 14 | 15 | "github.com/charmbracelet/lipgloss" | |
| 15 | 16 | "github.com/charmbracelet/lipgloss/table" |
| ... | ... | @@ -18,13 +19,16 @@ import ( | |
| 18 | 19 | ||
| 19 | 20 | // ListCmd lists configured goals. | |
| 20 | 21 | var ListCmd = &cobra.Command{ | |
| 21 | - | Use: "list", | |
| 22 | - | Short: "List configured goals", | |
| 23 | - | Long: `List goals configured in lune. | |
| 22 | + | Use: "list [AREA]", | |
| 23 | + | Aliases: []string{"lista"}, | |
| 24 | + | Short: "List goals", | |
| 25 | + | Long: `List goals configured in lune or found in your local database. | |
| 24 | 26 | ||
| 25 | 27 | By default, shows goals from the default area (if configured). | |
| 26 | - | Use --area to specify a different area, or --all to show all goals.`, | |
| 27 | - | RunE: runList, | |
| 28 | + | Use --area or provide the area name as an argument to filter.`, | |
| 29 | + | Args: cobra.MaximumNArgs(1), | |
| 30 | + | RunE: runList, | |
| 31 | + | SilenceUsage: true, | |
| 28 | 32 | } | |
| 29 | 33 | ||
| 30 | 34 | func init() { |
| ... | ... | @@ -35,30 +39,55 @@ func init() { | |
| 35 | 39 | _ = ListCmd.RegisterFlagCompletionFunc("area", completion.Areas) | |
| 36 | 40 | } | |
| 37 | 41 | ||
| 38 | - | func runList(cmd *cobra.Command, _ []string) error { | |
| 42 | + | func runList(cmd *cobra.Command, args []string) error { | |
| 39 | 43 | cfg, err := config.Load() | |
| 40 | 44 | if err != nil { | |
| 41 | 45 | return err | |
| 42 | 46 | } | |
| 43 | 47 | ||
| 44 | - | areaKey, _ := cmd.Flags().GetString("area") | |
| 45 | - | showAll, _ := cmd.Flags().GetBool("all") | |
| 46 | - | usingDefault := areaKey == "" && !showAll && cfg.Defaults.Area != "" | |
| 47 | - | ||
| 48 | - | areas := filterAreas(cfg, areaKey, showAll) | |
| 49 | - | if len(areas) == 0 { | |
| 50 | - | fmt.Fprintln(cmd.OutOrStdout(), "No areas found") | |
| 48 | + | if cfg != nil && cfg.Experimental.LocalDB { | |
| 49 | + | _ = db.WarmCache() | |
| 50 | + | } | |
| 51 | 51 | ||
| 52 | - | return nil | |
| 52 | + | areaInput := "" | |
| 53 | + | if len(args) > 0 { | |
| 54 | + | areaInput = args[0] | |
| 55 | + | } else { | |
| 56 | + | areaInput, _ = cmd.Flags().GetString("area") | |
| 53 | 57 | } | |
| 54 | 58 | ||
| 55 | - | goals := collectGoals(areas) | |
| 56 | - | if len(goals) == 0 { | |
| 57 | - | if usingDefault { | |
| 58 | - | fmt.Fprintf(cmd.OutOrStdout(), "No goals configured in %s area\n", cfg.Defaults.Area) | |
| 59 | + | showAll, _ := cmd.Flags().GetBool("all") | |
| 60 | + | ||
| 61 | + | var areas []config.Area | |
| 62 | + | if showAll { | |
| 63 | + | areas = cfg.Areas | |
| 64 | + | } else { | |
| 65 | + | targetAreaID := "" | |
| 66 | + | if areaInput == "" && cfg.Defaults.Area != "" { | |
| 67 | + | areaInput = cfg.Defaults.Area | |
| 68 | + | } | |
| 69 | + | ||
| 70 | + | if areaInput != "" { | |
| 71 | + | // Try config | |
| 72 | + | if a := cfg.AreaByKey(areaInput); a != nil { | |
| 73 | + | targetAreaID = a.ID | |
| 74 | + | areas = []config.Area{*a} | |
| 75 | + | } else { | |
| 76 | + | // Try proactive DB | |
| 77 | + | targetAreaID = db.FindAreaIDByName(areaInput) | |
| 78 | + | if targetAreaID != "" { | |
| 79 | + | // We found an area in DB that isn't in config, | |
| 80 | + | // we create a temporary config.Area to show its goals | |
| 81 | + | areas = []config.Area{{ID: targetAreaID, Name: areaInput, Key: "-"}} | |
| 82 | + | } | |
| 83 | + | } | |
| 59 | 84 | } else { | |
| 60 | - | fmt.Fprintln(cmd.OutOrStdout(), "No goals configured") | |
| 85 | + | areas = cfg.Areas | |
| 61 | 86 | } | |
| 87 | + | } | |
| 88 | + | goals := collectGoals(areas) | |
| 89 | + | if len(goals) == 0 { | |
| 90 | + | fmt.Fprintln(cmd.OutOrStdout(), "No goals configured") | |
| 62 | 91 | ||
| 63 | 92 | return nil | |
| 64 | 93 | } |
| ... | ... | @@ -78,27 +107,6 @@ type goalWithArea struct { | |
| 78 | 107 | AreaKey string `json:"area_key"` | |
| 79 | 108 | } | |
| 80 | 109 | ||
| 81 | - | func filterAreas(cfg *config.Config, areaKey string, showAll bool) []config.Area { | |
| 82 | - | if showAll { | |
| 83 | - | return cfg.Areas | |
| 84 | - | } | |
| 85 | - | ||
| 86 | - | if areaKey == "" { | |
| 87 | - | areaKey = cfg.Defaults.Area | |
| 88 | - | } | |
| 89 | - | ||
| 90 | - | if areaKey == "" { | |
| 91 | - | return cfg.Areas | |
| 92 | - | } | |
| 93 | - | ||
| 94 | - | area := cfg.AreaByKey(areaKey) | |
| 95 | - | if area == nil { | |
| 96 | - | return nil | |
| 97 | - | } | |
| 98 | - | ||
| 99 | - | return []config.Area{*area} | |
| 100 | - | } | |
| 101 | - | ||
| 102 | 110 | func collectGoals(areas []config.Area) []goalWithArea { | |
| 103 | 111 | var goals []goalWithArea | |
| 104 | 112 |
+5
-3
cmd/note/list.go
#
| ... | ... | @@ -27,15 +27,17 @@ type enrichedNote struct { | |
| 27 | 27 | ||
| 28 | 28 | // ListCmd lists notes. Exported for potential use by shortcuts. | |
| 29 | 29 | var ListCmd = &cobra.Command{ | |
| 30 | - | Use: "list", | |
| 31 | - | Short: "List notes", | |
| 30 | + | Use: "list", | |
| 31 | + | Aliases: []string{"lista"}, | |
| 32 | + | Short: "List notes", | |
| 32 | 33 | Long: `List notes from Lunatask. | |
| 33 | 34 | ||
| 34 | 35 | Proactive Features: | |
| 35 | 36 | - Local Database Enrichment: Retrieves real note and notebook names | |
| 36 | 37 | from your local database using your master password. | |
| 37 | 38 | - Organized View: Shows notes grouped by their original notebooks.`, | |
| 38 | - | RunE: runList, | |
| 39 | + | RunE: runList, | |
| 40 | + | SilenceUsage: true, | |
| 39 | 41 | } | |
| 40 | 42 | ||
| 41 | 43 | func init() { |
+40
-27
cmd/task/list.go
#
| ... | ... | @@ -8,11 +8,11 @@ import ( | |
| 8 | 8 | "encoding/json" | |
| 9 | 9 | "errors" | |
| 10 | 10 | "fmt" | |
| 11 | + | "strings" | |
| 11 | 12 | "time" | |
| 12 | 13 | ||
| 13 | 14 | "git.secluded.site/go-lunatask" | |
| 14 | 15 | "git.secluded.site/lune/internal/client" | |
| 15 | - | "git.secluded.site/lune/internal/completion" | |
| 16 | 16 | "git.secluded.site/lune/internal/config" | |
| 17 | 17 | "git.secluded.site/lune/internal/db" | |
| 18 | 18 | "git.secluded.site/lune/internal/ui" |
| ... | ... | @@ -32,19 +32,26 @@ var ErrUnknownArea = errors.New("unknown area key") | |
| 32 | 32 | ||
| 33 | 33 | // ListCmd lists tasks. Exported for potential use by shortcuts. | |
| 34 | 34 | var ListCmd = &cobra.Command{ | |
| 35 | - | Use: "list", | |
| 36 | - | Short: "List tasks", | |
| 35 | + | Use: "list [AREA]", | |
| 36 | + | Aliases: []string{"lista"}, | |
| 37 | + | Short: "List tasks", | |
| 37 | 38 | Long: `List tasks from Lunatask. | |
| 38 | 39 | ||
| 39 | 40 | By default, shows incomplete tasks and tasks completed today. | |
| 40 | 41 | Use --all to show entire task history. | |
| 41 | 42 | ||
| 43 | + | You can filter by area by providing its name as an argument | |
| 44 | + | or using the --area flag. | |
| 45 | + | ||
| 42 | 46 | Proactive Features: | |
| 43 | 47 | - Local Database Enrichment: If enabled in config and master password is set, | |
| 44 | 48 | real task names are retrieved from your local Lunatask database. | |
| 45 | 49 | - Status Coloring: Tasks are color-coded by their current status. | |
| 46 | - | - Scheduled Filtering: Filter tasks by when they are planned (today, tomorrow, or date).`, | |
| 47 | - | RunE: runList, | |
| 50 | + | - Scheduled Filtering: Filter tasks by when they are planned (today, tomorrow, or date). | |
| 51 | + | - Proactive Area Filtering: Filter by area names found in your local database.`, | |
| 52 | + | Args: cobra.MaximumNArgs(1), | |
| 53 | + | RunE: runList, | |
| 54 | + | SilenceUsage: true, | |
| 48 | 55 | } | |
| 49 | 56 | ||
| 50 | 57 | func init() { |
| ... | ... | @@ -53,12 +60,9 @@ func init() { | |
| 53 | 60 | ListCmd.Flags().StringP("scheduled", "d", "", "Filter by scheduled date (today, tomorrow, or YYYY-MM-DD)") | |
| 54 | 61 | ListCmd.Flags().Bool("all", false, "Show all tasks including completed") | |
| 55 | 62 | ListCmd.Flags().Bool("json", false, "Output as JSON") | |
| 56 | - | ||
| 57 | - | _ = ListCmd.RegisterFlagCompletionFunc("area", completion.Areas) | |
| 58 | - | _ = ListCmd.RegisterFlagCompletionFunc("status", completion.TaskStatuses) | |
| 59 | 63 | } | |
| 60 | 64 | ||
| 61 | - | func runList(cmd *cobra.Command, _ []string) error { | |
| 65 | + | func runList(cmd *cobra.Command, args []string) error { | |
| 62 | 66 | cfg, _ := config.Load() | |
| 63 | 67 | if cfg != nil && cfg.Experimental.LocalDB { | |
| 64 | 68 | _ = db.WarmCache() |
| ... | ... | @@ -85,10 +89,11 @@ func runList(cmd *cobra.Command, _ []string) error { | |
| 85 | 89 | enriched = append(enriched, enrichedTask{Task: t, Name: name}) | |
| 86 | 90 | } | |
| 87 | 91 | ||
| 88 | - | areaID, err := resolveAreaFilter(cmd) | |
| 92 | + | areaID, err := resolveAreaFilterSmart(cmd, args) | |
| 89 | 93 | if err != nil { | |
| 90 | 94 | return err | |
| 91 | 95 | } | |
| 96 | + | // ... | |
| 92 | 97 | ||
| 93 | 98 | statusFilter, err := resolveStatusFilter(cmd) | |
| 94 | 99 | if err != nil { |
| ... | ... | @@ -134,34 +139,42 @@ func mustGetBoolFlag(cmd *cobra.Command, name string) bool { | |
| 134 | 139 | return f.Value.String() == "true" | |
| 135 | 140 | } | |
| 136 | 141 | ||
| 137 | - | func resolveAreaFilter(cmd *cobra.Command) (string, error) { | |
| 138 | - | areaKey := mustGetStringFlag(cmd, "area") | |
| 142 | + | func resolveAreaFilterSmart(cmd *cobra.Command, args []string) (string, error) { | |
| 143 | + | areaInput := "" | |
| 144 | + | if len(args) > 0 { | |
| 145 | + | areaInput = args[0] | |
| 146 | + | } else { | |
| 147 | + | areaInput = mustGetStringFlag(cmd, "area") | |
| 148 | + | } | |
| 139 | 149 | ||
| 140 | - | cfg, err := config.Load() | |
| 141 | - | if err != nil { | |
| 142 | - | if errors.Is(err, config.ErrNotFound) { | |
| 143 | - | if areaKey != "" { | |
| 144 | - | return "", err | |
| 145 | - | } | |
| 150 | + | if areaInput == "" { | |
| 151 | + | cfg, err := config.Load() | |
| 152 | + | if err == nil && cfg.Defaults.Area != "" { | |
| 153 | + | areaInput = cfg.Defaults.Area | |
| 154 | + | } else { | |
| 146 | 155 | return "", nil | |
| 147 | 156 | } | |
| 148 | - | return "", err | |
| 149 | 157 | } | |
| 150 | 158 | ||
| 151 | - | if areaKey == "" { | |
| 152 | - | areaKey = cfg.Defaults.Area | |
| 159 | + | cfg, err := config.Load() | |
| 160 | + | if err == nil { | |
| 161 | + | area := cfg.AreaByKey(areaInput) | |
| 162 | + | if area != nil { | |
| 163 | + | return area.ID, nil | |
| 164 | + | } | |
| 153 | 165 | } | |
| 154 | 166 | ||
| 155 | - | if areaKey == "" { | |
| 156 | - | return "", nil | |
| 167 | + | // Try local DB (proactive) | |
| 168 | + | if id := db.FindAreaIDByName(areaInput); id != "" { | |
| 169 | + | return id, nil | |
| 157 | 170 | } | |
| 158 | 171 | ||
| 159 | - | area := cfg.AreaByKey(areaKey) | |
| 160 | - | if area == nil { | |
| 161 | - | return "", fmt.Errorf("%w: %s", ErrUnknownArea, areaKey) | |
| 172 | + | // Fallback to error if it's not a UUID | |
| 173 | + | if len(areaInput) == 36 && strings.Count(areaInput, "-") == 4 { | |
| 174 | + | return areaInput, nil | |
| 162 | 175 | } | |
| 163 | 176 | ||
| 164 | - | return area.ID, nil | |
| 177 | + | return "", fmt.Errorf("%w: %s", ErrUnknownArea, areaInput) | |
| 165 | 178 | } | |
| 166 | 179 | ||
| 167 | 180 | func resolveStatusFilter(cmd *cobra.Command) (string, error) { |
+22
-1
internal/db/reader.go
#
| ... | ... | @@ -118,7 +118,28 @@ func WarmCache() error { | |
| 118 | 118 | return nil | |
| 119 | 119 | } | |
| 120 | 120 | ||
| 121 | - | // EnrichTask attempts to find the task or note name in the cache or local database. | |
| 121 | + | // FindAreaIDByName searches for an area ID by its name in the cache. | |
| 122 | + | func FindAreaIDByName(name string) string { | |
| 123 | + | if !cacheWarmed { | |
| 124 | + | _ = WarmCache() | |
| 125 | + | } | |
| 126 | + | ||
| 127 | + | nameLower := strings.ToLower(name) | |
| 128 | + | for id, n := range nameCache { | |
| 129 | + | if strings.ToLower(n) == nameLower { | |
| 130 | + | return id | |
| 131 | + | } | |
| 132 | + | } | |
| 133 | + | // Try partial match if no exact match | |
| 134 | + | for id, n := range nameCache { | |
| 135 | + | if strings.Contains(strings.ToLower(n), nameLower) { | |
| 136 | + | return id | |
| 137 | + | } | |
| 138 | + | } | |
| 139 | + | return "" | |
| 140 | + | } | |
| 141 | + | ||
| 142 | + | // EnrichTask attempts to find the task or note name in the cache. | |
| 122 | 143 | func EnrichTask(taskID string) (string, error) { | |
| 123 | 144 | if !cacheWarmed { | |
| 124 | 145 | _ = WarmCache() |