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.
active/core/errs/ftext/text_builder.go

288 lines
6.0 KiB

// ------------------------------------------------------------------------
// Project active2
// Active Thing (activething.com) git.activething.com/go
//
// File name text_builder.go
// Created by DEV
// Modified 22/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"
"bins/mems"
"errs/collects"
"fmt"
"strings"
)
type (
TextBuilder struct {
f *TextFormatter
b *mems.ABuffer
useAux bool
auxB *mems.ABuffer
level int
ansiC ansi.Code
invalid error
}
TextBuilderFnc func (b *TextBuilder)
)
func newTextBuilder(formatter *TextFormatter) *TextBuilder {
b := &TextBuilder{
f : formatter,
b : mems.NewABuffer(),
useAux: len(formatter.valueTrans) > 0,
ansiC : formatter.layout.AnsiC,
}
if b.useAux {
b.auxB = mems.NewABuffer()
} else {
b.auxB = b.b
}
return b
}
func (b *TextBuilder) Level () int {
return b.level }
func (b *TextBuilder) AddText (text string) {
b.b.WriteString(text) }
func (b *TextBuilder) AddTextAnsi (ansiC ansi.Code, text string) {
if b.f.HasShowAnsi() {
if ansiC == 0 {
ansiC = b.ansiC
}
b.b.WriteString(ansiC.Begin())
defer b.b.WriteString(ansiC.End())
}
b.b.WriteString(text)
}
func (b *TextBuilder) SetAnsi(ansiC ansi.Code) {
if ansiC != 0 {
b.ansiC = ansiC
} else {
b.ansiC = b.f.layout.AnsiC
}
}
func (b *TextBuilder) format (err error) {
c := collects.NewErrorCollection(err)
if c.Collect(b.f.HasAddFields(), b.f.HasAddCauses(), b.f.HasAddTrace()); c.Invalid != nil {
//b.writeFormatError(cl.Invalid)
return
}
b.write(c, 0)
}
func (b *TextBuilder) write (c *collects.ErrorCollection, level int) {
if b.invalid != nil {
return
}
ind := strings.Repeat(b.f.layout.Indent,level)
d := false
f := b.f
b.level = level
if level == 0 {
b.f.sections.Main.begin(b)
}
defer func(bl *TextBuilder, dn *bool,er error){
if !(*dn) {
if rc := recover(); rc != nil {
if er,is := rc.(error); is {
bl.invalid = er
} else {
bl.invalid = fmt.Errorf("%#v",rc)
}
bl.f.onFormatError(bl,er,bl.invalid)
}
}
}(b,&d, c.Err)
f.sections.Head.begin(b)
b.writeFieldNameValue(collects.FieldNameError, c.ErrStr, ind)
if f.HasAddTypes() {
if len(c.TypesStr) == 1 {
b.writeFieldNameValue(collects.FieldNameType, c.TypesStr[0], ind)
} else {
b.writeFieldNameValue(collects.FieldNameTypes, strings.Join(c.TypesStr, ","), ind)
}
}
f.sections.Head.end(b)
if f.HasAddFields() && c.Fields.Len() > 0 {
f.sections.Fields.begin(b)
heads := c.Fields.GetHeads()
for _,fl := range heads {
b.writeField(c.Fields,fl,ind)
}
f.sections.Fields.end(b)
}
if len(c.Causes) > 0 {
if level == 0 {
f.sections.Causes.begin(b)
}
b.level++
for _,cs := range c.Causes {
f.sections.Cause.begin(b)
b.write(&cs,level+1)
f.sections.Cause.end(b)
}
if level == 0 {
f.sections.Causes.end(b)
}
}
if c.Trace != nil {
f.sections.Trace.begin(b)
for nu,fm := range c.Trace.Frames() {
b.f.frameBuilder(b,fm,nu)
}
f.sections.Trace.end(b)
}
if level == 0 {
b.f.sections.Main.end(b)
}
d = true
}
func (b *TextBuilder) reset () {
b.b.Reset()
if b.useAux {
b.auxB.Reset()
b.useAux = false
}
b.f = nil
b.level = 0
b.invalid = nil
}
func (b *TextBuilder) writeFieldBegin (name, indent string) {
if b.ansiC != 0 {
b.b.WriteString(b.ansiC.Begin())
}
b.b.WriteString(indent)
b.b.WriteString(b.f.nameTrans.Transform(name))
b.b.WriteString(b.f.layout.FieldSep)
}
func (b *TextBuilder) writeFieldEnd () {
b.b.WriteByte('\n')
if b.ansiC != 0 {
b.b.WriteString(b.ansiC.End())
}
}
func (b *TextBuilder) writeFieldNameValue(name string, value string, indent string) {
p:= b.b.Len()
b.writeFieldBegin(name,indent)
if b.f.HasIgnoreEmpty() && len(value) == 0 {
b.b.Truncate(p)
return
}
b.b.WriteString(b.f.valueTrans.Transform(value))
b.writeFieldEnd()
}
func (b *TextBuilder) writeField (fields collects.Fields, field *collects.FieldHead, indent string) {
p := b.b.Len()
b.writeFieldBegin(field.Name,indent)
if !b.writeFieldValue(fields,field) {
b.b.Truncate(p)
return
}
b.writeFieldEnd()
}
func (b *TextBuilder) writeFieldValue (fields collects.Fields, field *collects.FieldHead) bool {
switch field.Kind {
case collects.FieldKindFloat:
b.auxB.WriteFloatStr(fields.GetFieldValueFloat(field),'f',-1)
case collects.FieldKindInt:
b.auxB.WriteIntStr(int64(fields.GetFieldValueInt(field)),10)
case collects.FieldKindString:
s := fields.GetFieldValueString(field)
if b.f.HasIgnoreEmpty() && len(s) == 0 {
return false
}
b.auxB.WriteString(fields.GetFieldValueString(field))
case collects.FieldKindTime:
b.auxB.WriteDateStr(fields.GetFieldValueDate(field), b.f.layout.TimeLayout)
case collects.FieldKindDate:
b.auxB.WriteDateStr(fields.GetFieldValueDate(field), b.f.layout.DateLayout)
case collects.FieldKindBool:
b.auxB.WriteBoolStr(fields.GetFieldValueBool(field))
default:
a := fields.GetFieldValueAny(field)
if a == nil {
if b.f.HasIgnoreEmpty() {
return false
}
b.auxB.WOQ(false,'"', g.nullValue)
} else {
s := fmt.Sprintf("%#v",a)
if b.f.HasIgnoreEmpty() && len(s) == 0 {
return false
}
b.auxB.WriteString(s)
}
}
if b.useAux {
b.b.WriteString(b.f.valueTrans.Transform(string(b.auxB.Bytes())))
b.auxB.Reset()
}
return true
}

Powered by TurnKey Linux.