github.com/decred/politeia@v1.4.0/politeiawww/cmd/pictl/print.go (about)

     1  // Copyright (c) 2020-2021 The Decred developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package main
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"strconv"
    11  	"strings"
    12  
    13  	"github.com/decred/politeia/util"
    14  )
    15  
    16  // printf prints the provided string to stdout if the global config settings
    17  // allows for it.
    18  func printf(s string, args ...interface{}) {
    19  	switch {
    20  	case cfg.Verbose, cfg.RawJSON:
    21  		// These are handled by the politeiawwww client
    22  	case cfg.Silent:
    23  		// Do nothing
    24  	default:
    25  		// Print to stdout
    26  		fmt.Printf(s, args...)
    27  	}
    28  }
    29  
    30  // printJSON pretty prints the provided structure if the global config settings
    31  // allow for it.
    32  func printJSON(v interface{}) {
    33  	printf("%v\n", util.FormatJSON(v))
    34  }
    35  
    36  // printInPlace prints the provided text to stdout in a way that overwrites the
    37  // existing stdout text. This function can be called multiple times. Each
    38  // subsequent call will overwrite the existing text that was printed to stdout.
    39  func printInPlace(s string) {
    40  	fmt.Printf("\033[2K\r%s", s)
    41  }
    42  
    43  // addIndent adds indentation to the beginning of each line of the provided
    44  // string. The indentInSpaces argument is the number of spaces that will be
    45  // inserted into each line.
    46  //
    47  // Example: addIndent("hello,\nworld!\n", 2) -> "  hello,\n  world!\n"
    48  func addIndent(s string, indentInSpaces uint) string {
    49  	// Setup indent string
    50  	var b strings.Builder
    51  	for i := 0; i < int(indentInSpaces); i++ {
    52  		b.WriteString(" ")
    53  	}
    54  	indent := b.String()
    55  
    56  	// Add indentation after each new line
    57  	r := strings.NewReplacer("\n", "\n"+indent)
    58  	ss := r.Replace(s)
    59  
    60  	// Remove trailing spaces
    61  	ss = strings.TrimSpace(ss)
    62  
    63  	// Add indent to the first line
    64  	return indent + ss
    65  }
    66  
    67  // byteCountSI converts the provided bytes to a string representation of the
    68  // closest SI unit (kB, MB, GB, etc).
    69  func byteCountSI(b int64) string {
    70  	const unit = 1000
    71  	if b < unit {
    72  		return fmt.Sprintf("%d B", b)
    73  	}
    74  	div, exp := int64(unit), 0
    75  	for n := b / unit; n >= unit; n /= unit {
    76  		div *= unit
    77  		exp++
    78  	}
    79  	return fmt.Sprintf("%.1f %cB",
    80  		float64(b)/float64(div), "kMGTPE"[exp])
    81  }
    82  
    83  // dollars converts an int64 price in cents into a human readable dollar
    84  // string.
    85  //
    86  // | Input     | Output          |
    87  // |-----------------------------|
    88  // | 130000000 | "$1,300,000.00" |
    89  // | 13000000  | "$130,000.00"   |
    90  // | 130000    | "$1,300.00"     |
    91  // | 13000     | "$130.00"       |
    92  // | 78        | "$0.78"         |
    93  // | 9         | "$0.09"         |
    94  // | 0         | "$0.00"         |
    95  // | -9        | "-$0.09"        |
    96  // | -78       | "-$0.78"        |
    97  // | -13000000 | "-$130,000.00"  |
    98  func dollars(cents int64) string {
    99  	// Get the value in dollars.
   100  	dollars := float64(cents) / 100
   101  
   102  	// Initialize the buffer to store the string result.
   103  	var buf bytes.Buffer
   104  
   105  	// Check for a negative value.
   106  	if dollars < 0 {
   107  		buf.WriteString("-")
   108  		// Convert the negative value to a positive value.
   109  		// The code below can only handle positive values.
   110  		dollars = 0 - dollars
   111  	}
   112  	buf.WriteString("$")
   113  
   114  	// Convert the dollar value into a string and split it into a
   115  	// integer and decimal. This is done so that commas can be added
   116  	// to the integer.
   117  	var (
   118  		f       = strconv.FormatFloat(dollars, 'f', -1, 64)
   119  		s       = strings.Split(f, ".")
   120  		integer = s[0]
   121  
   122  		// The value may or may not have a decimal. Default to 0.
   123  		decimal = ".00"
   124  	)
   125  	if len(s) > 1 {
   126  		// The value includes a decimal. Overwrite the default.
   127  		decimal = "." + s[1]
   128  	}
   129  
   130  	// Write the integer to the buffer one character at a time. Commas
   131  	// are inserted in their appropriate places.
   132  	//
   133  	// Examples
   134  	// "100000" to "100,000"
   135  	// "1000000" to "1,000,000"
   136  	for i, c := range integer {
   137  		// A comma should be inserted if the character index is divisible
   138  		// by 3 when counting from the right side of the string.
   139  		divByThree := (len(integer)-i)%3 == 0
   140  
   141  		// A comma should never be inserted for the first character.
   142  		// Ex: "100000" should not be ",100,000"
   143  		if divByThree && i > 0 {
   144  			buf.WriteString(",")
   145  		}
   146  
   147  		// Write the character to the buffer.
   148  		buf.WriteRune(c)
   149  	}
   150  
   151  	// Write the decimal to the buffer.
   152  	buf.WriteString(decimal)
   153  
   154  	return buf.String()
   155  }