124 lines
2.9 KiB
Go
124 lines
2.9 KiB
Go
/*
|
|
* 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"
|
|
)
|
|
|
|
// 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)
|
|
os.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}} <command> [arguments]
|
|
|
|
The commands are:
|
|
{{range .Commands}}{{if or (.Runnable) .Commands}}
|
|
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
|
|
|
|
Use "llgo help{{with .LongName}} {{.}}{{end}} <command>" 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") {
|
|
os.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()
|
|
}
|