diff --git a/internal/help/help.go b/internal/help/help.go new file mode 100644 index 0000000..fb6d7f1 --- /dev/null +++ b/internal/help/help.go @@ -0,0 +1,68 @@ +package help + +import ( + "bytes" + "fmt" + "io" + "os" + "path/filepath" + + "github.com/spf13/pflag" +) + +func SetupCustomHelp() { + fs := pflag.CommandLine + fs.SortFlags = false + + pflag.Usage = func() { + name := filepath.Base(os.Args[0]) + out := fs.Output() + if out == nil { + out = os.Stderr + } + + if err := writeHelp(out, name); err != nil { + _, _ = fmt.Fprintf(os.Stderr, "failed to write help output: %v\n", err) + } + } +} + +func writeHelp(w io.Writer, name string) error { + var b bytes.Buffer + + fmt.Fprintf(&b, "%s — sleep cycle calculator\n\n", name) + b.WriteString("Usage:\n") + fmt.Fprintf(&b, " %s [mode] [options]\n\n", name) + + b.WriteString("Choose exactly one mode:\n") + b.WriteString(" -n, --now Calculate wake times from the current time\n") + b.WriteString(" -w, --wake HH:MM Calculate bedtimes for a target wake time\n") + b.WriteString(" -s, --sleep HH:MM Calculate wake times for a target sleep time\n") + b.WriteString(" -f, --from HH:MM Start of sleep window. Use together with --to\n") + b.WriteString(" -t, --to HH:MM End of sleep window. Use together with --from\n\n") + + b.WriteString("Options:\n") + b.WriteString(" -b, --buffer int Minutes to fall asleep (default: 15)\n") + b.WriteString(" -m, --cycles-min int Minimum cycles to show (default: 4)\n") + b.WriteString(" -x, --cycles-max int Maximum cycles to show (default: 6)\n\n") + + b.WriteString("Other:\n") + b.WriteString(" -g, --good-night Print random good night art\n") + b.WriteString(" -v, --version Print version\n") + b.WriteString(" -h, --help Show help\n\n") + + b.WriteString("Examples:\n") + fmt.Fprintf(&b, " %s --now\n", name) + fmt.Fprintf(&b, " %s --wake 07:00\n", name) + fmt.Fprintf(&b, " %s --sleep 22:30\n", name) + fmt.Fprintf(&b, " %s --from 22:00 --to 07:00\n", name) + fmt.Fprintf(&b, " %s --wake 07:00 --buffer 20 --cycles-min 5 --cycles-max 6\n\n", name) + + b.WriteString("Notes:\n") + b.WriteString(" - Time format is 24-hour HH:MM\n") + b.WriteString(" - Short hours like 7:00 are accepted\n") + b.WriteString(" - Modes cannot be combined\n") + + _, err := io.WriteString(w, b.String()) + return err +} diff --git a/main.go b/main.go index ee4a5a2..5a6e572 100644 --- a/main.go +++ b/main.go @@ -5,12 +5,15 @@ import ( "os" "github.com/TyostoKarry/sleepycli/internal/goodnight" + "github.com/TyostoKarry/sleepycli/internal/help" "github.com/spf13/pflag" ) const version = "0.1.0" func main() { + help.SetupCustomHelp() + var ( nowFlag bool wakeFlag string @@ -32,7 +35,7 @@ func main() { pflag.IntVarP(&bufferFlag, "buffer", "b", 15, "Fall asleep buffer in minutes") pflag.IntVarP(&cyclesMinFlag, "cycles-min", "m", 4, "Minimum cycles to show") pflag.IntVarP(&cyclesMaxFlag, "cycles-max", "x", 6, "Maximum cycles to show") - pflag.BoolVarP(&goodNightFlag, "good-night", "", false, "Display a random good night art") + pflag.BoolVarP(&goodNightFlag, "good-night", "g", false, "Display a random good night art") pflag.BoolVarP(&versionFlag, "version", "v", false, "Print version") pflag.Parse() @@ -49,6 +52,7 @@ func main() { if err := validateAndSelectMode(nowFlag, wakeFlag, sleepFlag, fromFlag, toFlag, bufferFlag, cyclesMinFlag, cyclesMaxFlag); err != nil { fmt.Fprintln(os.Stderr, "Error:", err) + fmt.Fprintln(os.Stderr, "Run 'sleepycli --help' for usage.") os.Exit(1) } }