github.com/Code-Hex/battery@v1.0.0/battery.go (about)

     1  package battery
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"math"
     8  	"strconv"
     9  
    10  	"github.com/fatih/color"
    11  )
    12  
    13  // LENGTH: 8
    14  var chars = []string{
    15  	"▏",
    16  	"▎",
    17  	"▍",
    18  	"▌",
    19  	"▋",
    20  	"▊",
    21  	"▉",
    22  	"█",
    23  }
    24  
    25  // Icons of battery
    26  var icons = []string{
    27  	"   ",
    28  	"   ",
    29  	"   ",
    30  	"   ",
    31  	"   ",
    32  	"   ",
    33  }
    34  
    35  type Bar struct {
    36  	buffer      bytes.Buffer
    37  	gauge       string
    38  	gaugeWidth  int
    39  	width       int
    40  	nowVal      int
    41  	elapsed     int
    42  	totalVal    int
    43  	charLen     int
    44  	format      string
    45  	prefix      string
    46  	postfix     string
    47  	charge      string
    48  	ShowPercent bool
    49  	ShowCounter bool
    50  	Showthunder bool
    51  	ShowElapsed bool
    52  	ShowIcon    bool
    53  	EnableColor bool
    54  	EnableTmux  bool
    55  }
    56  
    57  func digit(num int) string {
    58  	return strconv.Itoa(int(math.Log10(float64(num))) + 1)
    59  }
    60  
    61  func New(total int) *Bar {
    62  	if total <= 0 {
    63  		panic(errors.New("Please specify total size that is greater than zero"))
    64  	}
    65  	bar := &Bar{
    66  		buffer:      bytes.Buffer{},
    67  		totalVal:    total,
    68  		nowVal:      -1,
    69  		charLen:     len(chars),
    70  		format:      "%s",
    71  		prefix:      "|",
    72  		postfix:     "|",
    73  		charge:      "ϟ",
    74  		ShowPercent: true,
    75  		ShowCounter: true,
    76  		Showthunder: false,
    77  		ShowElapsed: false,
    78  		ShowIcon:    false,
    79  		EnableColor: false,
    80  		EnableTmux:  true,
    81  	}
    82  	return bar.SetWidth(3)
    83  }
    84  
    85  func (bar *Bar) SetPrefix(char rune) *Bar {
    86  	bar.prefix = string(char)
    87  	return bar
    88  }
    89  
    90  func (bar *Bar) SetPostfix(char rune) *Bar {
    91  	bar.postfix = string(char)
    92  	return bar
    93  }
    94  
    95  func (bar *Bar) SetWidth(width int) *Bar {
    96  	bar.width = width
    97  	// +1 for postfix
    98  	bar.gaugeWidth = width + 1
    99  
   100  	return bar
   101  }
   102  
   103  func (bar *Bar) Set(percent, elapsed int) *Bar {
   104  	bar.nowVal = percent
   105  	bar.elapsed = elapsed
   106  	return bar
   107  }
   108  
   109  func (bar *Bar) Run() {
   110  	bar.writer()
   111  }
   112  
   113  func (bar *Bar) writer() {
   114  	if bar.ShowPercent {
   115  		bar.format = "%3d%%" + bar.format
   116  	}
   117  
   118  	if bar.ShowCounter {
   119  		digit := digit(bar.totalVal)
   120  		bar.format += " %" + digit + "d/%" + digit + "d"
   121  	}
   122  
   123  	if bar.ShowElapsed {
   124  		bar.format += "%s"
   125  	}
   126  
   127  	if bar.nowVal <= bar.totalVal {
   128  		bar.print()
   129  	}
   130  
   131  }
   132  
   133  func (bar *Bar) print() {
   134  	frac := float64(bar.nowVal) / float64(bar.totalVal)
   135  
   136  	if bar.Showthunder {
   137  		// append prefix
   138  		bar.gauge += bar.prefix
   139  		mid := int(math.Ceil(float64(bar.gaugeWidth / 2)))
   140  		for i := 1; i < mid; i++ {
   141  			bar.gauge += " "
   142  		}
   143  		// Middle
   144  		bar.gauge += bar.charge
   145  		for i := mid + 1; i < bar.gaugeWidth; i++ {
   146  			bar.gauge += " "
   147  		}
   148  		// append postfix
   149  		bar.gauge += bar.postfix
   150  		bar.write(frac)
   151  
   152  		return
   153  	}
   154  
   155  	if bar.ShowIcon {
   156  		// append an icon
   157  		bar.gauge += icons[bar.nowVal / 20]
   158  	} else {
   159  		barLen, fracBarLen := bar.divmod(frac)
   160  
   161  		// append prefix
   162  		bar.gauge += bar.prefix
   163  
   164  		// append full block
   165  		for i := 1; i < barLen; i++ {
   166  			bar.gauge += chars[bar.charLen-1]
   167  		}
   168  
   169  		// append lower block
   170  		bar.gauge += chars[fracBarLen]
   171  
   172  		// padding with whitespace
   173  		for i := barLen + 1; i < bar.gaugeWidth; i++ {
   174  			bar.gauge += " "
   175  		}
   176  		// append postfix
   177  		bar.gauge += bar.postfix
   178  	}
   179  
   180  	bar.write(frac)
   181  }
   182  
   183  func (bar *Bar) write(frac float64) {
   184  	var args []interface{}
   185  	percent := int(frac * 100)
   186  
   187  	if bar.ShowPercent {
   188  		args = append(args, percent)
   189  	}
   190  
   191  	args = append(args, string(bar.gauge))
   192  
   193  	if bar.ShowCounter {
   194  		args = append(args, bar.nowVal)
   195  		args = append(args, bar.totalVal)
   196  	}
   197  
   198  	if bar.ShowElapsed {
   199  		if bar.elapsed > 0 {
   200  			args = append(args, fmt.Sprintf(" %d:%02d", bar.elapsed/60, bar.elapsed%60))
   201  		} else {
   202  			args = append(args, "")
   203  		}
   204  	}
   205  
   206  	if bar.EnableColor {
   207  		if bar.EnableTmux {
   208  			bar.colorTmuxPrint(percent, args...)
   209  		} else {
   210  			bar.colorPrint(percent, args...)
   211  		}
   212  	} else {
   213  		fmt.Fprintf(&bar.buffer, bar.format, args...)
   214  	}
   215  	color.Output.Write(bar.buffer.Bytes())
   216  }
   217  
   218  func (bar *Bar) colorTmuxPrint(percent int, args ...interface{}) {
   219  	if percent >= 60 {
   220  		bar.format = "#[fg=green]" + bar.format
   221  	} else if 20 <= percent && percent < 60 {
   222  		bar.format = "#[fg=yellow]" + bar.format
   223  	} else {
   224  		bar.format = "#[fg=red]" + bar.format
   225  	}
   226  	fmt.Fprintf(&bar.buffer, bar.format+"#[default]", args...)
   227  }
   228  
   229  func (bar *Bar) colorPrint(percent int, args ...interface{}) {
   230  	if percent >= 60 {
   231  		bar.buffer.WriteString(color.GreenString(bar.format, args...))
   232  	} else if 20 <= percent && percent < 60 {
   233  		bar.buffer.WriteString(color.YellowString(bar.format, args...))
   234  	} else {
   235  		bar.buffer.WriteString(color.RedString(bar.format, args...))
   236  	}
   237  }
   238  
   239  func (bar *Bar) divmod(frac float64) (int, int) {
   240  	// Over 100%
   241  	if frac >= 1.0 {
   242  		return bar.width, bar.charLen - 1
   243  	}
   244  	pre := int(frac * float64(bar.width) * float64(bar.charLen))
   245  	return pre/bar.charLen + 1, pre % bar.charLen
   246  }