ucl/repl/docs.go
2024-12-11 21:16:08 +11:00

94 lines
1.8 KiB
Go

package repl
import (
"context"
"errors"
"fmt"
"github.com/lmika/gopkgs/fp/maps"
"os"
"sort"
"strings"
"text/tabwriter"
"ucl.lmika.dev/ucl"
"unicode"
)
type Doc struct {
Brief string
Detailed string
}
func (d Doc) config(cmdName string, r *REPL) {
r.commandDocs[cmdName] = d
}
func (r *REPL) helpBuiltin(ctx context.Context, args ucl.CallArgs) (any, error) {
switch {
case args.NArgs() == 0:
names := maps.Keys(r.commandDocs)
sort.Strings(names)
tabWriter := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0)
for _, name := range names {
cdoc := r.commandDocs[name]
if cdoc.Brief != "" {
fmt.Fprintf(tabWriter, "%v\t %v\n", name, r.commandDocs[name].Brief)
} else {
fmt.Fprintf(tabWriter, "%v\n", name)
}
}
tabWriter.Flush()
default:
var cmdName string
if err := args.Bind(&cmdName); err != nil {
return nil, err
}
docs, ok := r.commandDocs[cmdName]
if !ok {
return nil, errors.New("no help docs found for command")
}
fmt.Printf("%v\n", cmdName)
fmt.Printf(" %v\n", docs.Brief)
if docs.Detailed != "" {
fmt.Println("")
fmt.Println("Details:")
lines := strings.Split(docs.Detailed, "\n")
trimLeft := 0
if len(lines) == 0 {
return nil, nil
} else if len(strings.TrimSpace(lines[0])) == 0 && len(lines) > 1 {
// indicates that the next line should indicate the indentation
trimLeft = len(lines[1]) - len(strings.TrimLeftFunc(lines[1], unicode.IsSpace))
lines = lines[1:]
}
for _, line := range lines {
fmt.Printf(" %v\n", trimSpaceLeftUpto(line, trimLeft))
}
}
}
return NoResults{}, nil
}
func trimSpaceLeftUpto(s string, n int) string {
if n == 0 {
return s
}
for i, c := range s {
if i >= n {
return s[i:]
} else if !unicode.IsSpace(c) {
return s[i:]
}
}
return s
}