adaptor.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. // Copyright 2018 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package errors
  5. import (
  6. "bytes"
  7. "fmt"
  8. "io"
  9. "reflect"
  10. "strconv"
  11. )
  12. // FormatError calls the FormatError method of f with an errors.Printer
  13. // configured according to s and verb, and writes the result to s.
  14. func FormatError(f Formatter, s fmt.State, verb rune) {
  15. // Assuming this function is only called from the Format method, and given
  16. // that FormatError takes precedence over Format, it cannot be called from
  17. // any package that supports errors.Formatter. It is therefore safe to
  18. // disregard that State may be a specific printer implementation and use one
  19. // of our choice instead.
  20. // limitations: does not support printing error as Go struct.
  21. var (
  22. sep = " " // separator before next error
  23. p = &state{State: s}
  24. direct = true
  25. )
  26. var err error = f
  27. switch verb {
  28. // Note that this switch must match the preference order
  29. // for ordinary string printing (%#v before %+v, and so on).
  30. case 'v':
  31. if s.Flag('#') {
  32. if stringer, ok := err.(fmt.GoStringer); ok {
  33. p.buf.WriteString(stringer.GoString())
  34. goto exit
  35. }
  36. // proceed as if it were %v
  37. } else if s.Flag('+') {
  38. p.printDetail = true
  39. sep = "\n - "
  40. }
  41. case 's':
  42. case 'q', 'x', 'X':
  43. // Use an intermediate buffer in the rare cases that precision,
  44. // truncation, or one of the alternative verbs (q, x, and X) are
  45. // specified.
  46. direct = false
  47. default:
  48. p.buf.WriteString("%!")
  49. p.buf.WriteRune(verb)
  50. p.buf.WriteByte('(')
  51. switch {
  52. case err != nil:
  53. p.buf.WriteString(reflect.TypeOf(f).String())
  54. default:
  55. p.buf.WriteString("<nil>")
  56. }
  57. p.buf.WriteByte(')')
  58. _, _ = io.Copy(s, &p.buf)
  59. return
  60. }
  61. loop:
  62. for {
  63. switch v := err.(type) {
  64. case Formatter:
  65. err = v.FormatError((*printer)(p))
  66. case fmt.Formatter:
  67. v.Format(p, 'v')
  68. break loop
  69. default:
  70. _, _ = p.buf.WriteString(v.Error())
  71. break loop
  72. }
  73. if err == nil {
  74. break
  75. }
  76. if p.needColon || !p.printDetail {
  77. p.buf.WriteByte(':')
  78. p.needColon = false
  79. }
  80. p.buf.WriteString(sep)
  81. p.inDetail = false
  82. p.needNewline = false
  83. }
  84. exit:
  85. width, okW := s.Width()
  86. prec, okP := s.Precision()
  87. if !direct || (okW && width > 0) || okP {
  88. // Construct format string from State s.
  89. format := []byte{'%'}
  90. if s.Flag('-') {
  91. format = append(format, '-')
  92. }
  93. if s.Flag('+') {
  94. format = append(format, '+')
  95. }
  96. if s.Flag(' ') {
  97. format = append(format, ' ')
  98. }
  99. if okW {
  100. format = strconv.AppendInt(format, int64(width), 10)
  101. }
  102. if okP {
  103. format = append(format, '.')
  104. format = strconv.AppendInt(format, int64(prec), 10)
  105. }
  106. format = append(format, string(verb)...)
  107. _, _ = fmt.Fprintf(s, string(format), p.buf.String())
  108. } else {
  109. _, _ = io.Copy(s, &p.buf)
  110. }
  111. }
  112. var detailSep = []byte("\n ")
  113. // state tracks error printing state. It implements fmt.State.
  114. type state struct {
  115. fmt.State
  116. buf bytes.Buffer
  117. printDetail bool
  118. inDetail bool
  119. needColon bool
  120. needNewline bool
  121. }
  122. func (s *state) Write(b []byte) (n int, err error) {
  123. if s.printDetail {
  124. if len(b) == 0 {
  125. return 0, nil
  126. }
  127. if s.inDetail && s.needColon {
  128. s.needNewline = true
  129. if b[0] == '\n' {
  130. b = b[1:]
  131. }
  132. }
  133. k := 0
  134. for i, c := range b {
  135. if s.needNewline {
  136. if s.inDetail && s.needColon {
  137. s.buf.WriteByte(':')
  138. s.needColon = false
  139. }
  140. s.buf.Write(detailSep)
  141. s.needNewline = false
  142. }
  143. if c == '\n' {
  144. s.buf.Write(b[k:i])
  145. k = i + 1
  146. s.needNewline = true
  147. }
  148. }
  149. s.buf.Write(b[k:])
  150. if !s.inDetail {
  151. s.needColon = true
  152. }
  153. } else if !s.inDetail {
  154. s.buf.Write(b)
  155. }
  156. return len(b), nil
  157. }
  158. // printer wraps a state to implement an xerrors.Printer.
  159. type printer state
  160. func (s *printer) Print(args ...interface{}) {
  161. if !s.inDetail || s.printDetail {
  162. _, _ = fmt.Fprint((*state)(s), args...)
  163. }
  164. }
  165. func (s *printer) Printf(format string, args ...interface{}) {
  166. if !s.inDetail || s.printDetail {
  167. _, _ = fmt.Fprintf((*state)(s), format, args...)
  168. }
  169. }
  170. func (s *printer) Detail() bool {
  171. s.inDetail = true
  172. return s.printDetail
  173. }