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