/* * Copyright (c) 2023 The GoPlus Authors (goplus.org). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // Package help implements the “llgo help” command. package help import ( "bufio" "fmt" "io" "log" "os" "strings" "text/template" "unicode" "unicode/utf8" "github.com/goplus/llgo/cmd/internal/base" "github.com/goplus/llgo/internal/mockable" ) // Help implements the 'help' command. func Help(w io.Writer, args []string) { cmd := base.Llgo Args: for i, arg := range args { for _, sub := range cmd.Commands { if sub.Name() == arg { cmd = sub continue Args } } // helpSuccess is the help command using as many args as possible that would succeed. helpSuccess := "llgo help" if i > 0 { helpSuccess += " " + strings.Join(args[:i], " ") } fmt.Fprintf(os.Stderr, "llgo help %s: unknown help topic. Run '%s'.\n", strings.Join(args, " "), helpSuccess) mockable.Exit(2) } if len(cmd.Commands) > 0 { PrintUsage(w, cmd) } else { cmd.Usage(w) } // not exit 2: succeeded at 'llgo help cmd'. } var usageTemplate = `{{.Short | trim}} Usage: {{.UsageLine}} [arguments] The commands are: {{range .Commands}}{{if or (.Runnable) .Commands}} {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}} Use "llgo help{{with .LongName}} {{.}}{{end}} " for more information about a command. ` // An errWriter wraps a writer, recording whether a write error occurred. type errWriter struct { w io.Writer err error } func (w *errWriter) Write(b []byte) (int, error) { n, err := w.w.Write(b) if err != nil { w.err = err } return n, err } // tmpl executes the given template text on data, writing the result to w. func tmpl(w io.Writer, text string, data interface{}) { t := template.New("top") t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize}) template.Must(t.Parse(text)) ew := &errWriter{w: w} err := t.Execute(ew, data) if ew.err != nil { // I/O error writing. Ignore write on closed pipe. if strings.Contains(ew.err.Error(), "pipe") { mockable.Exit(1) } log.Fatalf("writing output: %v", ew.err) } if err != nil { panic(err) } } func capitalize(s string) string { if s == "" { return s } r, n := utf8.DecodeRuneInString(s) return string(unicode.ToTitle(r)) + s[n:] } // PrintUsage prints usage information. func PrintUsage(w io.Writer, cmd *base.Command) { bw := bufio.NewWriter(w) tmpl(bw, usageTemplate, cmd) bw.Flush() }