...

Source file src/github.com/cli/go-gh/v2/pkg/text/text.go

Documentation: github.com/cli/go-gh/v2/pkg/text

     1  // Package text is a set of utility functions for text processing and outputting to the terminal.
     2  package text
     3  
     4  import (
     5  	"fmt"
     6  	"regexp"
     7  	"strings"
     8  	"time"
     9  	"unicode"
    10  
    11  	"github.com/charmbracelet/lipgloss"
    12  	"github.com/muesli/reflow/truncate"
    13  	"golang.org/x/text/runes"
    14  	"golang.org/x/text/transform"
    15  	"golang.org/x/text/unicode/norm"
    16  )
    17  
    18  const (
    19  	ellipsis            = "..."
    20  	minWidthForEllipsis = len(ellipsis) + 2
    21  )
    22  
    23  var indentRE = regexp.MustCompile(`(?m)^`)
    24  
    25  // Indent returns a copy of the string s with indent prefixed to it, will apply indent
    26  // to each line of the string.
    27  func Indent(s, indent string) string {
    28  	if len(strings.TrimSpace(s)) == 0 {
    29  		return s
    30  	}
    31  	return indentRE.ReplaceAllLiteralString(s, indent)
    32  }
    33  
    34  // DisplayWidth calculates what the rendered width of string s will be.
    35  func DisplayWidth(s string) int {
    36  	return lipgloss.Width(s)
    37  }
    38  
    39  // Truncate returns a copy of the string s that has been shortened to fit the maximum display width.
    40  func Truncate(maxWidth int, s string) string {
    41  	w := DisplayWidth(s)
    42  	if w <= maxWidth {
    43  		return s
    44  	}
    45  	tail := ""
    46  	if maxWidth >= minWidthForEllipsis {
    47  		tail = ellipsis
    48  	}
    49  	r := truncate.StringWithTail(s, uint(maxWidth), tail)
    50  	if DisplayWidth(r) < maxWidth {
    51  		r += " "
    52  	}
    53  	return r
    54  }
    55  
    56  // PadRight returns a copy of the string s that has been padded on the right with whitespace to fit
    57  // the maximum display width.
    58  func PadRight(maxWidth int, s string) string {
    59  	if padWidth := maxWidth - DisplayWidth(s); padWidth > 0 {
    60  		s += strings.Repeat(" ", padWidth)
    61  	}
    62  	return s
    63  }
    64  
    65  // Pluralize returns a concatenated string with num and the plural form of thing if necessary.
    66  func Pluralize(num int, thing string) string {
    67  	if num == 1 {
    68  		return fmt.Sprintf("%d %s", num, thing)
    69  	}
    70  	return fmt.Sprintf("%d %ss", num, thing)
    71  }
    72  
    73  func fmtDuration(amount int, unit string) string {
    74  	return fmt.Sprintf("about %s ago", Pluralize(amount, unit))
    75  }
    76  
    77  // RelativeTimeAgo returns a human readable string of the time duration between a and b that is estimated
    78  // to the nearest unit of time.
    79  func RelativeTimeAgo(a, b time.Time) string {
    80  	ago := a.Sub(b)
    81  
    82  	if ago < time.Minute {
    83  		return "less than a minute ago"
    84  	}
    85  	if ago < time.Hour {
    86  		return fmtDuration(int(ago.Minutes()), "minute")
    87  	}
    88  	if ago < 24*time.Hour {
    89  		return fmtDuration(int(ago.Hours()), "hour")
    90  	}
    91  	if ago < 30*24*time.Hour {
    92  		return fmtDuration(int(ago.Hours())/24, "day")
    93  	}
    94  	if ago < 365*24*time.Hour {
    95  		return fmtDuration(int(ago.Hours())/24/30, "month")
    96  	}
    97  
    98  	return fmtDuration(int(ago.Hours()/24/365), "year")
    99  }
   100  
   101  // RemoveDiacritics returns the input value without "diacritics", or accent marks.
   102  func RemoveDiacritics(value string) string {
   103  	// Mn = "Mark, nonspacing" unicode character category
   104  	removeMnTransfomer := runes.Remove(runes.In(unicode.Mn))
   105  
   106  	// 1. Decompose the text into characters and diacritical marks
   107  	// 2. Remove the diacriticals marks
   108  	// 3. Recompose the text
   109  	t := transform.Chain(norm.NFD, removeMnTransfomer, norm.NFC)
   110  	normalized, _, err := transform.String(t, value)
   111  	if err != nil {
   112  		return value
   113  	}
   114  	return normalized
   115  }
   116  

View as plain text