mirror of
https://github.com/taigrr/wtf
synced 2026-04-01 20:38:43 -07:00
WTF-539 Add missing vendored dependencies back
This commit is contained in:
2
vendor/github.com/rivo/tview/README.md
generated
vendored
2
vendor/github.com/rivo/tview/README.md
generated
vendored
@@ -65,6 +65,8 @@ Add your issue here on GitHub. Feel free to get in touch if you have any questio
|
||||
|
||||
(There are no corresponding tags in the project. I only keep such a history in this README.)
|
||||
|
||||
- v0.20 (2019-07-08)
|
||||
- Added autocomplete functionality to `InputField`.
|
||||
- v0.19 (2018-10-28)
|
||||
- Added `QueueUpdate()` and `QueueEvent()` to `Application` to help with modifications to primitives from goroutines.
|
||||
- v0.18 (2018-10-18)
|
||||
|
||||
2
vendor/github.com/rivo/tview/ansi.go
generated
vendored
2
vendor/github.com/rivo/tview/ansi.go
generated
vendored
@@ -127,6 +127,7 @@ func (a *ansi) Write(text []byte) (int, error) {
|
||||
"#ffffff",
|
||||
}[colorNumber]
|
||||
}
|
||||
FieldLoop:
|
||||
for index, field := range fields {
|
||||
switch field {
|
||||
case "1", "01":
|
||||
@@ -185,6 +186,7 @@ func (a *ansi) Write(text []byte) (int, error) {
|
||||
background = color
|
||||
}
|
||||
}
|
||||
break FieldLoop
|
||||
}
|
||||
}
|
||||
if len(attributes) > 0 || clearAttributes {
|
||||
|
||||
2
vendor/github.com/rivo/tview/application.go
generated
vendored
2
vendor/github.com/rivo/tview/application.go
generated
vendored
@@ -81,7 +81,7 @@ func NewApplication() *Application {
|
||||
//
|
||||
// Note that this also affects the default event handling of the application
|
||||
// itself: Such a handler can intercept the Ctrl-C event which closes the
|
||||
// applicatoon.
|
||||
// application.
|
||||
func (a *Application) SetInputCapture(capture func(event *tcell.EventKey) *tcell.EventKey) *Application {
|
||||
a.inputCapture = capture
|
||||
return a
|
||||
|
||||
24
vendor/github.com/rivo/tview/box.go
generated
vendored
24
vendor/github.com/rivo/tview/box.go
generated
vendored
@@ -88,7 +88,8 @@ func (b *Box) GetRect() (int, int, int, int) {
|
||||
}
|
||||
|
||||
// GetInnerRect returns the position of the inner rectangle (x, y, width,
|
||||
// height), without the border and without any padding.
|
||||
// height), without the border and without any padding. Width and height values
|
||||
// will clamp to 0 and thus never be negative.
|
||||
func (b *Box) GetInnerRect() (int, int, int, int) {
|
||||
if b.innerX >= 0 {
|
||||
return b.innerX, b.innerY, b.innerWidth, b.innerHeight
|
||||
@@ -100,10 +101,17 @@ func (b *Box) GetInnerRect() (int, int, int, int) {
|
||||
width -= 2
|
||||
height -= 2
|
||||
}
|
||||
return x + b.paddingLeft,
|
||||
y + b.paddingTop,
|
||||
width - b.paddingLeft - b.paddingRight,
|
||||
height - b.paddingTop - b.paddingBottom
|
||||
x, y, width, height = x+b.paddingLeft,
|
||||
y+b.paddingTop,
|
||||
width-b.paddingLeft-b.paddingRight,
|
||||
height-b.paddingTop-b.paddingBottom
|
||||
if width < 0 {
|
||||
width = 0
|
||||
}
|
||||
if height < 0 {
|
||||
height = 0
|
||||
}
|
||||
return x, y, width, height
|
||||
}
|
||||
|
||||
// SetRect sets a new position of the primitive. Note that this has no effect
|
||||
@@ -318,6 +326,12 @@ func (b *Box) Draw(screen tcell.Screen) {
|
||||
b.innerHeight += b.innerY
|
||||
b.innerY = 0
|
||||
}
|
||||
if b.innerWidth < 0 {
|
||||
b.innerWidth = 0
|
||||
}
|
||||
if b.innerHeight < 0 {
|
||||
b.innerHeight = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Focus is called when this primitive receives focus.
|
||||
|
||||
70
vendor/github.com/rivo/tview/dropdown.go
generated
vendored
70
vendor/github.com/rivo/tview/dropdown.go
generated
vendored
@@ -22,10 +22,19 @@ type DropDown struct {
|
||||
// The options from which the user can choose.
|
||||
options []*dropDownOption
|
||||
|
||||
// Strings to be placed before and after each drop-down option.
|
||||
optionPrefix, optionSuffix string
|
||||
|
||||
// The index of the currently selected option. Negative if no option is
|
||||
// currently selected.
|
||||
currentOption int
|
||||
|
||||
// Strings to be placed beefore and after the current option.
|
||||
currentOptionPrefix, currentOptionSuffix string
|
||||
|
||||
// The text to be displayed when no option has yet been selected.
|
||||
noSelection string
|
||||
|
||||
// Set to true if the options are visible and selectable.
|
||||
open bool
|
||||
|
||||
@@ -74,10 +83,12 @@ type DropDown struct {
|
||||
|
||||
// NewDropDown returns a new drop-down.
|
||||
func NewDropDown() *DropDown {
|
||||
list := NewList().ShowSecondaryText(false)
|
||||
list.SetMainTextColor(Styles.PrimitiveBackgroundColor).
|
||||
list := NewList()
|
||||
list.ShowSecondaryText(false).
|
||||
SetMainTextColor(Styles.PrimitiveBackgroundColor).
|
||||
SetSelectedTextColor(Styles.PrimitiveBackgroundColor).
|
||||
SetSelectedBackgroundColor(Styles.PrimaryTextColor).
|
||||
SetHighlightFullLine(true).
|
||||
SetBackgroundColor(Styles.MoreContrastBackgroundColor)
|
||||
|
||||
d := &DropDown{
|
||||
@@ -128,6 +139,23 @@ func (d *DropDown) GetCurrentOption() (int, string) {
|
||||
return d.currentOption, text
|
||||
}
|
||||
|
||||
// SetTextOptions sets the text to be placed before and after each drop-down
|
||||
// option (prefix/suffix), the text placed before and after the currently
|
||||
// selected option (currentPrefix/currentSuffix) as well as the text to be
|
||||
// displayed when no option is currently selected. Per default, all of these
|
||||
// strings are empty.
|
||||
func (d *DropDown) SetTextOptions(prefix, suffix, currentPrefix, currentSuffix, noSelection string) *DropDown {
|
||||
d.currentOptionPrefix = currentPrefix
|
||||
d.currentOptionSuffix = currentSuffix
|
||||
d.noSelection = noSelection
|
||||
d.optionPrefix = prefix
|
||||
d.optionSuffix = suffix
|
||||
for index := 0; index < d.list.GetItemCount(); index++ {
|
||||
d.list.SetItemText(index, prefix+d.options[index].Text+suffix, "")
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// SetLabel sets the text to be displayed before the input area.
|
||||
func (d *DropDown) SetLabel(label string) *DropDown {
|
||||
d.label = label
|
||||
@@ -208,7 +236,7 @@ func (d *DropDown) GetFieldWidth() int {
|
||||
// callback is called when this option was selected. It may be nil.
|
||||
func (d *DropDown) AddOption(text string, selected func()) *DropDown {
|
||||
d.options = append(d.options, &dropDownOption{Text: text, Selected: selected})
|
||||
d.list.AddItem(text, "", 0, nil)
|
||||
d.list.AddItem(d.optionPrefix+text+d.optionSuffix, "", 0, nil)
|
||||
return d
|
||||
}
|
||||
|
||||
@@ -282,8 +310,9 @@ func (d *DropDown) Draw(screen tcell.Screen) {
|
||||
|
||||
// What's the longest option text?
|
||||
maxWidth := 0
|
||||
optionWrapWidth := TaggedStringWidth(d.optionPrefix + d.optionSuffix)
|
||||
for _, option := range d.options {
|
||||
strWidth := TaggedStringWidth(option.Text)
|
||||
strWidth := TaggedStringWidth(option.Text) + optionWrapWidth
|
||||
if strWidth > maxWidth {
|
||||
maxWidth = strWidth
|
||||
}
|
||||
@@ -293,6 +322,17 @@ func (d *DropDown) Draw(screen tcell.Screen) {
|
||||
fieldWidth := d.fieldWidth
|
||||
if fieldWidth == 0 {
|
||||
fieldWidth = maxWidth
|
||||
if d.currentOption < 0 {
|
||||
noSelectionWidth := TaggedStringWidth(d.noSelection)
|
||||
if noSelectionWidth > fieldWidth {
|
||||
fieldWidth = noSelectionWidth
|
||||
}
|
||||
} else if d.currentOption < len(d.options) {
|
||||
currentOptionWidth := TaggedStringWidth(d.currentOptionPrefix + d.options[d.currentOption].Text + d.currentOptionSuffix)
|
||||
if currentOptionWidth > fieldWidth {
|
||||
fieldWidth = currentOptionWidth
|
||||
}
|
||||
}
|
||||
}
|
||||
if rightLimit-x < fieldWidth {
|
||||
fieldWidth = rightLimit - x
|
||||
@@ -308,21 +348,25 @@ func (d *DropDown) Draw(screen tcell.Screen) {
|
||||
// Draw selected text.
|
||||
if d.open && len(d.prefix) > 0 {
|
||||
// Show the prefix.
|
||||
Print(screen, d.prefix, x, y, fieldWidth, AlignLeft, d.prefixTextColor)
|
||||
currentOptionPrefixWidth := TaggedStringWidth(d.currentOptionPrefix)
|
||||
prefixWidth := stringWidth(d.prefix)
|
||||
listItemText := d.options[d.list.GetCurrentItem()].Text
|
||||
if prefixWidth < fieldWidth && len(d.prefix) < len(listItemText) {
|
||||
Print(screen, listItemText[len(d.prefix):], x+prefixWidth, y, fieldWidth-prefixWidth, AlignLeft, d.fieldTextColor)
|
||||
Print(screen, d.currentOptionPrefix, x, y, fieldWidth, AlignLeft, d.fieldTextColor)
|
||||
Print(screen, d.prefix, x+currentOptionPrefixWidth, y, fieldWidth-currentOptionPrefixWidth, AlignLeft, d.prefixTextColor)
|
||||
if len(d.prefix) < len(listItemText) {
|
||||
Print(screen, listItemText[len(d.prefix):]+d.currentOptionSuffix, x+prefixWidth+currentOptionPrefixWidth, y, fieldWidth-prefixWidth-currentOptionPrefixWidth, AlignLeft, d.fieldTextColor)
|
||||
}
|
||||
} else {
|
||||
color := d.fieldTextColor
|
||||
text := d.noSelection
|
||||
if d.currentOption >= 0 && d.currentOption < len(d.options) {
|
||||
color := d.fieldTextColor
|
||||
// Just show the current selection.
|
||||
if d.GetFocusable().HasFocus() && !d.open {
|
||||
color = d.fieldBackgroundColor
|
||||
}
|
||||
Print(screen, d.options[d.currentOption].Text, x, y, fieldWidth, AlignLeft, color)
|
||||
text = d.currentOptionPrefix + d.options[d.currentOption].Text + d.currentOptionSuffix
|
||||
}
|
||||
// Just show the current selection.
|
||||
if d.GetFocusable().HasFocus() && !d.open {
|
||||
color = d.fieldBackgroundColor
|
||||
}
|
||||
Print(screen, text, x, y, fieldWidth, AlignLeft, color)
|
||||
}
|
||||
|
||||
// Draw options list.
|
||||
|
||||
4
vendor/github.com/rivo/tview/form.go
generated
vendored
4
vendor/github.com/rivo/tview/form.go
generated
vendored
@@ -209,8 +209,8 @@ func (f *Form) AddPasswordField(label, value string, fieldWidth int, mask rune,
|
||||
func (f *Form) AddDropDown(label string, options []string, initialOption int, selected func(option string, optionIndex int)) *Form {
|
||||
f.items = append(f.items, NewDropDown().
|
||||
SetLabel(label).
|
||||
SetCurrentOption(initialOption).
|
||||
SetOptions(options, selected))
|
||||
SetOptions(options, selected).
|
||||
SetCurrentOption(initialOption))
|
||||
return f
|
||||
}
|
||||
|
||||
|
||||
142
vendor/github.com/rivo/tview/grid.go
generated
vendored
142
vendor/github.com/rivo/tview/grid.go
generated
vendored
@@ -68,7 +68,7 @@ type Grid struct {
|
||||
// grid.SetBackgroundColor(tview.Styles.PrimitiveBackgroundColor)
|
||||
func NewGrid() *Grid {
|
||||
g := &Grid{
|
||||
Box: NewBox().SetBackgroundColor(tcell.ColorDefault),
|
||||
Box: NewBox(),
|
||||
bordersColor: Styles.GraphicsColor,
|
||||
}
|
||||
g.focus = g
|
||||
@@ -230,7 +230,7 @@ func (g *Grid) Clear() *Grid {
|
||||
// drawing the first grid cell in the top-left corner. As the grid will never
|
||||
// completely move off the screen, these values may be adjusted the next time
|
||||
// the grid is drawn. The actual position of the grid may also be adjusted such
|
||||
// that contained primitives that have focus are visible.
|
||||
// that contained primitives that have focus remain visible.
|
||||
func (g *Grid) SetOffset(rows, columns int) *Grid {
|
||||
g.rowOffset, g.columnOffset = rows, columns
|
||||
return g
|
||||
@@ -392,8 +392,6 @@ func (g *Grid) Draw(screen tcell.Screen) {
|
||||
}
|
||||
|
||||
// Distribute proportional rows/columns.
|
||||
gridWidth := 0
|
||||
gridHeight := 0
|
||||
for index := 0; index < rows; index++ {
|
||||
row := 0
|
||||
if index < len(g.rows) {
|
||||
@@ -403,7 +401,6 @@ func (g *Grid) Draw(screen tcell.Screen) {
|
||||
if row < g.minHeight {
|
||||
row = g.minHeight
|
||||
}
|
||||
gridHeight += row
|
||||
continue // Not proportional. We already know the width.
|
||||
} else if row == 0 {
|
||||
row = 1
|
||||
@@ -417,7 +414,6 @@ func (g *Grid) Draw(screen tcell.Screen) {
|
||||
rowAbs = g.minHeight
|
||||
}
|
||||
rowHeight[index] = rowAbs
|
||||
gridHeight += rowAbs
|
||||
}
|
||||
for index := 0; index < columns; index++ {
|
||||
column := 0
|
||||
@@ -428,7 +424,6 @@ func (g *Grid) Draw(screen tcell.Screen) {
|
||||
if column < g.minWidth {
|
||||
column = g.minWidth
|
||||
}
|
||||
gridWidth += column
|
||||
continue // Not proportional. We already know the height.
|
||||
} else if column == 0 {
|
||||
column = 1
|
||||
@@ -442,18 +437,10 @@ func (g *Grid) Draw(screen tcell.Screen) {
|
||||
columnAbs = g.minWidth
|
||||
}
|
||||
columnWidth[index] = columnAbs
|
||||
gridWidth += columnAbs
|
||||
}
|
||||
if g.borders {
|
||||
gridHeight += rows + 1
|
||||
gridWidth += columns + 1
|
||||
} else {
|
||||
gridHeight += (rows - 1) * g.gapRows
|
||||
gridWidth += (columns - 1) * g.gapColumns
|
||||
}
|
||||
|
||||
// Calculate row/column positions.
|
||||
columnX, rowY := x, y
|
||||
var columnX, rowY int
|
||||
if g.borders {
|
||||
columnX++
|
||||
rowY++
|
||||
@@ -502,50 +489,87 @@ func (g *Grid) Draw(screen tcell.Screen) {
|
||||
}
|
||||
|
||||
// Calculate screen offsets.
|
||||
var offsetX, offsetY, add int
|
||||
if g.rowOffset < 0 {
|
||||
g.rowOffset = 0
|
||||
var offsetX, offsetY int
|
||||
add := 1
|
||||
if !g.borders {
|
||||
add = g.gapRows
|
||||
}
|
||||
if g.columnOffset < 0 {
|
||||
g.columnOffset = 0
|
||||
for index, height := range rowHeight {
|
||||
if index >= g.rowOffset {
|
||||
break
|
||||
}
|
||||
offsetY += height + add
|
||||
}
|
||||
if !g.borders {
|
||||
add = g.gapColumns
|
||||
}
|
||||
for index, width := range columnWidth {
|
||||
if index >= g.columnOffset {
|
||||
break
|
||||
}
|
||||
offsetX += width + add
|
||||
}
|
||||
|
||||
// Line up the last row/column with the end of the available area.
|
||||
var border int
|
||||
if g.borders {
|
||||
add = 1
|
||||
border = 1
|
||||
}
|
||||
for row := 0; row < rows-1; row++ {
|
||||
remainingHeight := gridHeight - offsetY
|
||||
if focus != nil && focus.y-add <= offsetY || // Don't let the focused item move out of screen.
|
||||
row >= g.rowOffset && (focus == nil || focus != nil && focus.y-offsetY < height) || // We've reached the requested offset.
|
||||
remainingHeight <= height { // We have enough space to show the rest.
|
||||
if row > 0 {
|
||||
if focus != nil && focus.y+focus.h+add-offsetY > height {
|
||||
offsetY += focus.y + focus.h + add - offsetY - height
|
||||
}
|
||||
if remainingHeight < height {
|
||||
offsetY = gridHeight - height
|
||||
}
|
||||
}
|
||||
g.rowOffset = row
|
||||
break
|
||||
}
|
||||
offsetY = rowPos[row+1] - add
|
||||
last := len(rowPos) - 1
|
||||
if rowPos[last]+rowHeight[last]+border-offsetY < height {
|
||||
offsetY = rowPos[last] - height + rowHeight[last] + border
|
||||
}
|
||||
for column := 0; column < columns-1; column++ {
|
||||
remainingWidth := gridWidth - offsetX
|
||||
if focus != nil && focus.x-add <= offsetX || // Don't let the focused item move out of screen.
|
||||
column >= g.columnOffset && (focus == nil || focus != nil && focus.x-offsetX < width) || // We've reached the requested offset.
|
||||
remainingWidth <= width { // We have enough space to show the rest.
|
||||
if column > 0 {
|
||||
if focus != nil && focus.x+focus.w+add-offsetX > width {
|
||||
offsetX += focus.x + focus.w + add - offsetX - width
|
||||
} else if remainingWidth < width {
|
||||
offsetX = gridWidth - width
|
||||
}
|
||||
}
|
||||
g.columnOffset = column
|
||||
break
|
||||
last = len(columnPos) - 1
|
||||
if columnPos[last]+columnWidth[last]+border-offsetX < width {
|
||||
offsetX = columnPos[last] - width + columnWidth[last] + border
|
||||
}
|
||||
|
||||
// The focused item must be within the visible area.
|
||||
if focus != nil {
|
||||
if focus.y+focus.h-offsetY >= height {
|
||||
offsetY = focus.y - height + focus.h
|
||||
}
|
||||
offsetX = columnPos[column+1] - add
|
||||
if focus.y-offsetY < 0 {
|
||||
offsetY = focus.y
|
||||
}
|
||||
if focus.x+focus.w-offsetX >= width {
|
||||
offsetX = focus.x - width + focus.w
|
||||
}
|
||||
if focus.x-offsetX < 0 {
|
||||
offsetX = focus.x
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust row/column offsets based on this value.
|
||||
var from, to int
|
||||
for index, pos := range rowPos {
|
||||
if pos-offsetY < 0 {
|
||||
from = index + 1
|
||||
}
|
||||
if pos-offsetY < height {
|
||||
to = index
|
||||
}
|
||||
}
|
||||
if g.rowOffset < from {
|
||||
g.rowOffset = from
|
||||
}
|
||||
if g.rowOffset > to {
|
||||
g.rowOffset = to
|
||||
}
|
||||
from, to = 0, 0
|
||||
for index, pos := range columnPos {
|
||||
if pos-offsetX < 0 {
|
||||
from = index + 1
|
||||
}
|
||||
if pos-offsetX < width {
|
||||
to = index
|
||||
}
|
||||
}
|
||||
if g.columnOffset < from {
|
||||
g.columnOffset = from
|
||||
}
|
||||
if g.columnOffset > to {
|
||||
g.columnOffset = to
|
||||
}
|
||||
|
||||
// Draw primitives and borders.
|
||||
@@ -556,10 +580,14 @@ func (g *Grid) Draw(screen tcell.Screen) {
|
||||
}
|
||||
item.x -= offsetX
|
||||
item.y -= offsetY
|
||||
if item.x+item.w > x+width {
|
||||
if item.x >= width || item.x+item.w <= 0 || item.y >= height || item.y+item.h <= 0 {
|
||||
item.visible = false
|
||||
continue
|
||||
}
|
||||
if item.x+item.w > width {
|
||||
item.w = width - item.x
|
||||
}
|
||||
if item.y+item.h > y+height {
|
||||
if item.y+item.h > height {
|
||||
item.h = height - item.y
|
||||
}
|
||||
if item.x < 0 {
|
||||
@@ -574,6 +602,8 @@ func (g *Grid) Draw(screen tcell.Screen) {
|
||||
item.visible = false
|
||||
continue
|
||||
}
|
||||
item.x += x
|
||||
item.y += y
|
||||
primitive.SetRect(item.x, item.y, item.w, item.h)
|
||||
|
||||
// Draw primitive.
|
||||
|
||||
160
vendor/github.com/rivo/tview/inputfield.go
generated
vendored
160
vendor/github.com/rivo/tview/inputfield.go
generated
vendored
@@ -4,6 +4,7 @@ import (
|
||||
"math"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/gdamore/tcell"
|
||||
@@ -71,6 +72,16 @@ type InputField struct {
|
||||
// The number of bytes of the text string skipped ahead while drawing.
|
||||
offset int
|
||||
|
||||
// An optional autocomplete function which receives the current text of the
|
||||
// input field and returns a slice of strings to be displayed in a drop-down
|
||||
// selection.
|
||||
autocomplete func(text string) []string
|
||||
|
||||
// The List object which shows the selectable autocomplete entries. If not
|
||||
// nil, the list's main texts represent the current autocomplete entries.
|
||||
autocompleteList *List
|
||||
autocompleteListMutex sync.Mutex
|
||||
|
||||
// An optional function which may reject the last character that was entered.
|
||||
accept func(text string, ch rune) bool
|
||||
|
||||
@@ -190,6 +201,70 @@ func (i *InputField) SetMaskCharacter(mask rune) *InputField {
|
||||
return i
|
||||
}
|
||||
|
||||
// SetAutocompleteFunc sets an autocomplete callback function which may return
|
||||
// strings to be selected from a drop-down based on the current text of the
|
||||
// input field. The drop-down appears only if len(entries) > 0. The callback is
|
||||
// invoked in this function and whenever the current text changes or when
|
||||
// Autocomplete() is called. Entries are cleared when the user selects an entry
|
||||
// or presses Escape.
|
||||
func (i *InputField) SetAutocompleteFunc(callback func(currentText string) (entries []string)) *InputField {
|
||||
i.autocomplete = callback
|
||||
i.Autocomplete()
|
||||
return i
|
||||
}
|
||||
|
||||
// Autocomplete invokes the autocomplete callback (if there is one). If the
|
||||
// length of the returned autocomplete entries slice is greater than 0, the
|
||||
// input field will present the user with a corresponding drop-down list the
|
||||
// next time the input field is drawn.
|
||||
//
|
||||
// It is safe to call this function from any goroutine. Note that the input
|
||||
// field is not redrawn automatically unless called from the main goroutine
|
||||
// (e.g. in response to events).
|
||||
func (i *InputField) Autocomplete() *InputField {
|
||||
i.autocompleteListMutex.Lock()
|
||||
defer i.autocompleteListMutex.Unlock()
|
||||
if i.autocomplete == nil {
|
||||
return i
|
||||
}
|
||||
|
||||
// Do we have any autocomplete entries?
|
||||
entries := i.autocomplete(i.text)
|
||||
if len(entries) == 0 {
|
||||
// No entries, no list.
|
||||
i.autocompleteList = nil
|
||||
return i
|
||||
}
|
||||
|
||||
// Make a list if we have none.
|
||||
if i.autocompleteList == nil {
|
||||
i.autocompleteList = NewList()
|
||||
i.autocompleteList.ShowSecondaryText(false).
|
||||
SetMainTextColor(Styles.PrimitiveBackgroundColor).
|
||||
SetSelectedTextColor(Styles.PrimitiveBackgroundColor).
|
||||
SetSelectedBackgroundColor(Styles.PrimaryTextColor).
|
||||
SetHighlightFullLine(true).
|
||||
SetBackgroundColor(Styles.MoreContrastBackgroundColor)
|
||||
}
|
||||
|
||||
// Fill it with the entries.
|
||||
currentEntry := -1
|
||||
i.autocompleteList.Clear()
|
||||
for index, entry := range entries {
|
||||
i.autocompleteList.AddItem(entry, "", 0, nil)
|
||||
if currentEntry < 0 && entry == i.text {
|
||||
currentEntry = index
|
||||
}
|
||||
}
|
||||
|
||||
// Set the selection if we have one.
|
||||
if currentEntry >= 0 {
|
||||
i.autocompleteList.SetCurrentItem(currentEntry)
|
||||
}
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
// SetAcceptanceFunc sets a handler which may reject the last character that was
|
||||
// entered (by returning false).
|
||||
//
|
||||
@@ -319,6 +394,38 @@ func (i *InputField) Draw(screen tcell.Screen) {
|
||||
}
|
||||
}
|
||||
|
||||
// Draw autocomplete list.
|
||||
i.autocompleteListMutex.Lock()
|
||||
defer i.autocompleteListMutex.Unlock()
|
||||
if i.autocompleteList != nil {
|
||||
// How much space do we need?
|
||||
lheight := i.autocompleteList.GetItemCount()
|
||||
lwidth := 0
|
||||
for index := 0; index < lheight; index++ {
|
||||
entry, _ := i.autocompleteList.GetItemText(index)
|
||||
width := TaggedStringWidth(entry)
|
||||
if width > lwidth {
|
||||
lwidth = width
|
||||
}
|
||||
}
|
||||
|
||||
// We prefer to drop down but if there is no space, maybe drop up?
|
||||
lx := x
|
||||
ly := y + 1
|
||||
_, sheight := screen.Size()
|
||||
if ly+lheight >= sheight && ly-2 > lheight-ly {
|
||||
ly = y - lheight
|
||||
if ly < 0 {
|
||||
ly = 0
|
||||
}
|
||||
}
|
||||
if ly+lheight >= sheight {
|
||||
lheight = sheight - ly
|
||||
}
|
||||
i.autocompleteList.SetRect(lx, ly, lwidth, lheight)
|
||||
i.autocompleteList.Draw(screen)
|
||||
}
|
||||
|
||||
// Set cursor.
|
||||
if i.focus.HasFocus() {
|
||||
screen.ShowCursor(x+cursorScreenPos, y)
|
||||
@@ -331,8 +438,11 @@ func (i *InputField) InputHandler() func(event *tcell.EventKey, setFocus func(p
|
||||
// Trigger changed events.
|
||||
currentText := i.text
|
||||
defer func() {
|
||||
if i.text != currentText && i.changed != nil {
|
||||
i.changed(i.text)
|
||||
if i.text != currentText {
|
||||
i.Autocomplete()
|
||||
if i.changed != nil {
|
||||
i.changed(i.text)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -370,7 +480,19 @@ func (i *InputField) InputHandler() func(event *tcell.EventKey, setFocus func(p
|
||||
return true
|
||||
}
|
||||
|
||||
// Finish up.
|
||||
finish := func(key tcell.Key) {
|
||||
if i.done != nil {
|
||||
i.done(key)
|
||||
}
|
||||
if i.finished != nil {
|
||||
i.finished(key)
|
||||
}
|
||||
}
|
||||
|
||||
// Process key event.
|
||||
i.autocompleteListMutex.Lock()
|
||||
defer i.autocompleteListMutex.Unlock()
|
||||
switch key := event.Key(); key {
|
||||
case tcell.KeyRune: // Regular character.
|
||||
if event.Modifiers()&tcell.ModAlt > 0 {
|
||||
@@ -435,12 +557,36 @@ func (i *InputField) InputHandler() func(event *tcell.EventKey, setFocus func(p
|
||||
home()
|
||||
case tcell.KeyEnd, tcell.KeyCtrlE:
|
||||
end()
|
||||
case tcell.KeyEnter, tcell.KeyTab, tcell.KeyBacktab, tcell.KeyEscape: // We're done.
|
||||
if i.done != nil {
|
||||
i.done(key)
|
||||
case tcell.KeyEnter, tcell.KeyEscape: // We might be done.
|
||||
if i.autocompleteList != nil {
|
||||
i.autocompleteList = nil
|
||||
} else {
|
||||
finish(key)
|
||||
}
|
||||
if i.finished != nil {
|
||||
i.finished(key)
|
||||
case tcell.KeyDown, tcell.KeyTab: // Autocomplete selection.
|
||||
if i.autocompleteList != nil {
|
||||
count := i.autocompleteList.GetItemCount()
|
||||
newEntry := i.autocompleteList.GetCurrentItem() + 1
|
||||
if newEntry >= count {
|
||||
newEntry = 0
|
||||
}
|
||||
i.autocompleteList.SetCurrentItem(newEntry)
|
||||
currentText, _ = i.autocompleteList.GetItemText(newEntry) // Don't trigger changed function twice.
|
||||
i.SetText(currentText)
|
||||
} else {
|
||||
finish(key)
|
||||
}
|
||||
case tcell.KeyUp, tcell.KeyBacktab: // Autocomplete selection.
|
||||
if i.autocompleteList != nil {
|
||||
newEntry := i.autocompleteList.GetCurrentItem() - 1
|
||||
if newEntry < 0 {
|
||||
newEntry = i.autocompleteList.GetItemCount() - 1
|
||||
}
|
||||
i.autocompleteList.SetCurrentItem(newEntry)
|
||||
currentText, _ = i.autocompleteList.GetItemText(newEntry) // Don't trigger changed function twice.
|
||||
i.SetText(currentText)
|
||||
} else {
|
||||
finish(key)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
7
vendor/github.com/rivo/tview/list.go
generated
vendored
7
vendor/github.com/rivo/tview/list.go
generated
vendored
@@ -95,13 +95,14 @@ func (l *List) SetCurrentItem(index int) *List {
|
||||
if index < 0 {
|
||||
index = 0
|
||||
}
|
||||
l.currentItem = index
|
||||
|
||||
if index != l.currentItem && l.changed != nil {
|
||||
item := l.items[l.currentItem]
|
||||
l.changed(l.currentItem, item.MainText, item.SecondaryText, item.Shortcut)
|
||||
item := l.items[index]
|
||||
l.changed(index, item.MainText, item.SecondaryText, item.Shortcut)
|
||||
}
|
||||
|
||||
l.currentItem = index
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
|
||||
15
vendor/github.com/rivo/tview/table.go
generated
vendored
15
vendor/github.com/rivo/tview/table.go
generated
vendored
@@ -355,9 +355,14 @@ func (t *Table) GetSelection() (row, column int) {
|
||||
|
||||
// Select sets the selected cell. Depending on the selection settings
|
||||
// specified via SetSelectable(), this may be an entire row or column, or even
|
||||
// ignored completely.
|
||||
// ignored completely. The "selection changed" event is fired if such a callback
|
||||
// is available (even if the selection ends up being the same as before, even if
|
||||
// cells are not selectable).
|
||||
func (t *Table) Select(row, column int) *Table {
|
||||
t.selectedRow, t.selectedColumn = row, column
|
||||
if t.selectionChanged != nil {
|
||||
t.selectionChanged(row, column)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
@@ -387,10 +392,10 @@ func (t *Table) SetSelectedFunc(handler func(row, column int)) *Table {
|
||||
return t
|
||||
}
|
||||
|
||||
// SetSelectionChangedFunc sets a handler which is called whenever the user
|
||||
// navigates to a new selection. The handler receives the position of the new
|
||||
// selection. If entire rows are selected, the column index is undefined.
|
||||
// Likewise for entire columns.
|
||||
// SetSelectionChangedFunc sets a handler which is called whenever the current
|
||||
// selection changes. The handler receives the position of the new selection.
|
||||
// If entire rows are selected, the column index is undefined. Likewise for
|
||||
// entire columns.
|
||||
func (t *Table) SetSelectionChangedFunc(handler func(row, column int)) *Table {
|
||||
t.selectionChanged = handler
|
||||
return t
|
||||
|
||||
7
vendor/github.com/rivo/tview/textview.go
generated
vendored
7
vendor/github.com/rivo/tview/textview.go
generated
vendored
@@ -939,8 +939,13 @@ func (t *TextView) Draw(screen tcell.Screen) {
|
||||
// If this view is not scrollable, we'll purge the buffer of lines that have
|
||||
// scrolled out of view.
|
||||
if !t.scrollable && t.lineOffset > 0 {
|
||||
t.buffer = t.buffer[t.index[t.lineOffset].Line:]
|
||||
if t.lineOffset <= len(t.index) {
|
||||
t.buffer = nil
|
||||
} else {
|
||||
t.buffer = t.buffer[t.index[t.lineOffset].Line:]
|
||||
}
|
||||
t.index = nil
|
||||
t.lineOffset = 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
86
vendor/github.com/rivo/tview/util.go
generated
vendored
86
vendor/github.com/rivo/tview/util.go
generated
vendored
@@ -24,7 +24,7 @@ var (
|
||||
regionPattern = regexp.MustCompile(`\["([a-zA-Z0-9_,;: \-\.]*)"\]`)
|
||||
escapePattern = regexp.MustCompile(`\[([a-zA-Z0-9_,;: \-\."#]+)\[(\[*)\]`)
|
||||
nonEscapePattern = regexp.MustCompile(`(\[[a-zA-Z0-9_,;: \-\."#]+\[*)\]`)
|
||||
boundaryPattern = regexp.MustCompile(`(([[:punct:]]|\n)[ \t\f\r]*|(\s+))`)
|
||||
boundaryPattern = regexp.MustCompile(`(([,\.\-:;!\?&#+]|\n)[ \t\f\r]*|([ \t\f\r]+))`)
|
||||
spacePattern = regexp.MustCompile(`\s+`)
|
||||
)
|
||||
|
||||
@@ -454,8 +454,8 @@ func WordWrap(text string, width int) (lines []string) {
|
||||
var (
|
||||
colorPos, escapePos, breakpointPos, tagOffset int
|
||||
lastBreakpoint, lastContinuation, currentLineStart int
|
||||
lineWidth, continuationWidth int
|
||||
newlineBreakpoint bool
|
||||
lineWidth, overflow int
|
||||
forceBreak bool
|
||||
)
|
||||
unescape := func(substr string, startIndex int) string {
|
||||
// A helper function to unescape escaped tags.
|
||||
@@ -468,54 +468,65 @@ func WordWrap(text string, width int) (lines []string) {
|
||||
return substr
|
||||
}
|
||||
iterateString(strippedText, func(main rune, comb []rune, textPos, textWidth, screenPos, screenWidth int) bool {
|
||||
// Handle colour tags.
|
||||
if colorPos < len(colorTagIndices) && textPos+tagOffset >= colorTagIndices[colorPos][0] && textPos+tagOffset < colorTagIndices[colorPos][1] {
|
||||
tagOffset += colorTagIndices[colorPos][1] - colorTagIndices[colorPos][0]
|
||||
colorPos++
|
||||
}
|
||||
|
||||
// Handle escape tags.
|
||||
if escapePos < len(escapeIndices) && textPos+tagOffset == escapeIndices[escapePos][1]-2 {
|
||||
tagOffset++
|
||||
escapePos++
|
||||
}
|
||||
|
||||
// Check if a break is warranted.
|
||||
afterContinuation := lastContinuation > 0 && textPos+tagOffset >= lastContinuation
|
||||
noBreakpoint := lastContinuation == 0
|
||||
beyondWidth := lineWidth > 0 && lineWidth > width
|
||||
if beyondWidth && noBreakpoint {
|
||||
// We need a hard break without a breakpoint.
|
||||
lines = append(lines, unescape(text[currentLineStart:textPos+tagOffset], currentLineStart))
|
||||
currentLineStart = textPos + tagOffset
|
||||
lineWidth = continuationWidth
|
||||
} else if afterContinuation && (beyondWidth || newlineBreakpoint) {
|
||||
// Break at last breakpoint or at newline.
|
||||
lines = append(lines, unescape(text[currentLineStart:lastBreakpoint], currentLineStart))
|
||||
currentLineStart = lastContinuation
|
||||
lineWidth = continuationWidth
|
||||
lastBreakpoint, lastContinuation, newlineBreakpoint = 0, 0, false
|
||||
// Handle tags.
|
||||
for {
|
||||
if colorPos < len(colorTagIndices) && textPos+tagOffset >= colorTagIndices[colorPos][0] && textPos+tagOffset < colorTagIndices[colorPos][1] {
|
||||
// Colour tags.
|
||||
tagOffset += colorTagIndices[colorPos][1] - colorTagIndices[colorPos][0]
|
||||
colorPos++
|
||||
} else if escapePos < len(escapeIndices) && textPos+tagOffset == escapeIndices[escapePos][1]-2 {
|
||||
// Escape tags.
|
||||
tagOffset++
|
||||
escapePos++
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Is this a breakpoint?
|
||||
if breakpointPos < len(breakpoints) && textPos == breakpoints[breakpointPos][0] {
|
||||
if breakpointPos < len(breakpoints) && textPos+tagOffset == breakpoints[breakpointPos][0] {
|
||||
// Yes, it is. Set up breakpoint infos depending on its type.
|
||||
lastBreakpoint = breakpoints[breakpointPos][0] + tagOffset
|
||||
lastContinuation = breakpoints[breakpointPos][1] + tagOffset
|
||||
newlineBreakpoint = main == '\n'
|
||||
if breakpoints[breakpointPos][6] < 0 && !newlineBreakpoint {
|
||||
overflow = 0
|
||||
forceBreak = main == '\n'
|
||||
if breakpoints[breakpointPos][6] < 0 && !forceBreak {
|
||||
lastBreakpoint++ // Don't skip punctuation.
|
||||
}
|
||||
breakpointPos++
|
||||
}
|
||||
|
||||
// Once we hit the continuation point, we start buffering widths.
|
||||
if textPos+tagOffset < lastContinuation {
|
||||
continuationWidth = 0
|
||||
// Check if a break is warranted.
|
||||
if forceBreak || lineWidth > 0 && lineWidth+screenWidth > width {
|
||||
breakpoint := lastBreakpoint
|
||||
continuation := lastContinuation
|
||||
if forceBreak {
|
||||
breakpoint = textPos + tagOffset
|
||||
continuation = textPos + tagOffset + 1
|
||||
lastBreakpoint = 0
|
||||
overflow = 0
|
||||
} else if lastBreakpoint <= currentLineStart {
|
||||
breakpoint = textPos + tagOffset
|
||||
continuation = textPos + tagOffset
|
||||
overflow = 0
|
||||
}
|
||||
lines = append(lines, unescape(text[currentLineStart:breakpoint], currentLineStart))
|
||||
currentLineStart, lineWidth, forceBreak = continuation, overflow, false
|
||||
}
|
||||
|
||||
// Remember the characters since the last breakpoint.
|
||||
if lastBreakpoint > 0 && lastContinuation <= textPos+tagOffset {
|
||||
overflow += screenWidth
|
||||
}
|
||||
|
||||
// Advance.
|
||||
lineWidth += screenWidth
|
||||
continuationWidth += screenWidth
|
||||
|
||||
// But if we're still inside a breakpoint, skip next character (whitespace).
|
||||
if textPos+tagOffset < currentLineStart {
|
||||
lineWidth -= screenWidth
|
||||
}
|
||||
|
||||
return false
|
||||
})
|
||||
|
||||
@@ -558,7 +569,6 @@ func iterateString(text string, callback func(main rune, comb []rune, textPos, t
|
||||
comb = r[1:]
|
||||
}
|
||||
|
||||
// panic(fmt.Sprintf(`from=%d to=%d screenPos=%d width=%d`, from, to, screenPos, width))
|
||||
if callback(r[0], comb, from, to-from, screenPos, width) {
|
||||
return true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user