package repl import ( "io" "reflect" "slices" "ucl.lmika.dev/ucl" ) type CommandOpt interface { config(cmdName string, r *REPL) } type REPL struct { inst *ucl.Inst commandDocs map[string]Doc typePrinters map[reflect.Type]func(w io.Writer, v any, brief bool) error } func New(opts ...ucl.InstOption) *REPL { r := &REPL{ commandDocs: make(map[string]Doc), typePrinters: make(map[reflect.Type]func(w io.Writer, v any, brief bool) error), } instOpts := append(slices.Clone(opts), ucl.WithCustomEchoPrinter(r.echoPrinter)) r.inst = ucl.New(instOpts...) r.SetCommand("help", r.helpBuiltin, Doc{ Brief: "displays help about a command or topic", Usage: "[topic]", Args: []ArgDoc{ {Name: "topic", Brief: "topic to display"}, }, Detailed: ` When used without arguments, 'help' will display the list of known commands, along with a brief description on what each one does. If is a direct match, the contents of will be displayed. Otherwise, 'help' will list the topics names that match the given substring. `, }) AddTypePrinter(r, func(w io.Writer, t NoResults, concise bool) error { return nil }) return r } func (r *REPL) Inst() *ucl.Inst { return r.inst } func (r *REPL) SetCommand(name string, fn ucl.BuiltinHandler, opts ...CommandOpt) { r.commandDocs[name] = Doc{} for _, opt := range opts { opt.config(name, r) } r.inst.SetBuiltin(name, fn) }