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.

270 lines
5.0 KiB

// ------------------------------------------------------------------------
// Project active2
// Active Thing (activething.com) git.activething.com/go
//
// File name state.go
// Created by DEV
// Modified 12/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 fmx
import (
"ansi"
"bytes"
"errors"
"errs/err_fmt"
"errs/stack"
"fmt"
"reflect"
)
const (
secHead uint8 = iota
secFields
secCause
)
type (
state struct {
f *TextFmt
b bytes.Buffer
fDone bool // se ha añadido la seccion de fields
curSec uint8 // actual seccion del formato
ansi ansi.Code
}
)
func newState (f *TextFmt) *state {
return &state { f : f }}
func (s *state) reset () *state {
s.curSec = 0
s.ansi = 0
s.b.Reset()
return s
}
func (s *state) writeError(err error, addUnwrap, addCause, addTrace bool, level int) (fe error) {
d := false
defer func(st *state, dn *bool, er *error){
if !(*dn) {
if rc := recover(); fe != nil {
ec,is := rc.(error)
if !is {
ec = fmt.Errorf("%#v",rc)
}
*er = *err_fmt.NewErrBuilderFormat(ec,reflect.TypeOf(er),true)
}
}
}(s,&d,&fe)
if fe,is := err.(err_fmt.Buildable); is {
fe.Build(s)
} else {
rt := reflect.TypeOf(err)
if rt.Kind() == reflect.Pointer {
rt = rt.Elem()
}
eb := err_fmt.GetErrorTypeBuilder(rt)
if eb != nil {
eb.BuildError(s,err)
} else {
eb := err_fmt.MakeErrorTypeBuilder(s,err)
err_fmt.SetErrorTypeBuilder(rt,eb)
}
}
if addUnwrap {
return fe
}
s.writeUnwrap(err,level)
if addCause {
s.writeCause(err,level)
}
if addTrace {
s.writeTrace (err)
}
d = true
return nil
}
func (s *state) writeUnwrap(err error, level int) {
uw := errors.Unwrap(err)
for uw != nil {
if ue := s.writeError(uw,true,false,false, level); ue != nil {
// llamamos al fallback del formateador
s.AddText(s.f.fbOnUnwrap(uw))
}
uw = errors.Unwrap(uw)
}
}
func (s *state) writeCause(err error, level int ) {
if s.fDone {
s.fDone = false
s.f.sections.fields.doAfter(s)
}
nx := err
dn := false
for nx != nil {
if cs, is := err.(interface{ Cause() error }); is {
if ce := cs.Cause(); ce != nil {
if s.curSec == 1 {
s.curSec = 2
s.f.sections.cause.doBefore(s)
s.setAnsi(s.f.sections.cause.ansi)
dn = true
}
if fe := s.writeError(ce, false, true, false, level+1); fe != nil {
// llamamos al fallback del formateador
s.AddText(s.f.fbOnError(ce))
}
}
return
}
var lc []error
if cs, is := err.(interface{ Causes() []error }); is {
lc = cs.Causes()
} else if me, ok := err.(interface{ Unwrap() []error }); ok {
lc = me.Unwrap()
}
if len(lc) > 0 {
if s.curSec == 1 {
s.curSec = 2
s.setAnsi(s.f.sections.cause.ansi)
s.f.sections.cause.doBefore(s)
dn = true
}
for _, e := range lc {
if fe := s.writeError(e, false, false, false, level); fe != nil {
s.AddText(fmt.Sprintf(fbCauseError, reflect.TypeOf(e), fe.Error()))
}
}
return
}
nx = errors.Unwrap(nx)
}
if dn {
s.f.sections.cause.doAfter(s)
}
}
func (s *state) writeTrace(err error) {
if s.fDone {
s.fDone = false
s.f.sections.fields.doAfter(s)
}
tc := stack.UnwrapTrace(err,true)
if tc == nil {
return
}
s.f.sections.trace.doBefore(s)
s.setAnsi(s.f.sections.trace.ansi)
for n,f := range tc.Frames() {
s.f.frameBuilder.BuildFrame(s,f,n)
}
defer s.f.sections.trace.doAfter(s)
}
func (s *state) writeField(name, value string) {
if !s.fDone {
s.fDone = true
s.setAnsi(s.f.sections.fields.ansi)
s.f.sections.fields.doBefore(s)
}
var cv, cn ansi.Code
n := s.f.defField.NameTrans.Apply(name)
v := s.f.defField.ValueTrans.Apply(value)
if s.f.options.ShowAnsi() {
cn = s.f.defField.NameAnsi
cv = s.f.defField.ValueAnsi
}
if ff,hs := s.f.fields[name]; hs {
n = ff.NameTrans.Apply (n)
v = ff.ValueTrans.Apply(v)
if s.f.options.ShowAnsi() {
cn = ff.NameAnsi
cv = ff.ValueAnsi
}
}
s.b.WriteString(s.f.vLayouts.indent)
s.b.WriteString(cn.Sprint(n))
s.b.WriteString(cn.Sprint(s.f.vLayouts.sep))
s.b.WriteString(cv.Sprint(v))
s.b.WriteByte('\n')
}
func (s *state) writeString (str string) {
str = s.f.stringTrans.Apply(str)
s.b.WriteString(s.ansi.Sprintf(str))
}
func (s *state) setAnsi (ansi ansi.Code) {
if s.f.options.ShowAnsi() {
s.ansi = ansi
}
}

Powered by TurnKey Linux.