github.com/turbot/steampipe@v1.7.0-rc.0.0.20240517123944-7cef272d4458/pkg/control/controldisplay/dimensions.go (about)

     1  package controldisplay
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"strings"
     7  
     8  	"github.com/logrusorgru/aurora"
     9  	"github.com/turbot/go-kit/helpers"
    10  	"github.com/turbot/steampipe/pkg/control/controlexecute"
    11  )
    12  
    13  type DimensionsRenderer struct {
    14  	dimensions     []controlexecute.Dimension
    15  	colorGenerator *controlexecute.DimensionColorGenerator
    16  	width          int
    17  }
    18  
    19  func NewDimensionsRenderer(dimensions []controlexecute.Dimension, colorGenerator *controlexecute.DimensionColorGenerator, width int) *DimensionsRenderer {
    20  	return &DimensionsRenderer{
    21  		dimensions:     dimensions,
    22  		colorGenerator: colorGenerator,
    23  		width:          width,
    24  	}
    25  }
    26  
    27  // Render returns the dimensions, truncated to the max length if necessary
    28  func (r DimensionsRenderer) Render() string {
    29  	if r.width <= 0 {
    30  		// this should never happen, since the minimum width is set by the formatter
    31  		log.Printf("[WARN] dimensions renderer has width of %d\n", r.width)
    32  		return ""
    33  	}
    34  	if len(r.dimensions) == 0 {
    35  		return ""
    36  	}
    37  	// make array of dimension values (including trailing spaces
    38  	var formattedDimensions = make([]string, len(r.dimensions))
    39  	for i, d := range r.dimensions {
    40  		formattedDimensions[i] = d.Value
    41  	}
    42  
    43  	var length int
    44  	for length = dimensionsLength(formattedDimensions); length > r.width; {
    45  		// truncate the first dimension
    46  		if helpers.PrintableLength(formattedDimensions[0]) > 0 {
    47  			// truncate the original value, not the already truncated value
    48  			newLength := helpers.PrintableLength(formattedDimensions[0]) - 1
    49  			formattedDimensions[0] = helpers.TruncateString(formattedDimensions[0], newLength)
    50  		} else {
    51  			// so event with all dimensions 1 long, we still do not have enough space
    52  			// remove a dimension from the array
    53  			if len(formattedDimensions) > 2 {
    54  				r.dimensions = r.dimensions[1:]
    55  				formattedDimensions = formattedDimensions[1:]
    56  			} else {
    57  				// there is only 1 dimension - nothing we can do here, give up
    58  				return ""
    59  			}
    60  		}
    61  		// update length
    62  		length = dimensionsLength(formattedDimensions)
    63  	}
    64  
    65  	// ok we now have dimensions that fit in the space, color them
    66  	// check whether color is disabled
    67  
    68  	coloredDimensions := make([]string, 0, len(r.dimensions))
    69  	for i, v := range formattedDimensions {
    70  		// get the source dimension object
    71  		dimension := r.dimensions[i]
    72  
    73  		if len(strings.TrimSpace(dimension.Value)) == 0 {
    74  			// if the value of the dimension is empty, skip it
    75  			continue
    76  		}
    77  
    78  		// get the color code - there must be an entry
    79  		dimensionColorFunc := func(val interface{}) aurora.Value {
    80  			// if current theme supports colors, apply coloring
    81  			if ControlColors.UseColor {
    82  				dimensionColor := r.colorGenerator.Map[dimension.Key][dimension.Value]
    83  				return aurora.Index(dimensionColor, val)
    84  			}
    85  			return aurora.Reset(val)
    86  		}
    87  
    88  		coloredDimensions = append(coloredDimensions, fmt.Sprintf("%s", dimensionColorFunc(v)))
    89  	}
    90  
    91  	return strings.Join(coloredDimensions, " ")
    92  }
    93  
    94  // count the total length of the dimensions
    95  func dimensionsLength(dimensionValues []string) int {
    96  	var res int
    97  	for _, v := range dimensionValues {
    98  		res += len(v)
    99  	}
   100  	// allow for spaces between the dimensions
   101  	res += len(dimensionValues) - 1
   102  	return res
   103  }