package cmd import ( "path/filepath" "github.com/spf13/cobra" "github.com/warrenronsiek/ctask/internal/config" "github.com/warrenronsiek/ctask/internal/workspace" ) // completionFilter selects which workspaces a command's tab-completion should // surface. It does not affect lookup — that's still the resolver's job — only // what the user sees as candidates while typing. type completionFilter int const ( completionActive completionFilter = iota completionArchived completionAny ) // completeWorkspaces returns a Cobra ValidArgsFunction that enumerates // workspace directory basenames matching the requested filter. Basenames are // emitted (not bare slugs) because the resolver's exact-match step accepts // basenames unambiguously, while bare slugs can collide across categories or // dates. // // On any internal error we surface ShellCompDirectiveError so the shell shows // nothing rather than a partial / misleading list. func completeWorkspaces(filter completionFilter) func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) { return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { // Only the first positional argument is a workspace name. if len(args) > 0 { return nil, cobra.ShellCompDirectiveNoFileComp } roots := config.SearchRoots() results, err := workspace.ListWorkspaces(roots, workspace.ListOpts{ IncludeArchived: filter != completionActive, }) if err != nil { return nil, cobra.ShellCompDirectiveError } var names []string for _, ws := range results { switch filter { case completionActive: if ws.Meta.Status == "archived" { continue } case completionArchived: if ws.Meta.Status != "archived" { continue } case completionAny: // no filter } names = append(names, filepath.Base(ws.Path)) } return names, cobra.ShellCompDirectiveNoFileComp } }