diff --git a/pkg/strategy/drift/output.go b/pkg/strategy/drift/output.go index 021b4aa31..c78875a45 100644 --- a/pkg/strategy/drift/output.go +++ b/pkg/strategy/drift/output.go @@ -7,7 +7,8 @@ import ( "unsafe" "github.com/c9s/bbgo/pkg/dynamic" - "github.com/c9s/bbgo/pkg/strategy" + "github.com/c9s/bbgo/pkg/util" + "github.com/jedib0t/go-pretty/v6/table" ) @@ -94,7 +95,7 @@ func (s *Strategy) ParamDump(f io.Writer, seriesLength ...int) { func (s *Strategy) Print(f io.Writer, pretty bool, withColor ...bool) { var style *table.Style if pretty { - style = strategy.DefaultStyle() + style = util.NewDefaultTableStyle() } - strategy.PrintConfig(s, f, style, len(withColor) > 0 && withColor[0], strategy.DefaultWhiteList()...) + util.PrintConfig(s, f, style, len(withColor) > 0 && withColor[0], util.DefaultWhiteList()...) } diff --git a/pkg/strategy/output.go b/pkg/strategy/output.go index 990fbb354..485f0fd29 100644 --- a/pkg/strategy/output.go +++ b/pkg/strategy/output.go @@ -1,140 +1,2 @@ package strategy -import ( - "fmt" - "io" - "reflect" - "sort" - "strings" - - "github.com/fatih/color" - "github.com/jedib0t/go-pretty/v6/table" - "github.com/jedib0t/go-pretty/v6/text" - - "github.com/c9s/bbgo/pkg/bbgo" - "github.com/c9s/bbgo/pkg/types" - "github.com/c9s/bbgo/pkg/util" -) - -func DefaultStyle() *table.Style { - style := table.Style{ - Name: "StyleRounded", - Box: table.StyleBoxRounded, - Format: table.FormatOptionsDefault, - HTML: table.DefaultHTMLOptions, - Options: table.OptionsDefault, - Title: table.TitleOptionsDefault, - Color: table.ColorOptionsYellowWhiteOnBlack, - } - style.Color.Row = text.Colors{text.FgHiYellow, text.BgHiBlack} - style.Color.RowAlternate = text.Colors{text.FgYellow, text.BgBlack} - return &style -} - -func DefaultWhiteList() []string { - return []string{"Window", "Interval", "Symbol"} -} - -// @param s: strategy object -// @param f: io.Writer used for writing the config dump -// @param style: pretty print table style. Use DefaultStyle() to get default one. -// @param withColor: whether to print with color -// @param whiteLists: fields to be printed out from embedded struct (1st layer only) -func PrintConfig(s interface{}, f io.Writer, style *table.Style, withColor bool, whiteLists ...string) { - t := table.NewWriter() - var write func(io.Writer, string, ...interface{}) - - if withColor { - write = color.New(color.FgHiYellow).FprintfFunc() - } else { - write = func(a io.Writer, format string, args ...interface{}) { - fmt.Fprintf(a, format, args...) - } - } - if style != nil { - t.SetOutputMirror(f) - t.SetStyle(*style) - t.SetColumnConfigs([]table.ColumnConfig{ - {Number: 4, WidthMax: 50, WidthMaxEnforcer: text.WrapText}, - }) - t.AppendHeader(table.Row{"json", "struct field name", "type", "value"}) - } - write(f, "---- %s Settings ---\n", bbgo.CallID(s)) - - embeddedWhiteSet := map[string]struct{}{} - for _, whiteList := range whiteLists { - embeddedWhiteSet[whiteList] = struct{}{} - } - - redundantSet := map[string]struct{}{} - - var rows []table.Row - - val := reflect.ValueOf(s) - - if val.Type().Kind() == util.Pointer { - val = val.Elem() - } - var values types.JsonArr - for i := 0; i < val.Type().NumField(); i++ { - t := val.Type().Field(i) - if !t.IsExported() { - continue - } - fieldName := t.Name - switch jsonTag := t.Tag.Get("json"); jsonTag { - case "-": - case "": - // we only fetch fields from the first layer of the embedded struct - if t.Anonymous { - var target reflect.Type - var field reflect.Value - if t.Type.Kind() == util.Pointer { - target = t.Type.Elem() - field = val.Field(i).Elem() - } else { - target = t.Type - field = val.Field(i) - } - for j := 0; j < target.NumField(); j++ { - tt := target.Field(j) - if !tt.IsExported() { - continue - } - fieldName := tt.Name - if _, ok := embeddedWhiteSet[fieldName]; !ok { - continue - } - if jtag := tt.Tag.Get("json"); jtag != "" && jtag != "-" { - name := strings.Split(jtag, ",")[0] - if _, ok := redundantSet[name]; ok { - continue - } - redundantSet[name] = struct{}{} - value := field.Field(j).Interface() - values = append(values, types.JsonStruct{Key: fieldName, Json: name, Type: tt.Type.String(), Value: value}) - } - } - } - default: - name := strings.Split(jsonTag, ",")[0] - if _, ok := redundantSet[name]; ok { - continue - } - redundantSet[name] = struct{}{} - values = append(values, types.JsonStruct{Key: fieldName, Json: name, Type: t.Type.String(), Value: val.Field(i).Interface()}) - } - } - sort.Sort(values) - for _, value := range values { - if style != nil { - rows = append(rows, table.Row{value.Json, value.Key, value.Type, value.Value}) - } else { - write(f, "%s: %v\n", value.Json, value.Value) - } - } - if style != nil { - t.AppendRows(rows) - t.Render() - } -} diff --git a/pkg/util/print_config.go b/pkg/util/print_config.go new file mode 100644 index 000000000..715832c51 --- /dev/null +++ b/pkg/util/print_config.go @@ -0,0 +1,139 @@ +package util + +import ( + "fmt" + "io" + "reflect" + "sort" + "strings" + + "github.com/fatih/color" + "github.com/jedib0t/go-pretty/v6/table" + "github.com/jedib0t/go-pretty/v6/text" + + "github.com/c9s/bbgo/pkg/bbgo" + "github.com/c9s/bbgo/pkg/types" +) + +func NewDefaultTableStyle() *table.Style { + style := table.Style{ + Name: "StyleRounded", + Box: table.StyleBoxRounded, + Format: table.FormatOptionsDefault, + HTML: table.DefaultHTMLOptions, + Options: table.OptionsDefault, + Title: table.TitleOptionsDefault, + Color: table.ColorOptionsYellowWhiteOnBlack, + } + style.Color.Row = text.Colors{text.FgHiYellow, text.BgHiBlack} + style.Color.RowAlternate = text.Colors{text.FgYellow, text.BgBlack} + return &style +} + +func DefaultWhiteList() []string { + return []string{"Window", "Interval", "Symbol"} +} + +// @param s: strategy object +// @param f: io.Writer used for writing the config dump +// @param style: pretty print table style. Use NewDefaultTableStyle() to get default one. +// @param withColor: whether to print with color +// @param whiteLists: fields to be printed out from embedded struct (1st layer only) +func PrintConfig(s interface{}, f io.Writer, style *table.Style, withColor bool, whiteLists ...string) { + t := table.NewWriter() + var write func(io.Writer, string, ...interface{}) + + if withColor { + write = color.New(color.FgHiYellow).FprintfFunc() + } else { + write = func(a io.Writer, format string, args ...interface{}) { + fmt.Fprintf(a, format, args...) + } + } + if style != nil { + t.SetOutputMirror(f) + t.SetStyle(*style) + t.SetColumnConfigs([]table.ColumnConfig{ + {Number: 4, WidthMax: 50, WidthMaxEnforcer: text.WrapText}, + }) + t.AppendHeader(table.Row{"json", "struct field name", "type", "value"}) + } + write(f, "---- %s Settings ---\n", bbgo.CallID(s)) + + embeddedWhiteSet := map[string]struct{}{} + for _, whiteList := range whiteLists { + embeddedWhiteSet[whiteList] = struct{}{} + } + + redundantSet := map[string]struct{}{} + + var rows []table.Row + + val := reflect.ValueOf(s) + + if val.Type().Kind() == Pointer { + val = val.Elem() + } + var values types.JsonArr + for i := 0; i < val.Type().NumField(); i++ { + t := val.Type().Field(i) + if !t.IsExported() { + continue + } + fieldName := t.Name + switch jsonTag := t.Tag.Get("json"); jsonTag { + case "-": + case "": + // we only fetch fields from the first layer of the embedded struct + if t.Anonymous { + var target reflect.Type + var field reflect.Value + if t.Type.Kind() == Pointer { + target = t.Type.Elem() + field = val.Field(i).Elem() + } else { + target = t.Type + field = val.Field(i) + } + for j := 0; j < target.NumField(); j++ { + tt := target.Field(j) + if !tt.IsExported() { + continue + } + fieldName := tt.Name + if _, ok := embeddedWhiteSet[fieldName]; !ok { + continue + } + if jtag := tt.Tag.Get("json"); jtag != "" && jtag != "-" { + name := strings.Split(jtag, ",")[0] + if _, ok := redundantSet[name]; ok { + continue + } + redundantSet[name] = struct{}{} + value := field.Field(j).Interface() + values = append(values, types.JsonStruct{Key: fieldName, Json: name, Type: tt.Type.String(), Value: value}) + } + } + } + default: + name := strings.Split(jsonTag, ",")[0] + if _, ok := redundantSet[name]; ok { + continue + } + redundantSet[name] = struct{}{} + values = append(values, types.JsonStruct{Key: fieldName, Json: name, Type: t.Type.String(), Value: val.Field(i).Interface()}) + } + } + sort.Sort(values) + for _, value := range values { + if style != nil { + rows = append(rows, table.Row{value.Json, value.Key, value.Type, value.Value}) + } else { + write(f, "%s: %v\n", value.Json, value.Value) + } + } + if style != nil { + t.AppendRows(rows) + t.Render() + } +}