...

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

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

     1  package list
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"strings"
     7  	"unicode/utf8"
     8  )
     9  
    10  const (
    11  	// DefaultHTMLCSSClass stores the css-class to use when none-provided via
    12  	// SetHTMLCSSClass(cssClass string).
    13  	DefaultHTMLCSSClass = "go-pretty-table"
    14  )
    15  
    16  // listItem represents one line in the List
    17  type listItem struct {
    18  	Level int
    19  	Text  string
    20  }
    21  
    22  // List helps print a 2-dimensional array in a human readable pretty-List.
    23  type List struct {
    24  	// approxSize stores the approximate output length/size
    25  	approxSize int
    26  	// htmlCSSClass stores the HTML CSS Class to use on the <ul> node
    27  	htmlCSSClass string
    28  	// items contains the list of items to render
    29  	items []*listItem
    30  	// level stores the current indentation level
    31  	level int
    32  	// outputMirror stores an io.Writer where the "Render" functions would write
    33  	outputMirror io.Writer
    34  	// style contains all the strings used to draw the List, and more
    35  	style *Style
    36  }
    37  
    38  // AppendItem appends the item to the List of items to render.
    39  func (l *List) AppendItem(item interface{}) {
    40  	l.items = append(l.items, l.analyzeAndStringify(item))
    41  }
    42  
    43  // AppendItems appends the items to the List of items to render.
    44  func (l *List) AppendItems(items []interface{}) {
    45  	for _, item := range items {
    46  		l.AppendItem(item)
    47  	}
    48  }
    49  
    50  // Indent indents the following items to appear right-shifted.
    51  func (l *List) Indent() {
    52  	if len(l.items) == 0 {
    53  		// should not indent when there is no item in the current level
    54  	} else if l.level > l.items[len(l.items)-1].Level {
    55  		// already indented compared to previous item; do not indent more
    56  	} else {
    57  		l.level++
    58  	}
    59  }
    60  
    61  // Length returns the number of items to be rendered.
    62  func (l *List) Length() int {
    63  	return len(l.items)
    64  }
    65  
    66  // Reset sets the List to its initial state.
    67  func (l *List) Reset() {
    68  	l.approxSize = 0
    69  	l.items = make([]*listItem, 0)
    70  	l.level = 0
    71  	l.style = nil
    72  }
    73  
    74  // SetHTMLCSSClass sets the the HTML CSS Class to use on the <ul> node
    75  // when rendering the List in HTML format. Recursive lists would use a numbered
    76  // index suffix. For ex., if the cssClass is set as "foo"; the <ul> for level 0
    77  // would have the class set as "foo"; the <ul> for level 1 would have "foo-1".
    78  func (l *List) SetHTMLCSSClass(cssClass string) {
    79  	l.htmlCSSClass = cssClass
    80  }
    81  
    82  // SetOutputMirror sets an io.Writer for all the Render functions to "Write" to
    83  // in addition to returning a string.
    84  func (l *List) SetOutputMirror(mirror io.Writer) {
    85  	l.outputMirror = mirror
    86  }
    87  
    88  // SetStyle overrides the DefaultStyle with the provided one.
    89  func (l *List) SetStyle(style Style) {
    90  	l.style = &style
    91  }
    92  
    93  // Style returns the current style.
    94  func (l *List) Style() *Style {
    95  	if l.style == nil {
    96  		tempStyle := StyleDefault
    97  		l.style = &tempStyle
    98  	}
    99  	return l.style
   100  }
   101  
   102  func (l *List) analyzeAndStringify(item interface{}) *listItem {
   103  	itemStr := fmt.Sprint(item)
   104  	if strings.Contains(itemStr, "\t") {
   105  		itemStr = strings.Replace(itemStr, "\t", "    ", -1)
   106  	}
   107  	if strings.Contains(itemStr, "\r") {
   108  		itemStr = strings.Replace(itemStr, "\r", "", -1)
   109  	}
   110  	return &listItem{
   111  		Level: l.level,
   112  		Text:  itemStr,
   113  	}
   114  }
   115  
   116  // UnIndent un-indents the following items to appear left-shifted.
   117  func (l *List) UnIndent() {
   118  	if l.level > 0 {
   119  		l.level--
   120  	}
   121  }
   122  
   123  func (l *List) UnIndentAll() {
   124  	l.level = 0
   125  }
   126  
   127  func (l *List) initForRender() {
   128  	// pick a default style
   129  	l.Style()
   130  
   131  	// calculate the approximate size needed by looking at all entries
   132  	l.approxSize = 0
   133  	for _, item := range l.items {
   134  		// account for the following when incrementing approxSize:
   135  		// 1. prefix, 2. padding, 3. bullet, 4. text, 5. newline
   136  		l.approxSize += utf8.RuneCountInString(l.style.LinePrefix)
   137  		if item.Level > 0 {
   138  			l.approxSize += utf8.RuneCountInString(l.style.CharItemVertical) * item.Level
   139  		}
   140  		l.approxSize += utf8.RuneCountInString(l.style.CharItemVertical)
   141  		l.approxSize += utf8.RuneCountInString(item.Text)
   142  		l.approxSize += utf8.RuneCountInString(l.style.CharNewline)
   143  	}
   144  
   145  	// default to a HTML CSS Class if none-defined
   146  	if l.htmlCSSClass == "" {
   147  		l.htmlCSSClass = DefaultHTMLCSSClass
   148  	}
   149  }
   150  
   151  func (l *List) hasMoreItemsInLevel(levelIdx int, fromItemIdx int) bool {
   152  	for idx := fromItemIdx + 1; idx >= 0 && idx < len(l.items); idx++ {
   153  		if l.items[idx].Level < levelIdx {
   154  			return false
   155  		} else if l.items[idx].Level == levelIdx {
   156  			return true
   157  		}
   158  	}
   159  	return false
   160  }
   161  
   162  func (l *List) render(out *strings.Builder) string {
   163  	outStr := out.String()
   164  	if l.outputMirror != nil && len(outStr) > 0 {
   165  		l.outputMirror.Write([]byte(outStr))
   166  		l.outputMirror.Write([]byte("\n"))
   167  	}
   168  	return outStr
   169  }
   170  
   171  // renderHint has hints for the Render*() logic
   172  type renderHint struct {
   173  	isTopItem    bool
   174  	isFirstItem  bool
   175  	isOnlyItem   bool
   176  	isLastItem   bool
   177  	isBottomItem bool
   178  }
   179  

View as plain text