返回 DeepSeek-Reasonix
flag_parse.go
根目录 / internal / cli / flag_parse.go
1 package cli
2
3 import (
4 "bytes"
5 "errors"
6 "flag"
7 "fmt"
8 "io"
9 "os"
10
11 "reasonix/internal/i18n"
12
13 "github.com/spf13/pflag"
14 )
15
16 type commandFlagSet interface {
17 Output() io.Writer
18 Parse([]string) error
19 SetOutput(io.Writer)
20 }
21
22 // commandFlagError keeps parse output attached to the returned error so pure
23 // syntax parsers can defer user-facing reporting to their command boundary.
24 type commandFlagError struct {
25 err error
26 output io.Writer
27 parseOutput string
28 }
29
30 func (e *commandFlagError) Error() string { return e.err.Error() }
31 func (e *commandFlagError) Unwrap() error { return e.err }
32
33 // commandHelpRequested reports explicit help flags in the positional prefix a
34 // command validates before constructing its FlagSet. Once parsing starts, the
35 // FlagSet's ErrHelp path remains the source of truth.
36 func commandHelpRequested(args []string, positionalPrefix int) bool {
37 if positionalPrefix > len(args) {
38 positionalPrefix = len(args)
39 }
40 for _, arg := range args[:positionalPrefix] {
41 if arg == "-h" || arg == "--help" {
42 return true
43 }
44 }
45 return false
46 }
47
48 func parseCommandFlagSet(fs commandFlagSet, args []string) error {
49 output := fs.Output()
50 var parseOutput bytes.Buffer
51 fs.SetOutput(&parseOutput)
52 err := fs.Parse(args)
53 fs.SetOutput(output)
54 if err == nil {
55 return nil
56 }
57 return &commandFlagError{err: err, output: output, parseOutput: parseOutput.String()}
58 }
59
60 func reportCommandFlagError(err error) (exitCode int, handled bool) {
61 var parseErr *commandFlagError
62 if !errors.As(err, &parseErr) {
63 return 0, false
64 }
65 if errors.Is(parseErr, flag.ErrHelp) || errors.Is(parseErr, pflag.ErrHelp) {
66 _, _ = io.WriteString(os.Stdout, parseErr.parseOutput)
67 return 0, true
68 }
69 fmt.Fprintln(parseErr.output, i18n.M.ErrorPrefix, parseErr.err)
70 return 2, true
71 }
72
73 // parseCommandFlags gives standard flag and pflag commands the same public
74 // behavior: help is successful, while malformed input prints one concise error
75 // and returns the conventional command-line usage exit code.
76 func parseCommandFlags(fs commandFlagSet, args []string) (exitCode int, proceed bool) {
77 err := parseCommandFlagSet(fs, args)
78 if err == nil {
79 return 0, true
80 }
81 if code, ok := reportCommandFlagError(err); ok {
82 return code, false
83 }
84 fmt.Fprintln(fs.Output(), i18n.M.ErrorPrefix, err)
85 return 2, false
86 }
87
87 lines GO