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.
288 lines
6.0 KiB
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
|
|
}
|