...

Source file src/github.com/jedib0t/go-pretty/v6/progress/indicator.go

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

     1  package progress
     2  
     3  import (
     4  	"strings"
     5  	"time"
     6  
     7  	"github.com/jedib0t/go-pretty/v6/text"
     8  )
     9  
    10  // IndeterminateIndicator defines the structure for the indicator to indicate
    11  // indeterminate progress. Ex.: {0, <=>}
    12  type IndeterminateIndicator struct {
    13  	Position int
    14  	Text     string
    15  }
    16  
    17  // IndeterminateIndicatorGenerator is a function that takes the maximum length
    18  // of the progress bar and returns an IndeterminateIndicator telling the
    19  // indicator string, and the location of the same in the progress bar.
    20  //
    21  // Technically, this could generate and return the entire progress bar string to
    22  // override the full display of the same - this is done by the Dominoes and
    23  // Pac-Man examples below.
    24  type IndeterminateIndicatorGenerator func(maxLen int) IndeterminateIndicator
    25  
    26  // IndeterminateIndicatorDominoes simulates a bunch of dominoes falling back and
    27  // forth.
    28  func IndeterminateIndicatorDominoes(duration time.Duration) IndeterminateIndicatorGenerator {
    29  	return timedIndeterminateIndicatorGenerator(indeterminateIndicatorDominoes(), duration)
    30  }
    31  
    32  // IndeterminateIndicatorMovingBackAndForth incrementally moves from the left to
    33  // right and back for each specified duration. If duration is 0, then every
    34  // single invocation moves the indicator.
    35  func IndeterminateIndicatorMovingBackAndForth(indicator string, duration time.Duration) IndeterminateIndicatorGenerator {
    36  	return timedIndeterminateIndicatorGenerator(indeterminateIndicatorMovingBackAndForth(indicator), duration)
    37  }
    38  
    39  // IndeterminateIndicatorMovingLeftToRight incrementally moves from the left to
    40  // right and starts from left again for each specified duration. If duration is
    41  // 0, then every single invocation moves the indicator.
    42  func IndeterminateIndicatorMovingLeftToRight(indicator string, duration time.Duration) IndeterminateIndicatorGenerator {
    43  	return timedIndeterminateIndicatorGenerator(indeterminateIndicatorMovingLeftToRight(indicator), duration)
    44  }
    45  
    46  // IndeterminateIndicatorMovingRightToLeft incrementally moves from the right to
    47  // left and starts from right again for each specified duration. If duration is
    48  // 0, then every single invocation moves the indicator.
    49  func IndeterminateIndicatorMovingRightToLeft(indicator string, duration time.Duration) IndeterminateIndicatorGenerator {
    50  	return timedIndeterminateIndicatorGenerator(indeterminateIndicatorMovingRightToLeft(indicator), duration)
    51  }
    52  
    53  // IndeterminateIndicatorPacMan simulates a Pac-Man character chomping through
    54  // the progress bar back and forth.
    55  func IndeterminateIndicatorPacMan(duration time.Duration) IndeterminateIndicatorGenerator {
    56  	return timedIndeterminateIndicatorGenerator(indeterminateIndicatorPacMan(), duration)
    57  }
    58  
    59  func indeterminateIndicatorDominoes() IndeterminateIndicatorGenerator {
    60  	direction := 1 // positive == left to right; negative == right to left
    61  	nextPosition := 0
    62  
    63  	out := strings.Builder{}
    64  	generateIndicator := func(currentPosition int, maxLen int) string {
    65  		out.Reset()
    66  		out.WriteString(strings.Repeat("/", currentPosition))
    67  		out.WriteString(strings.Repeat("\\", maxLen-currentPosition))
    68  		return out.String()
    69  	}
    70  
    71  	return func(maxLen int) IndeterminateIndicator {
    72  		currentPosition := nextPosition
    73  
    74  		if currentPosition == 0 {
    75  			direction = 1
    76  		} else if currentPosition == maxLen {
    77  			direction = -1
    78  		}
    79  		nextPosition += direction
    80  
    81  		return IndeterminateIndicator{
    82  			Position: 0,
    83  			Text:     generateIndicator(currentPosition, maxLen),
    84  		}
    85  	}
    86  }
    87  
    88  func indeterminateIndicatorMovingBackAndForth(indicator string) IndeterminateIndicatorGenerator {
    89  	direction := 1 // positive == left to right; negative == right to left
    90  	nextPosition := 0
    91  
    92  	return func(maxLen int) IndeterminateIndicator {
    93  		currentPosition := nextPosition
    94  
    95  		if currentPosition == 0 {
    96  			direction = 1
    97  		} else if currentPosition+text.RuneWidthWithoutEscSequences(indicator) == maxLen {
    98  			direction = -1
    99  		}
   100  		nextPosition += direction
   101  
   102  		return IndeterminateIndicator{
   103  			Position: currentPosition,
   104  			Text:     indicator,
   105  		}
   106  	}
   107  }
   108  
   109  func indeterminateIndicatorMovingLeftToRight(indicator string) IndeterminateIndicatorGenerator {
   110  	nextPosition := 0
   111  
   112  	return func(maxLen int) IndeterminateIndicator {
   113  		currentPosition := nextPosition
   114  
   115  		nextPosition++
   116  		if nextPosition+text.RuneWidthWithoutEscSequences(indicator) > maxLen {
   117  			nextPosition = 0
   118  		}
   119  
   120  		return IndeterminateIndicator{
   121  			Position: currentPosition,
   122  			Text:     indicator,
   123  		}
   124  	}
   125  }
   126  
   127  func indeterminateIndicatorMovingRightToLeft(indicator string) IndeterminateIndicatorGenerator {
   128  	nextPosition := -1
   129  
   130  	return func(maxLen int) IndeterminateIndicator {
   131  		if nextPosition == -1 {
   132  			nextPosition = maxLen - text.RuneWidthWithoutEscSequences(indicator)
   133  		}
   134  		currentPosition := nextPosition
   135  		nextPosition--
   136  
   137  		return IndeterminateIndicator{
   138  			Position: currentPosition,
   139  			Text:     indicator,
   140  		}
   141  	}
   142  }
   143  
   144  func indeterminateIndicatorPacMan() IndeterminateIndicatorGenerator {
   145  	pacManMovingRight, pacManMovingLeft := "ᗧ", "ᗤ"
   146  	direction := 1 // positive == left to right; negative == right to left
   147  	indicator := pacManMovingRight
   148  	nextPosition := 0
   149  
   150  	out := strings.Builder{}
   151  	generateIndicator := func(currentPosition int, maxLen int) string {
   152  		out.Reset()
   153  		if currentPosition > 0 {
   154  			out.WriteString(strings.Repeat(" ", currentPosition))
   155  		}
   156  		out.WriteString(indicator)
   157  		out.WriteString(strings.Repeat(" ", maxLen-currentPosition-1))
   158  		return out.String()
   159  	}
   160  
   161  	return func(maxLen int) IndeterminateIndicator {
   162  		currentPosition := nextPosition
   163  		currentText := generateIndicator(currentPosition, maxLen)
   164  
   165  		if currentPosition == 0 {
   166  			direction = 1
   167  			indicator = pacManMovingRight
   168  		} else if currentPosition+text.RuneWidthWithoutEscSequences(indicator) == maxLen {
   169  			direction = -1
   170  			indicator = pacManMovingLeft
   171  		}
   172  		nextPosition += direction
   173  
   174  		return IndeterminateIndicator{
   175  			Position: 0,
   176  			Text:     currentText,
   177  		}
   178  	}
   179  }
   180  
   181  // timedIndeterminateIndicatorGenerator ticks based on the given duration. If
   182  // duration is 0, it ticks for every invocation.
   183  func timedIndeterminateIndicatorGenerator(indicatorGenerator IndeterminateIndicatorGenerator, duration time.Duration) IndeterminateIndicatorGenerator {
   184  	var indeterminateIndicator *IndeterminateIndicator
   185  	lastRenderTime := time.Now()
   186  
   187  	return func(maxLen int) IndeterminateIndicator {
   188  		currRenderTime := time.Now()
   189  		if indeterminateIndicator == nil || duration == 0 || currRenderTime.Sub(lastRenderTime) > duration {
   190  			tmpIndeterminateIndicator := indicatorGenerator(maxLen)
   191  			indeterminateIndicator = &tmpIndeterminateIndicator
   192  			lastRenderTime = currRenderTime
   193  		}
   194  
   195  		return *indeterminateIndicator
   196  	}
   197  }
   198  

View as plain text