parent
11b8bf37cd
commit
83dad836a2
@ -0,0 +1,308 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// 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"
|
||||
"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,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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) AddText (text string) {
|
||||
s.b.WriteString(s.ansiC.String())
|
||||
s.b.WriteString(text)
|
||||
s.b.WriteString(s.ansiC.End())
|
||||
}
|
||||
|
||||
|
||||
|
||||
func (s *TextBuilder) AddFieldAny(name string, value any ) {
|
||||
if value == nil && s.f.NotShowEmpty() {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (s *TextBuilder) AddFieldInt(name string, value int ) {
|
||||
s.writeField(name,fmt.Sprintf(s.f.layouts.intLayout,value))}
|
||||
|
||||
func (s *TextBuilder) AddFieldBool(name string, value bool ) {
|
||||
s.writeField(name,fmt.Sprintf(s.f.layouts.boolLayout)) }
|
||||
|
||||
func (s *TextBuilder) AddFieldString(name string, value string ) {
|
||||
if len(value) == 0 && s.f.NotShowEmpty() {
|
||||
return
|
||||
}
|
||||
s.writeField(name,value) }
|
||||
|
||||
func (s *TextBuilder) AddFieldFloat(name string, value float64) {
|
||||
s.writeField(name,fmt.Sprintf(s.f.layouts.floatLayout,value)) }
|
||||
|
||||
func (s *TextBuilder) AddFieldTime(name string, value time.Time) {
|
||||
if value.IsZero() && s.f.NotShowEmpty() {
|
||||
return
|
||||
}
|
||||
s.writeField(name,value.Format(s.f.layouts.timeLayout)) }
|
||||
|
||||
func (s *TextBuilder) AddFieldDate(name string, value time.Time) {
|
||||
if value.IsZero() && s.f.NotShowEmpty() {
|
||||
return
|
||||
}
|
||||
s.writeField(name,value.Format(s.f.layouts.dateLayout)) }
|
||||
|
||||
|
||||
|
||||
|
||||
func (s *TextBuilder) Build(errCode, errType string, fbuilder fmtr.BuildFieldFnc) {
|
||||
if !s.unwrap {
|
||||
if s.level == 0 {
|
||||
s.f.sections.Head.begin(s)
|
||||
}
|
||||
s.writeField(fmtr.FieldNameError,errCode)
|
||||
if s.f.ShowType() {
|
||||
s.writeField(fmtr.FieldNameType, errType)
|
||||
}
|
||||
if s.level == 0 {
|
||||
s.f.sections.Head.end(s)
|
||||
}
|
||||
}
|
||||
if fbuilder != nil {
|
||||
if s.level == 0 {
|
||||
s.f.sections.Fields.begin(s)
|
||||
}
|
||||
fbuilder(s)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
func (s *TextBuilder) format (err error) (fe error) {
|
||||
|
||||
s.f.sections.Main.begin(s)
|
||||
|
||||
if fe = s.addError(err); fe != nil {
|
||||
return fe
|
||||
}
|
||||
|
||||
if s.numFields > 0 {
|
||||
s.f.sections.Fields.end(s)
|
||||
}
|
||||
|
||||
if s.f.ShowCause() {
|
||||
s.f.sections.Causes.begin(s)
|
||||
if fe = s.addCause(err); fe != nil {
|
||||
//todo
|
||||
}
|
||||
s.f.sections.Causes.end(s)
|
||||
}
|
||||
|
||||
if s.f.ShowTrace() {
|
||||
s.f.sections.Trace.begin(s)
|
||||
s.f.sections.Trace.end(s)
|
||||
}
|
||||
|
||||
s.f.sections.Main.end(s)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
func (s *TextBuilder) addError(err error) (fe error) {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if eb,is := err.(fmtr.Formattable); is {
|
||||
eb.Format(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)
|
||||
return
|
||||
}
|
||||
|
||||
eb = fmtr.MakeErrorTypeBuilder(s,err)
|
||||
fmtr.SetErrorTypeBuilder(rt,eb)
|
||||
}
|
||||
|
||||
if !s.unwrap {
|
||||
s.unwrap = true
|
||||
}
|
||||
if fe = s.addError(errors.Unwrap(err)); fe != nil {
|
||||
//todo
|
||||
return fe
|
||||
}
|
||||
|
||||
s.unwrap = false
|
||||
|
||||
return fe
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
func (s *TextBuilder) addCause(err error) (fe error) {
|
||||
ls := getCauses(err)
|
||||
for _,ce := range ls {
|
||||
s.incLevel()
|
||||
s.f.sections.Cause.begin(s)
|
||||
if fe = s.addError(ce); fe != nil {
|
||||
//todo
|
||||
continue
|
||||
}
|
||||
if fe = s.addCause(ce); fe != nil {
|
||||
//todo
|
||||
}
|
||||
s.f.sections.Cause.end(s)
|
||||
s.decLevel()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
func getCauses (err error) []error {
|
||||
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) setAnsi(ansiC ansi.Code) {
|
||||
if ansiC != 0 {
|
||||
s.ansiC = ansiC
|
||||
} else {
|
||||
s.ansiC = s.f.ansiC
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
func (s *TextBuilder) writeField (name string, value string) {
|
||||
s.numFields++
|
||||
|
||||
n := s.f.nameTrans.Apply(name)
|
||||
v := s.f.valueTrans.Apply(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.sep)
|
||||
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.ShowIndent() {
|
||||
s.indent = strings.Repeat(s.f.indent,s.level)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *TextBuilder) decLevel () {
|
||||
s.level--
|
||||
if s.f.ShowIndent() && s.level > 0 {
|
||||
s.indent = strings.Repeat(s.f.indent,s.level)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,279 +0,0 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// 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"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
state struct {
|
||||
f *Formatter
|
||||
b bytes.Buffer
|
||||
|
||||
section *Section
|
||||
level int
|
||||
ansiC ansi.Code
|
||||
unwrap bool
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
func newState(formatter *Formatter) *state {
|
||||
return &state{
|
||||
f : formatter,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func (s *state) format (err error) (fe error) {
|
||||
|
||||
if fe = s.wError(err,0); fe != nil {
|
||||
return fe
|
||||
}
|
||||
|
||||
if fe = s.wCause(err,0); fe != nil {
|
||||
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
func (s *state) wError (err error, level int) (fe error) {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if s.level != level && !s.unwrap {
|
||||
ol := s.level
|
||||
s.level = level
|
||||
defer func(){ s.level = ol }()
|
||||
}
|
||||
|
||||
if eb,is := err.(fmtr.Formattable); is {
|
||||
eb.Format(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)
|
||||
return
|
||||
}
|
||||
|
||||
eb = fmtr.MakeErrorTypeBuilder(s,err)
|
||||
fmtr.SetErrorTypeBuilder(rt,eb)
|
||||
}
|
||||
|
||||
if !s.unwrap {
|
||||
s.unwrap = true
|
||||
}
|
||||
if fe = s.wError(errors.Unwrap(err), level); fe != nil {
|
||||
|
||||
return fe
|
||||
}
|
||||
|
||||
s.unwrap = false
|
||||
|
||||
return fe
|
||||
}
|
||||
|
||||
func (s *state) wCause(err error, level int ) (fe error){
|
||||
nx := err
|
||||
for nx != nil {
|
||||
|
||||
if cs, is := nx.(interface{ Cause() error }); is {
|
||||
if ce := cs.Cause(); ce != nil {
|
||||
s.b.WriteString("-Prev Cause --------------------\n")
|
||||
if fe := s.wError(ce, level+1); fe != nil {
|
||||
// llamamos al fallback del formateador
|
||||
}
|
||||
nx = errors.Unwrap(ce)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
var lc []error
|
||||
if cs, is := nx.(interface{ Causes() []error }); is {
|
||||
lc = cs.Causes()
|
||||
} else if me, ok := nx.(interface{ Unwrap() []error }); ok {
|
||||
lc = me.Unwrap()
|
||||
}
|
||||
if len(lc) > 0 {
|
||||
for i, e := range lc {
|
||||
s.b.WriteString(fmt.Sprintf("-%d---------------\n",i))
|
||||
if fe = s.wError(e,level+1); fe != nil {
|
||||
// llamamos al fallback del formateado
|
||||
}
|
||||
if fe = s.wCause(e,level+1); fe != nil {
|
||||
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
nx = errors.Unwrap(nx)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
func getCauses (err error) []error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if cs,is := err.(interface { Cause() error }); is {
|
||||
ce := cs.Cause()
|
||||
if ce == nil {
|
||||
return nil
|
||||
}
|
||||
return []error{ce}
|
||||
}
|
||||
|
||||
if cs,is := err.(interface { Causes() []error }); is {
|
||||
return cs.Causes()
|
||||
}
|
||||
if cs,is := err.(interface{ Unwrap() []error }); is {
|
||||
return cs.Unwrap()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
func (s *state) applySection (sec *Section, begin bool) {
|
||||
if begin {
|
||||
s.section = sec
|
||||
s.section.Begin()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
func (s *state) indent () string {
|
||||
if s.level == 0 {
|
||||
return ""
|
||||
}
|
||||
return strings.Repeat(s.f.lays.indent,s.level)
|
||||
}
|
||||
|
||||
|
||||
func (s *state) Build(errCode, errType string, fbuilder fmtr.BuildFieldFnc) {
|
||||
if !s.unwrap {
|
||||
s.applySection(&s.f.secs.Head,true)
|
||||
s.writeField(fmtr.FieldNameError,errCode)
|
||||
if s.f.ShowType() {
|
||||
s.writeField(fmtr.FieldNameType, errType)
|
||||
}
|
||||
s.applySection(&s.f.secs.Head,false)
|
||||
}
|
||||
if fbuilder != nil {
|
||||
s.applySection(&s.f.secs.Fields,true)
|
||||
fbuilder(s)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func (s *state) AddAny (name string, value any ) {
|
||||
if value == nil && s.f.NotShowEmpty() {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (s *state) AddInt (name string, value int ) {
|
||||
s.writeField(name,fmt.Sprintf(s.f.lays.intLayout,value))}
|
||||
|
||||
func (s *state) AddBool (name string, value bool ) {
|
||||
s.writeField(name,fmt.Sprintf(s.f.lays.boolLayout)) }
|
||||
|
||||
func (s *state) AddString(name string, value string ) {
|
||||
if len(value) == 0 && s.f.NotShowEmpty() {
|
||||
return
|
||||
}
|
||||
s.writeField(name,value) }
|
||||
|
||||
func (s *state) AddFloat (name string, value float64) {
|
||||
s.writeField(name,fmt.Sprintf(s.f.lays.floatLayout,value)) }
|
||||
|
||||
func (s *state) AddTime (name string, value time.Time) {
|
||||
if value.IsZero() && s.f.NotShowEmpty() {
|
||||
return
|
||||
}
|
||||
s.writeField(name,value.Format(s.f.lays.timeLayout)) }
|
||||
|
||||
func (s *state) AddDate (name string, value time.Time) {
|
||||
if value.IsZero() && s.f.NotShowEmpty() {
|
||||
return
|
||||
}
|
||||
s.writeField(name,value.Format(s.f.lays.dateLayout)) }
|
||||
|
||||
|
||||
|
||||
func (s *state) writeField (name string, value string) {
|
||||
|
||||
n := s.f.nameTrans.Apply(name)
|
||||
v := s.f.valueTrans.Apply(value)
|
||||
|
||||
s.b.WriteString(s.indent())
|
||||
if s.ansiC == 0 {
|
||||
s.b.WriteString(n)
|
||||
s.b.WriteString(s.f.lays.sep)
|
||||
s.b.WriteString(v)
|
||||
s.b.WriteByte('\n')
|
||||
return
|
||||
}
|
||||
|
||||
s.b.WriteString(s.ansiC.String())
|
||||
s.b.WriteString(n)
|
||||
s.b.WriteString(s.f.lays.sep)
|
||||
s.b.WriteString(v)
|
||||
s.b.WriteByte('\n')
|
||||
s.b.WriteString(s.ansiC.End())
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in new issue