package errors
import (
"bytes"
"fmt"
"io"
"reflect"
"strconv"
)
func FormatError (f Formatter , s fmt .State , verb rune ) {
var (
sep = " "
p = &state {State : s }
direct = true
)
var err error = f
switch verb {
case 'v' :
if s .Flag ('#' ) {
if stringer , ok := err .(fmt .GoStringer ); ok {
p .buf .WriteString (stringer .GoString ())
goto exit
}
} else if s .Flag ('+' ) {
p .printDetail = true
sep = "\n - "
}
case 's' :
case 'q' , 'x' , 'X' :
direct = false
default :
p .buf .WriteString ("%!" )
p .buf .WriteRune (verb )
p .buf .WriteByte ('(' )
switch {
case err != nil :
p .buf .WriteString (reflect .TypeOf (f ).String ())
default :
p .buf .WriteString ("<nil>" )
}
p .buf .WriteByte (')' )
_, _ = io .Copy (s , &p .buf )
return
}
loop :
for {
switch v := err .(type ) {
case Formatter :
err = v .FormatError ((*printer )(p ))
case fmt .Formatter :
v .Format (p , 'v' )
break loop
default :
_, _ = p .buf .WriteString (v .Error())
break loop
}
if err == nil {
break
}
if p .needColon || !p .printDetail {
p .buf .WriteByte (':' )
p .needColon = false
}
p .buf .WriteString (sep )
p .inDetail = false
p .needNewline = false
}
exit :
width , okW := s .Width ()
prec , okP := s .Precision ()
if !direct || (okW && width > 0 ) || okP {
format := []byte {'%' }
if s .Flag ('-' ) {
format = append (format , '-' )
}
if s .Flag ('+' ) {
format = append (format , '+' )
}
if s .Flag (' ' ) {
format = append (format , ' ' )
}
if okW {
format = strconv .AppendInt (format , int64 (width ), 10 )
}
if okP {
format = append (format , '.' )
format = strconv .AppendInt (format , int64 (prec ), 10 )
}
format = append (format , string (verb )...)
_, _ = fmt .Fprintf (s , string (format ), p .buf .String ())
} else {
_, _ = io .Copy (s , &p .buf )
}
}
var detailSep = []byte ("\n " )
type state struct {
fmt .State
buf bytes .Buffer
printDetail bool
inDetail bool
needColon bool
needNewline bool
}
func (s *state ) Write (b []byte ) (n int , err error ) {
if s .printDetail {
if len (b ) == 0 {
return 0 , nil
}
if s .inDetail && s .needColon {
s .needNewline = true
if b [0 ] == '\n' {
b = b [1 :]
}
}
k := 0
for i , c := range b {
if s .needNewline {
if s .inDetail && s .needColon {
s .buf .WriteByte (':' )
s .needColon = false
}
s .buf .Write (detailSep )
s .needNewline = false
}
if c == '\n' {
s .buf .Write (b [k :i ])
k = i + 1
s .needNewline = true
}
}
s .buf .Write (b [k :])
if !s .inDetail {
s .needColon = true
}
} else if !s .inDetail {
s .buf .Write (b )
}
return len (b ), nil
}
type printer state
func (s *printer ) Print (args ...interface {}) {
if !s .inDetail || s .printDetail {
_, _ = fmt .Fprint ((*state )(s ), args ...)
}
}
func (s *printer ) Printf (format string , args ...interface {}) {
if !s .inDetail || s .printDetail {
_, _ = fmt .Fprintf ((*state )(s ), format , args ...)
}
}
func (s *printer ) Detail () bool {
s .inDetail = true
return s .printDetail
}
The pages are generated with Golds v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds .