github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/columns/formatter/textcolumns/textcolumns.go (about) 1 // Copyright 2022-2023 The Inspektor Gadget authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package textcolumns 16 17 import ( 18 "fmt" 19 "sort" 20 "strings" 21 22 "github.com/inspektor-gadget/inspektor-gadget/pkg/columns" 23 ) 24 25 type Column[T any] struct { 26 col *columns.Column[T] 27 calculatedWidth int 28 treatAsFixed bool 29 formatter func(*T) string 30 } 31 32 type TextColumnsFormatter[T any] struct { 33 options *Options 34 columns map[string]*Column[T] 35 currentMaxWidth int 36 showColumns []*Column[T] 37 fillString string 38 } 39 40 // NewFormatter returns a TextColumnsFormatter that will turn entries of type T into tables that can be shown 41 // on terminals or other frontends using fixed-width characters 42 func NewFormatter[T any](columns columns.ColumnMap[T], options ...Option) *TextColumnsFormatter[T] { 43 opts := DefaultOptions() 44 for _, o := range options { 45 o(opts) 46 } 47 48 formatterColumnMap := make(map[string]*Column[T]) 49 for columnName, column := range columns { 50 formatterColumnMap[columnName] = &Column[T]{ 51 col: column, 52 calculatedWidth: column.Width, 53 } 54 } 55 56 tf := &TextColumnsFormatter[T]{ 57 options: opts, 58 columns: formatterColumnMap, 59 } 60 61 for _, column := range tf.columns { 62 tf.setFormatter(column) 63 } 64 65 tf.SetShowColumns(opts.DefaultColumns) 66 67 return tf 68 } 69 70 // SetShowDefaultColumns resets the shown columns to those defined by default 71 func (tf *TextColumnsFormatter[T]) SetShowDefaultColumns() { 72 if tf.options.DefaultColumns != nil { 73 tf.SetShowColumns(tf.options.DefaultColumns) 74 return 75 } 76 newColumns := make([]*Column[T], 0) 77 for _, c := range tf.columns { 78 if !c.col.Visible { 79 continue 80 } 81 newColumns = append(newColumns, c) 82 } 83 84 // Sort using the default sort order 85 sort.Slice(newColumns, func(i, j int) bool { 86 return newColumns[i].col.Order < newColumns[j].col.Order 87 }) 88 89 tf.showColumns = newColumns 90 91 tf.rebuild() 92 } 93 94 // SetShowColumns takes a list of column names that will be displayed when using the output methods 95 // Returns an error if any of the columns is not available. 96 func (tf *TextColumnsFormatter[T]) SetShowColumns(columns []string) error { 97 if columns == nil { 98 tf.SetShowDefaultColumns() 99 return nil 100 } 101 102 newColumns := make([]*Column[T], 0) 103 for _, c := range columns { 104 column, ok := tf.columns[strings.ToLower(c)] 105 if !ok { 106 return fmt.Errorf("column %q is invalid", strings.ToLower(c)) 107 } 108 109 newColumns = append(newColumns, column) 110 } 111 tf.showColumns = newColumns 112 113 tf.rebuild() 114 115 return nil 116 } 117 118 // SetAutoScale enables or disables the AutoScale option for the formatter. This will recalculate the widths. 119 func (tf *TextColumnsFormatter[T]) SetAutoScale(enableAutoScale bool) { 120 tf.options.AutoScale = enableAutoScale 121 if enableAutoScale { 122 tf.rebuild() 123 } else { 124 // Set calculated width to configured widths 125 for _, column := range tf.columns { 126 column.calculatedWidth = column.col.Width 127 column.treatAsFixed = false 128 } 129 tf.buildFillString() 130 } 131 } 132 133 func (tf *TextColumnsFormatter[T]) rebuild() { 134 tf.buildFillString() 135 tf.currentMaxWidth = -1 // force recalculation 136 tf.AdjustWidthsToScreen() 137 }