Store ListItem text as []byte instead of string

This commit is contained in:
Trevor Slocum 2020-10-06 18:19:40 -07:00
parent 96b2dd5523
commit d5edb975b6
7 changed files with 65 additions and 40 deletions

View File

@ -154,7 +154,7 @@ func (c *ContextMenu) show(item int, x int, y int, setFocus func(Primitive)) {
if c.selected != nil {
c.l.Unlock()
c.selected(index, item.mainText, item.shortcut)
c.selected(index, string(item.mainText), item.shortcut)
} else {
c.l.Unlock()
}

View File

@ -1,8 +1,8 @@
package main
import (
"bytes"
"fmt"
"strings"
"github.com/gdamore/tcell/v2"
"gitlab.com/tslocum/cview"
@ -251,8 +251,8 @@ const tableSelectCell = `[green]func[white] [yellow]main[white]() {
func Table(nextSlide func()) (title string, content cview.Primitive) {
table := cview.NewTable().
SetFixed(1, 1)
for row, line := range bytes.Split([]byte(tableData), []byte("\n")) {
for column, cell := range bytes.Split(line, []byte("|")) {
for row, line := range strings.Split(tableData, "\n") {
for column, cell := range strings.Split(line, "|") {
color := tcell.ColorWhite.TrueColor()
if row == 0 {
color = tcell.ColorYellow.TrueColor()

View File

@ -2,7 +2,7 @@
package main
import (
"bytes"
"strings"
"github.com/gdamore/tcell/v2"
"gitlab.com/tslocum/cview"
@ -14,7 +14,7 @@ func main() {
app := cview.NewApplication()
table := cview.NewTable().
SetBorders(true)
lorem := bytes.Split([]byte(loremIpsumText), []byte(" "))
lorem := strings.Split(loremIpsumText, " ")
cols, rows := 10, 40
word := 0
for r := 0; r < rows; r++ {

View File

@ -488,7 +488,7 @@ func (i *InputField) Autocomplete() *InputField {
for index, entry := range entries {
entry.enabled = true
i.autocompleteList.AddItem(entry)
if currentEntry < 0 && entry.mainText == i.text {
if currentEntry < 0 && entry.GetMainText() == i.text {
currentEntry = index
}
}
@ -505,10 +505,12 @@ func (i *InputField) Autocomplete() *InputField {
// autocompleteChanged gets called when another item in the
// autocomplete list has been selected.
func (i *InputField) autocompleteChanged(_ int, item *ListItem) {
if len(item.secondaryText) > 0 && len(i.text) < len(item.secondaryText) {
i.autocompleteListSuggestion = item.secondaryText[len(i.text):]
} else if len(item.mainText) > len(i.text)+1 {
i.autocompleteListSuggestion = item.mainText[len(i.text)+1:]
mainText := item.GetMainText()
secondaryText := item.GetSecondaryText()
if len(secondaryText) > 0 && len(i.text) < len(secondaryText) {
i.autocompleteListSuggestion = secondaryText[len(i.text):]
} else if len(mainText) > len(i.text)+1 {
i.autocompleteListSuggestion = mainText[len(i.text)+1:]
} else {
i.autocompleteListSuggestion = ""
}
@ -879,9 +881,9 @@ func (i *InputField) InputHandler() func(event *tcell.EventKey, setFocus func(p
case tcell.KeyEnter: // We might be done.
if i.autocompleteList != nil {
currentItem := i.autocompleteList.GetCurrentItem()
selectionText := currentItem.mainText
if currentItem.secondaryText != "" {
selectionText = currentItem.secondaryText
selectionText := currentItem.GetMainText()
if currentItem.GetSecondaryText() != "" {
selectionText = currentItem.GetSecondaryText()
}
i.Unlock()
i.SetText(selectionText)

67
list.go
View File

@ -12,8 +12,8 @@ import (
// ListItem represents an item in a List.
type ListItem struct {
enabled bool // Whether or not the list item is selectable.
mainText string // The main text of the list item.
secondaryText string // A secondary text to be shown underneath the main text.
mainText []byte // The main text of the list item.
secondaryText []byte // A secondary text to be shown underneath the main text.
shortcut rune // The key to select the list item directly, 0 if there is no shortcut.
selected func() // The optional function which is called when the item is selected.
reference interface{} // An optional reference object.
@ -24,13 +24,13 @@ type ListItem struct {
// NewListItem returns a new item for a list.
func NewListItem(mainText string) *ListItem {
return &ListItem{
mainText: mainText,
mainText: []byte(mainText),
enabled: true,
}
}
// SetMainText sets the main text of the list item.
func (l *ListItem) SetMainText(val string) *ListItem {
// SetMainBytes sets the main text of the list item.
func (l *ListItem) SetMainBytes(val []byte) *ListItem {
l.Lock()
defer l.Unlock()
@ -38,16 +38,26 @@ func (l *ListItem) SetMainText(val string) *ListItem {
return l
}
// GetMainText returns the item's main text.
func (l *ListItem) GetMainText() string {
// SetMainText sets the main text of the list item.
func (l *ListItem) SetMainText(val string) *ListItem {
return l.SetMainBytes([]byte(val))
}
// GetMainBytes returns the item's main text.
func (l *ListItem) GetMainBytes() []byte {
l.RLock()
defer l.RUnlock()
return l.mainText
}
// SetSecondaryText sets a secondary text to be shown underneath the main text.
func (l *ListItem) SetSecondaryText(val string) *ListItem {
// GetMainText returns the item's main text.
func (l *ListItem) GetMainText() string {
return string(l.GetMainBytes())
}
// SetSecondaryBytes sets a secondary text to be shown underneath the main text.
func (l *ListItem) SetSecondaryBytes(val []byte) *ListItem {
l.Lock()
defer l.Unlock()
@ -55,14 +65,24 @@ func (l *ListItem) SetSecondaryText(val string) *ListItem {
return l
}
// GetSecondaryText returns the item's secondary text.
func (l *ListItem) GetSecondaryText() string {
// SetSecondaryText sets a secondary text to be shown underneath the main text.
func (l *ListItem) SetSecondaryText(val string) *ListItem {
return l.SetSecondaryBytes([]byte(val))
}
// GetSecondaryBytes returns the item's secondary text.
func (l *ListItem) GetSecondaryBytes() []byte {
l.RLock()
defer l.RUnlock()
return l.secondaryText
}
// GetSecondaryText returns the item's secondary text.
func (l *ListItem) GetSecondaryText() string {
return string(l.GetSecondaryBytes())
}
// SetShortcut sets the key to select the ListItem directly, 0 if there is no shortcut.
func (l *ListItem) SetShortcut(val rune) *ListItem {
l.Lock()
@ -612,7 +632,7 @@ func (l *List) GetItemCount() int {
func (l *List) GetItemText(index int) (main, secondary string) {
l.RLock()
defer l.RUnlock()
return l.items[index].mainText, l.items[index].secondaryText
return string(l.items[index].mainText), string(l.items[index].secondaryText)
}
// SetItemText sets an item's main and secondary text. Panics if the index is
@ -622,8 +642,8 @@ func (l *List) SetItemText(index int, main, secondary string) *List {
defer l.Unlock()
item := l.items[index]
item.mainText = main
item.secondaryText = secondary
item.mainText = []byte(main)
item.secondaryText = []byte(secondary)
return l
}
@ -661,19 +681,22 @@ func (l *List) FindItems(mainSearch, secondarySearch string, mustContainBoth, ig
secondarySearch = strings.ToLower(secondarySearch)
}
mainSearchBytes := []byte(mainSearch)
secondarySearchBytes := []byte(secondarySearch)
for index, item := range l.items {
mainText := item.mainText
secondaryText := item.secondaryText
if ignoreCase {
mainText = strings.ToLower(mainText)
secondaryText = strings.ToLower(secondaryText)
mainText = bytes.ToLower(mainText)
secondaryText = bytes.ToLower(secondaryText)
}
// strings.Contains() always returns true for a "" search.
mainContained := strings.Contains(mainText, mainSearch)
secondaryContained := strings.Contains(secondaryText, secondarySearch)
mainContained := bytes.Contains(mainText, mainSearchBytes)
secondaryContained := bytes.Contains(secondaryText, secondarySearchBytes)
if mustContainBoth && mainContained && secondaryContained ||
!mustContainBoth && (mainText != "" && mainContained || secondaryText != "" && secondaryContained) {
!mustContainBoth && (len(mainText) > 0 && mainContained || len(secondaryText) > 0 && secondaryContained) {
indices = append(indices, index)
}
}
@ -871,7 +894,7 @@ func (l *List) Draw(screen tcell.Screen) {
break
}
if item.mainText == "" && item.secondaryText == "" && item.shortcut == 0 { // Divider
if len(item.mainText) == 0 && len(item.secondaryText) == 0 && item.shortcut == 0 { // Divider
Print(screen, []byte(string(tcell.RuneLTee)), (x-5)-l.paddingLeft, y, 1, AlignLeft, l.mainTextColor)
Print(screen, bytes.Repeat([]byte(string(tcell.RuneHLine)), width+4+l.paddingLeft+l.paddingRight), (x-4)-l.paddingLeft, y, width+4+l.paddingLeft+l.paddingRight, AlignLeft, l.mainTextColor)
Print(screen, []byte(string(tcell.RuneRTee)), (x-5)+width+5+l.paddingRight, y, 1, AlignLeft, l.mainTextColor)
@ -905,7 +928,7 @@ func (l *List) Draw(screen tcell.Screen) {
if index == l.currentItem && (!l.selectedFocusOnly || hasFocus) {
textWidth := width
if !l.highlightFullLine {
if w := TaggedStringWidth(item.mainText); w < textWidth {
if w := TaggedTextWidth(item.mainText); w < textWidth {
textWidth = w
}
}
@ -955,7 +978,7 @@ func (l *List) Draw(screen tcell.Screen) {
// What's the longest option text?
maxWidth := 0
for _, option := range ctx.items {
strWidth := TaggedStringWidth(option.mainText)
strWidth := TaggedTextWidth(option.mainText)
if option.shortcut != 0 {
strWidth += 4
}

View File

@ -53,9 +53,9 @@ type TableCell struct {
// NewTableCell returns a new table cell with sensible defaults. That is, left
// aligned text with the primary text color (see Styles) and a transparent
// background (using the background of the Table).
func NewTableCell(text []byte) *TableCell {
func NewTableCell(text string) *TableCell {
return &TableCell{
Text: text,
Text: []byte(text),
Align: AlignLeft,
Color: Styles.PrimaryTextColor,
BackgroundColor: tcell.ColorDefault,
@ -610,7 +610,7 @@ func (t *Table) SetCell(row, column int, cell *TableCell) *Table {
}
// SetCellSimple calls SetCell() with the given text, left-aligned, in white.
func (t *Table) SetCellSimple(row, column int, text []byte) *Table {
func (t *Table) SetCellSimple(row, column int, text string) *Table {
return t.SetCell(row, column, NewTableCell(text))
}

View File

@ -96,7 +96,7 @@ func tc(c *tableTestCase) *Table {
for row := 0; row < c.rows; row++ {
for column := 0; column < c.columns; column++ {
table.SetCellSimple(row, column, []byte(fmt.Sprintf("%d,%d", column, row)))
table.SetCellSimple(row, column, fmt.Sprintf("%d,%d", column, row))
}
}