...

Source file src/github.com/jedib0t/go-pretty/v6/text/align.go

Documentation: github.com/jedib0t/go-pretty/v6/text

     1  package text
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  	"strings"
     7  	"unicode/utf8"
     8  )
     9  
    10  // Align denotes how text is to be aligned horizontally.
    11  type Align int
    12  
    13  // Align enumerations
    14  const (
    15  	AlignDefault Align = iota // same as AlignLeft
    16  	AlignLeft                 // "left        "
    17  	AlignCenter               // "   center   "
    18  	AlignJustify              // "justify   it"
    19  	AlignRight                // "       right"
    20  )
    21  
    22  // Apply aligns the text as directed. For ex.:
    23  //  * AlignDefault.Apply("Jon Snow", 12) returns "Jon Snow    "
    24  //  * AlignLeft.Apply("Jon Snow",    12) returns "Jon Snow    "
    25  //  * AlignCenter.Apply("Jon Snow",  12) returns "  Jon Snow  "
    26  //  * AlignJustify.Apply("Jon Snow", 12) returns "Jon     Snow"
    27  //  * AlignRight.Apply("Jon Snow",   12) returns "    Jon Snow"
    28  func (a Align) Apply(text string, maxLength int) string {
    29  	text = a.trimString(text)
    30  	sLen := utf8.RuneCountInString(text)
    31  	sLenWoE := RuneWidthWithoutEscSequences(text)
    32  	numEscChars := sLen - sLenWoE
    33  
    34  	// now, align the text
    35  	switch a {
    36  	case AlignDefault, AlignLeft:
    37  		return fmt.Sprintf("%-"+strconv.Itoa(maxLength+numEscChars)+"s", text)
    38  	case AlignCenter:
    39  		if sLenWoE < maxLength {
    40  			// left pad with half the number of spaces needed before using %text
    41  			return fmt.Sprintf("%"+strconv.Itoa(maxLength+numEscChars)+"s",
    42  				text+strings.Repeat(" ", int((maxLength-sLenWoE)/2)))
    43  		}
    44  	case AlignJustify:
    45  		return a.justifyText(text, sLenWoE, maxLength)
    46  	}
    47  	return fmt.Sprintf("%"+strconv.Itoa(maxLength+numEscChars)+"s", text)
    48  }
    49  
    50  // HTMLProperty returns the equivalent HTML horizontal-align tag property.
    51  func (a Align) HTMLProperty() string {
    52  	switch a {
    53  	case AlignLeft:
    54  		return "align=\"left\""
    55  	case AlignCenter:
    56  		return "align=\"center\""
    57  	case AlignJustify:
    58  		return "align=\"justify\""
    59  	case AlignRight:
    60  		return "align=\"right\""
    61  	default:
    62  		return ""
    63  	}
    64  }
    65  
    66  // MarkdownProperty returns the equivalent Markdown horizontal-align separator.
    67  func (a Align) MarkdownProperty() string {
    68  	switch a {
    69  	case AlignLeft:
    70  		return ":--- "
    71  	case AlignCenter:
    72  		return ":---:"
    73  	case AlignRight:
    74  		return " ---:"
    75  	default:
    76  		return " --- "
    77  	}
    78  }
    79  
    80  func (a Align) justifyText(text string, textLength int, maxLength int) string {
    81  	// split the text into individual words
    82  	wordsUnfiltered := strings.Split(text, " ")
    83  	words := Filter(wordsUnfiltered, func(item string) bool {
    84  		return item != ""
    85  	})
    86  	// empty string implies spaces for maxLength
    87  	if len(words) == 0 {
    88  		return strings.Repeat(" ", maxLength)
    89  	}
    90  	// get the number of spaces to insert into the text
    91  	numSpacesNeeded := maxLength - textLength + strings.Count(text, " ")
    92  	numSpacesNeededBetweenWords := 0
    93  	if len(words) > 1 {
    94  		numSpacesNeededBetweenWords = numSpacesNeeded / (len(words) - 1)
    95  	}
    96  	// create the output string word by word with spaces in between
    97  	var outText strings.Builder
    98  	outText.Grow(maxLength)
    99  	for idx, word := range words {
   100  		if idx > 0 {
   101  			// insert spaces only after the first word
   102  			if idx == len(words)-1 {
   103  				// insert all the remaining space before the last word
   104  				outText.WriteString(strings.Repeat(" ", numSpacesNeeded))
   105  				numSpacesNeeded = 0
   106  			} else {
   107  				// insert the determined number of spaces between each word
   108  				outText.WriteString(strings.Repeat(" ", numSpacesNeededBetweenWords))
   109  				// and reduce the number of spaces needed after this
   110  				numSpacesNeeded -= numSpacesNeededBetweenWords
   111  			}
   112  		}
   113  		outText.WriteString(word)
   114  		if idx == len(words)-1 && numSpacesNeeded > 0 {
   115  			outText.WriteString(strings.Repeat(" ", numSpacesNeeded))
   116  		}
   117  	}
   118  	return outText.String()
   119  }
   120  
   121  func (a Align) trimString(text string) string {
   122  	switch a {
   123  	case AlignDefault, AlignLeft:
   124  		if strings.HasSuffix(text, " ") {
   125  			return strings.TrimRight(text, " ")
   126  		}
   127  	case AlignRight:
   128  		if strings.HasPrefix(text, " ") {
   129  			return strings.TrimLeft(text, " ")
   130  		}
   131  	default:
   132  		if strings.HasPrefix(text, " ") || strings.HasSuffix(text, " ") {
   133  			return strings.Trim(text, " ")
   134  		}
   135  	}
   136  	return text
   137  }
   138  

View as plain text