Skip to content

Add templating support to CLI flags list/list-all #2348

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/task/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ func run() error {
flags.ListAll,
flags.ListJson,
flags.NoStatus,
flags.Template,
)
if listOptions.ShouldListTasks() {
if flags.Silent {
Expand Down
68 changes: 55 additions & 13 deletions help.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,45 @@ import (
"context"
"encoding/json"
"fmt"
"html/template"
"io"
"os"
"path"
"strings"

"github.com/Ladicle/tabwriter"
"golang.org/x/sync/errgroup"

sprig "github.com/go-task/slim-sprig/v3"

"github.com/go-task/task/v3/internal/editors"
"github.com/go-task/task/v3/internal/fingerprint"
"github.com/go-task/task/v3/internal/logger"
"github.com/go-task/task/v3/internal/sort"
"github.com/go-task/task/v3/taskfile/ast"
)

var listDefaultTemplate = `task: Available tasks for this project:{{ range . }}
{{color "Yellow"}}* {{color "Green"}}{{ .Task }}{{color "Reset"}}:{{"\t"}} {{ .Desc | replace "\n" " " }}{{if len .Aliases}}{{color "Cyan"}}{{"\t"}}(aliases: {{.Aliases | join ", "}}){{color "Reset"}}{{end}}{{end}}
`

// ListOptions collects list-related options
type ListOptions struct {
ListOnlyTasksWithDescriptions bool
ListAllTasks bool
FormatTaskListAsJSON bool
NoStatus bool
ListTemplate string
}

// NewListOptions creates a new ListOptions instance
func NewListOptions(list, listAll, listAsJson, noStatus bool) ListOptions {
func NewListOptions(list, listAll, listAsJson, noStatus bool, template string) ListOptions {
return ListOptions{
ListOnlyTasksWithDescriptions: list,
ListAllTasks: listAll,
FormatTaskListAsJSON: listAsJson,
NoStatus: noStatus,
ListTemplate: template,
}
}

Expand Down Expand Up @@ -62,20 +72,20 @@ func (e *Executor) ListTasks(o ListOptions) (bool, error) {
if err != nil {
return false, err
}

if o.FormatTaskListAsJSON {
output, err := e.ToEditorOutput(tasks, o.NoStatus)
if err != nil {
return false, err
}

encoder := json.NewEncoder(e.Stdout)
encoder.SetIndent("", " ")
if err := encoder.Encode(output); err != nil {
return false, err
}

return len(tasks) > 0, nil
}

if len(tasks) == 0 {
if o.ListOnlyTasksWithDescriptions {
e.Logger.Outf(logger.Yellow, "task: No tasks with description available. Try --list-all to list all tasks\n")
Expand All @@ -84,19 +94,51 @@ func (e *Executor) ListTasks(o ListOptions) (bool, error) {
}
return false, nil
}
e.Logger.Outf(logger.Default, "task: Available tasks for this project:\n")

// List tasks using a template (optionally load from a file(s)).
setupTemplate := func(listTemplate string, fallback string) (tmpl *template.Template, err error) {
funcMap := template.FuncMap(sprig.TxtFuncMap())
color := func(color string) string {
if e.Logger.Color {
switch color {
case "Blue":
return "\033[34m"
case "Green":
return "\033[32m"
case "Cyan":
return "\033[36m"
case "Yellow":
return "\033[33m"
case "Magenta":
return "\033[35m"
case "Red":
return "\033[31m"
case "Reset":
return "\033[0m"
default:
return "\033[0m"
}
} else {
return ""
}
}
funcMap["color"] = color
if len(listTemplate) > 0 {
files := strings.Split(listTemplate, ",")
tmpl, err = template.New(path.Base(files[0])).Funcs(funcMap).ParseFiles(files...)
} else {
tmpl, err = template.New("list").Funcs(funcMap).Parse(fallback)
}
return
}
tmpl, err := setupTemplate(o.ListTemplate, listDefaultTemplate)
if err != nil {
return false, err
}
// Format in tab-separated columns with a tab stop of 8.
w := tabwriter.NewWriter(e.Stdout, 0, 8, 6, ' ', 0)
for _, task := range tasks {
e.Logger.FOutf(w, logger.Yellow, "* ")
e.Logger.FOutf(w, logger.Green, task.Task)
desc := strings.ReplaceAll(task.Desc, "\n", " ")
e.Logger.FOutf(w, logger.Default, ": \t%s", desc)
if len(task.Aliases) > 0 {
e.Logger.FOutf(w, logger.Cyan, "\t(aliases: %s)", strings.Join(task.Aliases, ", "))
}
_, _ = fmt.Fprint(w, "\n")
if err := tmpl.Execute(w, tasks); err != nil {
return false, err
}
if err := w.Flush(); err != nil {
return false, err
Expand Down
2 changes: 2 additions & 0 deletions internal/flags/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ var (
Color bool
Interval time.Duration
Global bool
Template string
Experiments bool
Download bool
Offline bool
Expand Down Expand Up @@ -137,6 +138,7 @@ func init() {
pflag.IntVarP(&Concurrency, "concurrency", "C", 0, "Limit number of tasks to run concurrently.")
pflag.DurationVarP(&Interval, "interval", "I", 0, "Interval to watch for changes.")
pflag.BoolVarP(&Global, "global", "g", false, "Runs global Taskfile, from $HOME/{T,t}askfile.{yml,yaml}.")
pflag.StringVar(&Template, "template", "", "Format output using a template. Select commands [list|list-all].")
pflag.BoolVar(&Experiments, "experiments", false, "Lists all the available experiments and whether or not they are enabled.")

// Gentle force experiment will override the force flag and add a new force-all flag
Expand Down