You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

429 lines
7.6 KiB

// ------------------------------------------------------------------------
// Project active2
// Active Thing (activething.com) git.activething.com/go
//
// File name formatter_stae.go
// Created by DEV
// Modified 16/04/2024
//
// Copyright 2024 activething.com
// ------------------------------------------------------------------------
// 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 ftext
import (
"ansi"
"bytes"
"errors"
"errs/fmtr"
"errs/stack"
"fmt"
"reflect"
"strings"
"time"
)
type (
TextBuilder struct {
f *TextFormatter
b bytes.Buffer
numFields int
indent string
level int
ansiC ansi.Code
unwrap bool
}
TextBuilderFnc func (s *TextBuilder)
)
func newTextBuilder(formatter *TextFormatter) *TextBuilder {
return &TextBuilder{
f : formatter,
ansiC: formatter.layout.AnsiC}}
func (s *TextBuilder) Indent() string {
return s.indent }
func (s *TextBuilder) Level () int {
return s.level }
func (s *TextBuilder) Ansi () ansi.Code {
return s.ansiC }
func (s *TextBuilder) Options () Option {
return s.f.Option
}
func (s *TextBuilder) AddText (text string) {
s.b.WriteString(text) }
func (s *TextBuilder) AddTextAnsi (text string, ansiC ansi.Code) {
if s.f.ShowAnsi() {
if ansiC == 0 {
ansiC = s.ansiC
}
s.b.WriteString(ansiC.String())
defer s.b.WriteString(ansiC.End())
}
s.b.WriteString(text)
}
func (s *TextBuilder) AddFieldAny(name string, value any ) {
if value == nil && s.f.NotShowEmpty() {
return
}
s.writeField(name,fmt.Sprintf("%v",value),false)
}
func (s *TextBuilder) AddFieldInt(name string, value int ) {
s.writeField(name,fmt.Sprintf(s.f.layout.IntLayout,value),false)}
func (s *TextBuilder) AddFieldBool(name string, value bool ) {
s.writeField(name,fmt.Sprintf(s.f.layout.BoolLayout),false) }
func (s *TextBuilder) AddFieldString(name string, value string ) {
if len(value) == 0 && s.f.NotShowEmpty() {
return
}
s.writeField(name,value,false) }
func (s *TextBuilder) AddFieldFloat(name string, value float64) {
s.writeField(name,fmt.Sprintf(s.f.layout.FloatLayout,value),false) }
func (s *TextBuilder) AddFieldTime(name string, value time.Time) {
if value.IsZero() && s.f.NotShowEmpty() {
return
}
s.writeField(name,value.Format(s.f.layout.TimeLayout),false) }
func (s *TextBuilder) AddFieldDate(name string, value time.Time) {
if value.IsZero() && s.f.NotShowEmpty() {
return
}
s.writeField(name,value.Format(s.f.layout.DateLayout),false) }
func (s *TextBuilder) Build(err error, fbuilder fmtr.BuildFieldFnc) {
if err == nil {
return
}
defer func(bl *TextBuilder){
if re:=recover(); re != nil {
er,is := re.(error)
if !is {
er = fmt.Errorf("%#v",re)
}
s.f.onFormatError(bl,err,er)
}
}(s)
if !s.unwrap {
if s.level == 0 {
s.f.sections.Head.begin(s)
}
s.writeField(fmtr.FieldNameError,err.Error(),true)
if s.f.AddType() {
s.writeField(fmtr.FieldNameType, reflect.TypeOf(err).String(),true)
}
if s.level == 0 {
s.f.sections.Head.end(s)
}
}
if s.f.AddCode() {
if ec,is := err.(interface { Code() string}); is {
cd := ec.Code()
if cd != err.Error() {
s.writeField(fmtr.FieldNameCode, cd, false)
}
}
}
if fbuilder != nil {
if s.level == 0 {
s.f.sections.Fields.begin(s)
}
fbuilder(s)
}
}
func (s *TextBuilder) format (err error) {
s.f.sections.Main.begin(s)
d := false
defer func(bl *TextBuilder, dn *bool){
if !(*dn) {
if rc:= recover(); rc != nil {
er,is := rc.(error)
if !is {
er = fmt.Errorf("%#v",rc)
}
bl.f.onFormatError(bl,err,er)
}
}
s.f.sections.Main.end(bl)
}(s,&d)
var fe error
if fe = s.addError(err); fe != nil {
s.f.onFormatError(s,err,fe)
return
}
if s.numFields > 0 {
s.f.sections.Fields.end(s)
}
if s.f.AddCause() {
cl := getCauses(err)
if len(cl) > 0 {
s.f.sections.Causes.begin(s)
if fe = s.addCauses(cl); fe != nil {
s.f.onCauseError(s, err, fe)
}
s.f.sections.Causes.end(s)
}
}
if s.f.AddTrace() {
if fe = s.addTrace(err); fe != nil {
s.f.onTraceError(s,err,fe)
}
}
}
func (s *TextBuilder) addError(err error) (fe error) {
if err == nil {
return
}
dn := true
defer func (d *bool, e *error){
if !(*d) {
if re := recover(); re != nil {
if er,is := re.(error); is {
*e = er
} else {
*e = fmt.Errorf("%#v",re)
}
}
}
}(&dn,&fe)
if eb,is := err.(fmtr.Formattable); is {
eb.BuildFormat(s)
} else {
rt := reflect.TypeOf(err)
if rt.Kind() == reflect.Pointer {
rt = rt.Elem()
}
eb := fmtr.GetErrorTypeBuilder(rt)
if eb != nil {
eb.BuildError(s,err)
} else {
eb = fmtr.MakeErrorTypeBuilder(s, err)
fmtr.SetErrorTypeBuilder(rt, eb)
}
}
if s.f.AddFields() {
if ne := errors.Unwrap(err); ne != nil {
if !s.unwrap {
s.unwrap = true
defer func() {
s.unwrap = false
}()
}
if fe = s.addError(ne); fe != nil {
s.f.onFormatError(s, ne, fe)
return fe
}
}
}
dn = true
return fe
}
func (s *TextBuilder) addCauses (causes []error) (fe error) {
if len(causes) == 0 {
return
}
for _,ce := range causes {
s.incLevel()
s.f.sections.Cause.begin(s)
if fe := s.addError(ce); fe == nil {
fe = s.addCauses(getCauses(ce))
}
if fe != nil {
s.f.onCauseError(s,ce,fe)
}
s.f.sections.Cause.end(s)
s.decLevel()
if fe != nil {
return
}
}
return
}
func getCauses (err error) []error {
if err == nil {
return nil
}
ne := err
for ne != nil {
if cs, is := ne.(interface{ Cause() error }); is {
ce := cs.Cause()
if ce == nil {
return nil
}
return []error{ce}
}
if cs, is := ne.(interface{ Causes() []error }); is {
return cs.Causes()
}
if cs, is := ne.(interface{ Unwrap() []error }); is {
return cs.Unwrap()
}
ne = errors.Unwrap(ne)
}
return nil
}
func (s *TextBuilder) addTrace (err error) (fe error) {
st := stack.UnwrapTrace(err,true)
if st == nil {
return
}
dn := false
s.f.sections.Trace.begin(s)
defer func(d *bool, e *error){
if !(*d) {
if er := recover(); er != nil {
if ne, is := er.(error); is {
fe = ne
} else {
fe = fmt.Errorf("%#v", er)
}
}
}
s.f.sections.Trace.end(s)
}(&dn,&fe)
for n,f := range st.Frames() {
s.f.frameBuilder(s,f,n)
}
dn = true
return
}
func (s *TextBuilder) setAnsi(ansiC ansi.Code) {
if ansiC != 0 {
s.ansiC = ansiC
} else {
s.ansiC = s.f.layout.AnsiC
}
}
func (s *TextBuilder) writeField (name string, value string, head bool) {
if !head {
if !s.f.AddFields() {
return
}
s.numFields++
}
n := s.f.nameTrans.Transform(name)
v := s.f.valueTrans.Transform(value)
if s.ansiC != 0 {
s.b.WriteString(s.ansiC.String())
}
s.b.WriteString(s.indent)
s.b.WriteString(n)
s.b.WriteString(s.f.layout.FieldSep)
s.b.WriteString(v)
s.b.WriteByte('\n')
if s.ansiC != 0 {
s.b.WriteString(s.ansiC.String())
}
}
func (s *TextBuilder) incLevel () {
s.level++
if s.f.UseIndent() {
s.indent = strings.Repeat(s.f.layout.Indent,s.level)
}
}
func (s *TextBuilder) decLevel () {
s.level--
if s.f.UseIndent() && s.level > 0 {
s.indent = strings.Repeat(s.f.layout.Indent,s.level)
}
}

Powered by TurnKey Linux.