github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/yaml/internal/errors/error.go (about) 1 package errors 2 3 import ( 4 "bytes" 5 "fmt" 6 7 "github.com/bingoohuang/gg/pkg/yaml/printer" 8 "github.com/bingoohuang/gg/pkg/yaml/token" 9 "golang.org/x/xerrors" 10 ) 11 12 const ( 13 defaultColorize = false 14 defaultIncludeSource = true 15 ) 16 17 var ErrDecodeRequiredPointerType = xerrors.New("required pointer type value") 18 19 // Wrapf wrap error for stack trace 20 func Wrapf(err error, msg string, args ...interface{}) error { 21 return &wrapError{ 22 baseError: &baseError{}, 23 err: xerrors.Errorf(msg, args...), 24 nextErr: err, 25 frame: xerrors.Caller(1), 26 } 27 } 28 29 // ErrSyntax create syntax error instance with message and token 30 func ErrSyntax(msg string, tk *token.Token) *syntaxError { 31 return &syntaxError{ 32 baseError: &baseError{}, 33 msg: msg, 34 token: tk, 35 frame: xerrors.Caller(1), 36 } 37 } 38 39 type baseError struct { 40 state fmt.State 41 verb rune 42 } 43 44 func (e *baseError) Error() string { 45 return "" 46 } 47 48 func (e *baseError) chainStateAndVerb(err error) { 49 wrapErr, ok := err.(*wrapError) 50 if ok { 51 wrapErr.state = e.state 52 wrapErr.verb = e.verb 53 } 54 syntaxErr, ok := err.(*syntaxError) 55 if ok { 56 syntaxErr.state = e.state 57 syntaxErr.verb = e.verb 58 } 59 } 60 61 type wrapError struct { 62 *baseError 63 err error 64 nextErr error 65 frame xerrors.Frame 66 } 67 68 type myprinter struct { 69 xerrors.Printer 70 colored bool 71 inclSource bool 72 } 73 74 func (e *wrapError) As(target interface{}) bool { 75 err := e.nextErr 76 for { 77 if wrapErr, ok := err.(*wrapError); ok { 78 err = wrapErr.nextErr 79 continue 80 } 81 break 82 } 83 return xerrors.As(err, target) 84 } 85 86 func (e *wrapError) Unwrap() error { 87 return e.nextErr 88 } 89 90 func (e *wrapError) PrettyPrint(p xerrors.Printer, colored, inclSource bool) error { 91 return e.FormatError(&myprinter{Printer: p, colored: colored, inclSource: inclSource}) 92 } 93 94 func (e *wrapError) FormatError(p xerrors.Printer) error { 95 if _, ok := p.(*myprinter); !ok { 96 p = &myprinter{ 97 Printer: p, 98 colored: defaultColorize, 99 inclSource: defaultIncludeSource, 100 } 101 } 102 if e.verb == 'v' && e.state.Flag('+') { 103 // print stack trace for debugging 104 p.Print(e.err, "\n") 105 e.frame.Format(p) 106 e.chainStateAndVerb(e.nextErr) 107 return e.nextErr 108 } 109 err := e.nextErr 110 for { 111 if wrapErr, ok := err.(*wrapError); ok { 112 err = wrapErr.nextErr 113 continue 114 } 115 break 116 } 117 e.chainStateAndVerb(err) 118 if fmtErr, ok := err.(xerrors.Formatter); ok { 119 fmtErr.FormatError(p) 120 } else { 121 p.Print(err) 122 } 123 return nil 124 } 125 126 type wrapState struct { 127 org fmt.State 128 } 129 130 func (s *wrapState) Write(b []byte) (n int, err error) { 131 return s.org.Write(b) 132 } 133 134 func (s *wrapState) Width() (wid int, ok bool) { 135 return s.org.Width() 136 } 137 138 func (s *wrapState) Precision() (prec int, ok bool) { 139 return s.org.Precision() 140 } 141 142 func (s *wrapState) Flag(c int) bool { 143 // set true to 'printDetail' forced because when p.Detail() is false, xerrors.Printer no output any text 144 if c == '#' { 145 // ignore '#' keyword because xerrors.FormatError doesn't set true to printDetail. 146 // ( see https://github.com/golang/xerrors/blob/master/adaptor.go#L39-L43 ) 147 return false 148 } 149 return true 150 } 151 152 func (e *wrapError) Format(state fmt.State, verb rune) { 153 e.state = state 154 e.verb = verb 155 xerrors.FormatError(e, &wrapState{org: state}, verb) 156 } 157 158 func (e *wrapError) Error() string { 159 var buf bytes.Buffer 160 e.PrettyPrint(&Sink{&buf}, defaultColorize, defaultIncludeSource) 161 return buf.String() 162 } 163 164 type syntaxError struct { 165 *baseError 166 msg string 167 token *token.Token 168 frame xerrors.Frame 169 } 170 171 func (e *syntaxError) PrettyPrint(p xerrors.Printer, colored, inclSource bool) error { 172 return e.FormatError(&myprinter{Printer: p, colored: colored, inclSource: inclSource}) 173 } 174 175 func (e *syntaxError) FormatError(p xerrors.Printer) error { 176 var pp printer.Printer 177 178 var colored, inclSource bool 179 if mp, ok := p.(*myprinter); ok { 180 colored = mp.colored 181 inclSource = mp.inclSource 182 } 183 184 pos := fmt.Sprintf("[%d:%d] ", e.token.Position.Line, e.token.Position.Column) 185 msg := pp.PrintErrorMessage(fmt.Sprintf("%s%s", pos, e.msg), colored) 186 if inclSource { 187 msg += "\n" + pp.PrintErrorToken(e.token, colored) 188 } 189 p.Print(msg) 190 191 if e.verb == 'v' && e.state.Flag('+') { 192 // %+v 193 // print stack trace for debugging 194 e.frame.Format(p) 195 } 196 return nil 197 } 198 199 type PrettyPrinter interface { 200 PrettyPrint(xerrors.Printer, bool, bool) error 201 } 202 type Sink struct{ *bytes.Buffer } 203 204 func (es *Sink) Print(args ...interface{}) { 205 fmt.Fprint(es.Buffer, args...) 206 } 207 208 func (es *Sink) Printf(f string, args ...interface{}) { 209 fmt.Fprintf(es.Buffer, f, args...) 210 } 211 212 func (es *Sink) Detail() bool { 213 return false 214 } 215 216 func (e *syntaxError) Error() string { 217 var buf bytes.Buffer 218 e.PrettyPrint(&Sink{&buf}, defaultColorize, defaultIncludeSource) 219 return buf.String() 220 }