From f57ccb885d20c48e1dae65b8ad5c46375b9a11a9 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Fri, 27 Mar 2026 11:33:33 +0200 Subject: docs: document askcli exports --- internal/askcli/completion.go | 2 ++ internal/askcli/dispatch.go | 6 ++++++ internal/askcli/formatter.go | 5 +++++ internal/askcli/task_selector.go | 2 ++ internal/askcli/taskexec.go | 3 +++ internal/askcli/taskexport.go | 2 ++ 6 files changed, 20 insertions(+) diff --git a/internal/askcli/completion.go b/internal/askcli/completion.go index 0f6c47b..b4d8620 100644 --- a/internal/askcli/completion.go +++ b/internal/askcli/completion.go @@ -85,10 +85,12 @@ func fishAddDependencyModifierCompletionContext(positional []string, current str return current == "depends" || strings.HasPrefix(current, "depends:") } +// FishCompletion returns the default Fish completion script for the ask CLI. func FishCompletion() string { return FishCompletionFor("ask") } +// FishCompletionFor returns a Fish completion script that points to the provided binary path. func FishCompletionFor(binaryPath string) string { var b strings.Builder writeFishPreamble(&b) diff --git a/internal/askcli/dispatch.go b/internal/askcli/dispatch.go index 4612555..142f7b4 100644 --- a/internal/askcli/dispatch.go +++ b/internal/askcli/dispatch.go @@ -6,15 +6,20 @@ import ( "io" ) +// Runner performs CLI work that would otherwise be handled by ask itself. +// +// The interface is implemented by the executor that ultimately proxies commands to Taskwarrior. type Runner interface { Run(ctx context.Context, args []string, stdin io.Reader, stdout, stderr io.Writer) (int, error) } +// Dispatcher translates CLI arguments into concrete subcommands and presents the output. type Dispatcher struct { runner Runner jsonOutput bool } +// NewDispatcher creates a Dispatcher backed by the provided Runner or a default executor when nil. func NewDispatcher(runner Runner) *Dispatcher { if runner == nil { e := NewExecutor("ask") @@ -36,6 +41,7 @@ func parseGlobalFlags(args []string) ([]string, bool) { return filtered, jsonOutput } +// Dispatch parses CLI arguments, handles global flags, and routes the request to the matching subcommand. func (d *Dispatcher) Dispatch(ctx context.Context, args []string, stdin io.Reader, stdout, stderr io.Writer) (int, error) { args, jsonOutput := parseGlobalFlags(args) d.jsonOutput = jsonOutput diff --git a/internal/askcli/formatter.go b/internal/askcli/formatter.go index 743637b..2327a94 100644 --- a/internal/askcli/formatter.go +++ b/internal/askcli/formatter.go @@ -9,10 +9,12 @@ import ( "codeberg.org/snonux/hexai/internal/termprint" ) +// FormatTaskList renders a table of tasks using the terminal's width when possible. func FormatTaskList(tasks []TaskExport, aliases map[string]string) string { return FormatTaskListForWidth(tasks, aliases, 0) } +// FormatTaskListForWidth renders a table of tasks constrained to the provided terminal width. func FormatTaskListForWidth(tasks []TaskExport, aliases map[string]string, terminalWidth int) string { widths := taskListWidthsFor(tasks, aliases, terminalWidth) var b strings.Builder @@ -133,6 +135,7 @@ func detectTaskListTerminalWidth(w io.Writer) int { return termprint.DetectTerminalWidth(w) } +// FormatTaskInfo builds a human-readable block describing a single task. func FormatTaskInfo(t TaskExport, alias string, dependencyAliases map[string]string) string { var b strings.Builder fmt.Fprintf(&b, "ID: %s\n", alias) @@ -160,10 +163,12 @@ func FormatTaskInfo(t TaskExport, alias string, dependencyAliases map[string]str return b.String() } +// FormatSuccess returns the success string written to stdout after a task command runs. func FormatSuccess(alias string) string { return fmt.Sprintf("ok %s\n", alias) } +// FormatError formats error output using the optional task identifier when available. func FormatError(err error, taskID string) string { if taskID != "" { return fmt.Sprintf("error %s: %v\n", taskID, err) diff --git a/internal/askcli/task_selector.go b/internal/askcli/task_selector.go index 220aa7c..82dc06f 100644 --- a/internal/askcli/task_selector.go +++ b/internal/askcli/task_selector.go @@ -137,6 +137,7 @@ func NormalizeUUID(s string) string { return strings.TrimPrefix(s, "uuid:") } +// IsNumericID reports whether the string is entirely numeric. func IsNumericID(s string) bool { if s == "" { return false @@ -149,6 +150,7 @@ func IsNumericID(s string) bool { return true } +// RejectNumericID returns the error message emitted when numeric Taskwarrior IDs are passed. func RejectNumericID() string { return "error: use a task alias ID or UUID, not a numeric Taskwarrior task ID\n" } diff --git a/internal/askcli/taskexec.go b/internal/askcli/taskexec.go index 59d9b55..b188230 100644 --- a/internal/askcli/taskexec.go +++ b/internal/askcli/taskexec.go @@ -16,6 +16,7 @@ type repoTopLevelDetector func(context.Context) (string, error) type commandRunner func(context.Context, string, []string, io.Reader, io.Writer, io.Writer) error +// Executor encapsulates how ask communicates with the Taskwarrior binary. type Executor struct { commandName string findBinary binaryFinder @@ -23,6 +24,7 @@ type Executor struct { runCommand commandRunner } +// NewExecutor constructs an Executor that invokes Taskwarrior via the given command name. func NewExecutor(commandName string) Executor { return Executor{ commandName: strings.TrimSpace(commandName), @@ -43,6 +45,7 @@ func (e Executor) taskArgs(repoRoot string, args []string) ([]string, error) { return append([]string{"rc.verbose=nothing", "rc.confirmation=off", "project:" + projectName, "+agent"}, args...), nil } +// Run delegates CLI arguments to Taskwarrior, enforcing agent defaults and error handling. func (e Executor) Run(ctx context.Context, args []string, stdin io.Reader, stdout, stderr io.Writer) (int, error) { executor := normalizeExecutor(e) taskPath, err := executor.findBinary() diff --git a/internal/askcli/taskexport.go b/internal/askcli/taskexport.go index ca67ef5..d633d3c 100644 --- a/internal/askcli/taskexport.go +++ b/internal/askcli/taskexport.go @@ -6,6 +6,7 @@ import ( "io" ) +// TaskExport mirrors the JSON structure returned by Taskwarrior export commands. type TaskExport struct { UUID string `json:"uuid"` Description string `json:"description"` @@ -21,6 +22,7 @@ type TaskExport struct { } `json:"annotations"` } +// ParseTaskExport decodes Taskwarrior JSON from the supplied reader. func ParseTaskExport(r io.Reader) ([]TaskExport, error) { data, err := io.ReadAll(r) if err != nil { -- cgit v1.2.3