1
0
mirror of https://github.com/rivo/tview.git synced 2025-04-30 13:48:50 +08:00

Tags can be turned off for List and Autocomplete; also added Unescape function. Fixes #1016

This commit is contained in:
Oliver 2024-11-03 12:33:52 +01:00
parent 65faf5cfc7
commit ad9e2501de
4 changed files with 56 additions and 10 deletions

View File

@ -1,6 +1,7 @@
package tview package tview
import ( import (
"math"
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
@ -99,6 +100,7 @@ type InputField struct {
main tcell.Style main tcell.Style
selected tcell.Style selected tcell.Style
background tcell.Color background tcell.Color
useTags bool
} }
// An optional function which is called when the user selects an // An optional function which is called when the user selects an
@ -146,6 +148,7 @@ func NewInputField() *InputField {
i.autocompleteStyles.main = tcell.StyleDefault.Background(Styles.MoreContrastBackgroundColor).Foreground(Styles.PrimitiveBackgroundColor) i.autocompleteStyles.main = tcell.StyleDefault.Background(Styles.MoreContrastBackgroundColor).Foreground(Styles.PrimitiveBackgroundColor)
i.autocompleteStyles.selected = tcell.StyleDefault.Background(Styles.PrimaryTextColor).Foreground(Styles.PrimitiveBackgroundColor) i.autocompleteStyles.selected = tcell.StyleDefault.Background(Styles.PrimaryTextColor).Foreground(Styles.PrimitiveBackgroundColor)
i.autocompleteStyles.background = Styles.MoreContrastBackgroundColor i.autocompleteStyles.background = Styles.MoreContrastBackgroundColor
i.autocompleteStyles.useTags = true
return i return i
} }
@ -256,6 +259,13 @@ func (i *InputField) SetAutocompleteStyles(background tcell.Color, main, selecte
return i return i
} }
// SetAutocompleteUseTags sets whether or not the autocomplete entries may
// contain style tags affecting their appearance. The default is true.
func (i *InputField) SetAutocompleteUseTags(useTags bool) *InputField {
i.autocompleteStyles.useTags = useTags
return i
}
// SetFormAttributes sets attributes shared by all form items. // SetFormAttributes sets attributes shared by all form items.
func (i *InputField) SetFormAttributes(labelWidth int, labelColor, bgColor, fieldTextColor, fieldBgColor tcell.Color) FormItem { func (i *InputField) SetFormAttributes(labelWidth int, labelColor, bgColor, fieldTextColor, fieldBgColor tcell.Color) FormItem {
i.textArea.SetFormAttributes(labelWidth, labelColor, bgColor, fieldTextColor, fieldBgColor) i.textArea.SetFormAttributes(labelWidth, labelColor, bgColor, fieldTextColor, fieldBgColor)
@ -363,13 +373,14 @@ func (i *InputField) Autocomplete() *InputField {
i.autocompleteList.ShowSecondaryText(false). i.autocompleteList.ShowSecondaryText(false).
SetMainTextStyle(i.autocompleteStyles.main). SetMainTextStyle(i.autocompleteStyles.main).
SetSelectedStyle(i.autocompleteStyles.selected). SetSelectedStyle(i.autocompleteStyles.selected).
SetUseStyleTags(i.autocompleteStyles.useTags, i.autocompleteStyles.useTags).
SetHighlightFullLine(true). SetHighlightFullLine(true).
SetBackgroundColor(i.autocompleteStyles.background) SetBackgroundColor(i.autocompleteStyles.background)
} }
// Fill it with the entries. // Fill it with the entries.
currentEntry := -1 currentEntry := -1
suffixLength := 9999 // I'm just waiting for the day somebody opens an issue with this number being too small. suffixLength := math.MaxInt
i.autocompleteList.Clear() i.autocompleteList.Clear()
for index, entry := range entries { for index, entry := range entries {
i.autocompleteList.AddItem(entry, "", 0, nil) i.autocompleteList.AddItem(entry, "", 0, nil)

39
list.go
View File

@ -30,6 +30,9 @@ type listItem struct {
// - Right / left: Scroll horizontally. Only if the list is wider than the // - Right / left: Scroll horizontally. Only if the list is wider than the
// available space. // available space.
// //
// By default, list item texts can contain style tags. Use
// [List.SetUseStyleTags] to disable this feature.
//
// See [List.SetChangedFunc] for a way to be notified when the user navigates // See [List.SetChangedFunc] for a way to be notified when the user navigates
// to a list item. See [List.SetSelectedFunc] for a way to be notified when a // to a list item. See [List.SetSelectedFunc] for a way to be notified when a
// list item was selected. // list item was selected.
@ -65,6 +68,12 @@ type List struct {
// If true, the entire row is highlighted when selected. // If true, the entire row is highlighted when selected.
highlightFullLine bool highlightFullLine bool
// Whether or not style tags can be used in the main text.
mainStyleTags bool
// Whether or not style tags can be used in the secondary text.
secondaryStyleTags bool
// Whether or not navigating the list will wrap around. // Whether or not navigating the list will wrap around.
wrapAround bool wrapAround bool
@ -98,6 +107,8 @@ func NewList() *List {
secondaryTextStyle: tcell.StyleDefault.Foreground(Styles.TertiaryTextColor).Background(Styles.PrimitiveBackgroundColor), secondaryTextStyle: tcell.StyleDefault.Foreground(Styles.TertiaryTextColor).Background(Styles.PrimitiveBackgroundColor),
shortcutStyle: tcell.StyleDefault.Foreground(Styles.SecondaryTextColor).Background(Styles.PrimitiveBackgroundColor), shortcutStyle: tcell.StyleDefault.Foreground(Styles.SecondaryTextColor).Background(Styles.PrimitiveBackgroundColor),
selectedStyle: tcell.StyleDefault.Foreground(Styles.PrimitiveBackgroundColor).Background(Styles.PrimaryTextColor), selectedStyle: tcell.StyleDefault.Foreground(Styles.PrimitiveBackgroundColor).Background(Styles.PrimaryTextColor),
mainStyleTags: true,
secondaryStyleTags: true,
} }
} }
@ -268,6 +279,14 @@ func (l *List) SetSelectedStyle(style tcell.Style) *List {
return l return l
} }
// SetUseStyleTags sets a flag which determines whether style tags are used in
// the main and secondary texts. The default is true.
func (l *List) SetUseStyleTags(mainStyleTags, secondaryStyleTags bool) *List {
l.mainStyleTags = mainStyleTags
l.secondaryStyleTags = secondaryStyleTags
return l
}
// SetSelectedFocusOnly sets a flag which determines when the currently selected // SetSelectedFocusOnly sets a flag which determines when the currently selected
// list item is highlighted. If set to true, selected items are only highlighted // list item is highlighted. If set to true, selected items are only highlighted
// when the list has focus. If set to false, they are always highlighted. // when the list has focus. If set to false, they are always highlighted.
@ -328,7 +347,7 @@ func (l *List) SetDoneFunc(handler func()) *List {
return l return l
} }
// AddItem calls InsertItem() with an index of -1. // AddItem calls [List.InsertItem] with an index of -1.
func (l *List) AddItem(mainText, secondaryText string, shortcut rune, selected func()) *List { func (l *List) AddItem(mainText, secondaryText string, shortcut rune, selected func()) *List {
l.InsertItem(-1, mainText, secondaryText, shortcut, selected) l.InsertItem(-1, mainText, secondaryText, shortcut, selected)
return l return l
@ -336,8 +355,8 @@ func (l *List) AddItem(mainText, secondaryText string, shortcut rune, selected f
// InsertItem adds a new item to the list at the specified index. An index of 0 // InsertItem adds a new item to the list at the specified index. An index of 0
// will insert the item at the beginning, an index of 1 before the second item, // will insert the item at the beginning, an index of 1 before the second item,
// and so on. An index of GetItemCount() or higher will insert the item at the // and so on. An index of [List.GetItemCount] or higher will insert the item at
// end of the list. Negative indices are also allowed: An index of -1 will // the end of the list. Negative indices are also allowed: An index of -1 will
// insert the item at the end of the list, an index of -2 before the last item, // insert the item at the end of the list, an index of -2 before the last item,
// and so on. An index of -GetItemCount()-1 or lower will insert the item at the // and so on. An index of -GetItemCount()-1 or lower will insert the item at the
// beginning. // beginning.
@ -351,7 +370,7 @@ func (l *List) AddItem(mainText, secondaryText string, shortcut rune, selected f
// //
// The "selected" callback will be invoked when the user selects the item. You // The "selected" callback will be invoked when the user selects the item. You
// may provide nil if no such callback is needed or if all events are handled // may provide nil if no such callback is needed or if all events are handled
// through the selected callback set with SetSelectedFunc(). // through the selected callback set with [List.SetSelectedFunc].
// //
// The currently selected item will shift its position accordingly. If the list // The currently selected item will shift its position accordingly. If the list
// was previously empty, a "changed" event is fired because the new item becomes // was previously empty, a "changed" event is fired because the new item becomes
@ -511,7 +530,11 @@ func (l *List) Draw(screen tcell.Screen) {
if selected { if selected {
style = l.selectedStyle style = l.selectedStyle
} }
_, _, printedWidth := printWithStyle(screen, item.MainText, x, y, l.horizontalOffset, width, AlignLeft, style, false) mainText := item.MainText
if !l.mainStyleTags {
mainText = Escape(mainText)
}
_, _, printedWidth := printWithStyle(screen, mainText, x, y, l.horizontalOffset, width, AlignLeft, style, false)
if printedWidth > maxWidth { if printedWidth > maxWidth {
maxWidth = printedWidth maxWidth = printedWidth
} }
@ -530,7 +553,11 @@ func (l *List) Draw(screen tcell.Screen) {
// Secondary text. // Secondary text.
if l.showSecondaryText { if l.showSecondaryText {
_, _, printedWidth := printWithStyle(screen, item.SecondaryText, x, y, l.horizontalOffset, width, AlignLeft, l.secondaryTextStyle, false) secondaryText := item.SecondaryText
if !l.secondaryStyleTags {
secondaryText = Escape(secondaryText)
}
_, _, printedWidth := printWithStyle(screen, secondaryText, x, y, l.horizontalOffset, width, AlignLeft, l.secondaryTextStyle, false)
if printedWidth > maxWidth { if printedWidth > maxWidth {
maxWidth = printedWidth maxWidth = printedWidth
} }

View File

@ -593,7 +593,12 @@ func WordWrap(text string, width int) (lines []string) {
// box.SetTitle(tview.Escape("[squarebrackets]")) // box.SetTitle(tview.Escape("[squarebrackets]"))
// fmt.Fprint(textView, tview.Escape(`["quoted"]`)) // fmt.Fprint(textView, tview.Escape(`["quoted"]`))
func Escape(text string) string { func Escape(text string) string {
return nonEscapePattern.ReplaceAllString(text, "$1[]") return escapePattern.ReplaceAllString(text, "$1[]")
}
// Unescape unescapes text previously escaped with [Escape].
func Unescape(text string) string {
return unescapePattern.ReplaceAllString(text, "$1]")
} }
// stripTags strips style tags from the given string. (Region tags are not // stripTags strips style tags from the given string. (Region tags are not

View File

@ -19,7 +19,10 @@ const (
var ( var (
// Regular expression used to escape style/region tags. // Regular expression used to escape style/region tags.
nonEscapePattern = regexp.MustCompile(`(\[[a-zA-Z0-9_,;: \-\."#]+\[*)\]`) escapePattern = regexp.MustCompile(`(\[[a-zA-Z0-9_,;: \-\."#]+\[*)\]`)
// Regular expression used to unescape escaped style/region tags.
unescapePattern = regexp.MustCompile(`(\[[a-zA-Z0-9_,;: \-\."#]+\[*)\[\]`)
// The number of colors available in the terminal. // The number of colors available in the terminal.
availableColors = 256 availableColors = 256
@ -48,7 +51,7 @@ func Print(screen tcell.Screen, text string, x, y, maxWidth, align int, color tc
return end - start, width return end - start, width
} }
// printWithStyle works like Print() but it takes a style instead of just a // printWithStyle works like [Print] but it takes a style instead of just a
// foreground color. The skipWidth parameter specifies the number of cells // foreground color. The skipWidth parameter specifies the number of cells
// skipped at the beginning of the text. It returns the start index, end index // skipped at the beginning of the text. It returns the start index, end index
// (exclusively), and screen width of the text actually printed. If // (exclusively), and screen width of the text actually printed. If