diff --git a/go.mod b/go.mod index 4c3745fd0..e2336b4ea 100644 --- a/go.mod +++ b/go.mod @@ -65,7 +65,7 @@ require ( github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.66.1 github.com/prometheus/procfs v0.16.1 // indirect - github.com/rivo/tview v0.0.0-20250501113434-0c592cd31026 + github.com/rivo/tview v0.42.0 github.com/rivo/uniseg v0.4.7 // indirect github.com/segmentio/kafka-go v0.4.49 // indirect github.com/spf13/pflag v1.0.9 // indirect diff --git a/go.sum b/go.sum index 92ca38d29..ce88f51b4 100644 --- a/go.sum +++ b/go.sum @@ -156,8 +156,8 @@ github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9Z github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= -github.com/rivo/tview v0.0.0-20250501113434-0c592cd31026 h1:ij8h8B3psk3LdMlqkfPTKIzeGzTaZLOiyplILMlxPAM= -github.com/rivo/tview v0.0.0-20250501113434-0c592cd31026/go.mod h1:02iFIz7K/A9jGCvrizLPvoqr4cEIx7q54RH5Qudkrss= +github.com/rivo/tview v0.42.0 h1:b/ftp+RxtDsHSaynXTbJb+/n/BxDEi+W3UfF5jILK6c= +github.com/rivo/tview v0.42.0/go.mod h1:cSfIYfhpSGCjp3r/ECJb+GKS7cGJnqV8vfjQPwoXyfY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= diff --git a/vendor/github.com/rivo/tview/README.md b/vendor/github.com/rivo/tview/README.md index 75e4bac22..245f9b856 100644 --- a/vendor/github.com/rivo/tview/README.md +++ b/vendor/github.com/rivo/tview/README.md @@ -140,6 +140,7 @@ For a presentation highlighting this package, compile and run the program found - [chiko: Ultimate Beauty TUI gRPC Client](https://github.com/felangga/chiko) - [kmip-explorer: Browse & manage your KMIP objects from the terminal](https://github.com/phsym/kmip-explorer) - [stui: Slurm TUI for managing HPC clusters](https://github.com/antvirf/stui) +- [nerdlog: Fast, remote-first, multi-host log viewer with timeline histogram](https://github.com/dimonomid/nerdlog) ## Documentation @@ -153,9 +154,9 @@ This package is based on [github.com/gdamore/tcell](https://github.com/gdamore/t [Become a Sponsor on GitHub](https://github.com/sponsors/rivo?metadata_source=tview_readme) to further this project! -## Versioning and Backwards-Compatibility +## Backwards-Compatibility -I try really hard to keep this project backwards compatible. Your software should not break when you upgrade `tview`. But this also means that some of its shortcomings that were present in the initial versions will remain. In addition, at least for the time being, you won't find any version tags in this repo. The newest version should be the one to upgrade to. It has all the bugfixes and latest features. Having said that, backwards compatibility may still break when: +I try really hard to keep this project backwards compatible. Your software should not break when you upgrade `tview`. But this also means that some of its shortcomings that were present in the initial versions will remain. Having said that, backwards compatibility may still break when: - a new version of an imported package (most likely [`tcell`](https://github.com/gdamore/tcell)) changes in such a way that forces me to make changes in `tview` as well, - I fix something that I consider a bug, rather than a feature, something that does not work as originally intended, diff --git a/vendor/github.com/rivo/tview/ansi.go b/vendor/github.com/rivo/tview/ansi.go index 1b7d2e3c1..53bccd109 100644 --- a/vendor/github.com/rivo/tview/ansi.go +++ b/vendor/github.com/rivo/tview/ansi.go @@ -95,11 +95,9 @@ func (a *ansi) Write(text []byte) (int, error) { fields := strings.Split(params, ";") if len(params) == 0 || fields[0] == "" || fields[0] == "0" { // Reset. - a.attributes = "" - if _, err := a.buffer.WriteString("[-:-:-]"); err != nil { - return 0, err - } - break + foreground = "-" + background = "-" + a.attributes = "-" } lookupColor := func(colorNumber int) string { if colorNumber < 0 || colorNumber > 15 { @@ -232,6 +230,9 @@ func (a *ansi) Write(text []byte) (int, error) { } } var colon string + if len(a.attributes) > 1 && a.attributes[0] == '-' { + a.attributes = a.attributes[1:] + } if len(a.attributes) > 0 { colon = ":" } diff --git a/vendor/github.com/rivo/tview/application.go b/vendor/github.com/rivo/tview/application.go index 6e6666b1d..3c5fde846 100644 --- a/vendor/github.com/rivo/tview/application.go +++ b/vendor/github.com/rivo/tview/application.go @@ -77,6 +77,10 @@ type Application struct { // Fini(), to set a new screen (or nil to stop the application). screen tcell.Screen + // The application's title. If not empty, it will be set on every new screen + // that is added. + title string + // The primitive which currently has the keyboard focus. focus Primitive @@ -187,7 +191,9 @@ func (a *Application) GetMouseCapture() func(event *tcell.EventMouse, action Mou // SetScreen allows you to provide your own tcell.Screen object. For most // applications, this is not needed and you should be familiar with -// tcell.Screen when using this function. +// tcell.Screen when using this function. As the tcell.Screen interface may +// change in the future, you may need to update your code when this package +// updates to a new tcell version. // // This function is typically called before the first call to Run(). Init() need // not be called on the screen. @@ -214,6 +220,19 @@ func (a *Application) SetScreen(screen tcell.Screen) *Application { return a } +// SetTitle sets the title of the terminal window, to the extent that the +// terminal supports it. A non-empty title will be set on every new tcell.Screen +// that is created by or added to this application. +func (a *Application) SetTitle(title string) *Application { + a.Lock() + defer a.Unlock() + a.title = title + if a.screen != nil { + a.screen.SetTitle(title) + } + return a +} + // EnableMouse enables mouse events or disables them (if "false" is provided). func (a *Application) EnableMouse(enable bool) *Application { a.Lock() @@ -286,6 +305,9 @@ func (a *Application) Run() error { } else { a.screen.DisablePaste() } + if a.title != "" { + a.screen.SetTitle(a.title) + } } // We catch panics to clean up because they mess up the terminal. @@ -354,6 +376,9 @@ func (a *Application) Run() error { } else { screen.DisablePaste() } + if a.title != "" { + screen.SetTitle(a.title) + } a.draw() } }() diff --git a/vendor/github.com/rivo/tview/box.go b/vendor/github.com/rivo/tview/box.go index 04ce08523..c05994cc5 100644 --- a/vendor/github.com/rivo/tview/box.go +++ b/vendor/github.com/rivo/tview/box.go @@ -314,7 +314,7 @@ func (b *Box) SetBorderColor(color tcell.Color) *Box { // SetBorderAttributes sets the border's style attributes. You can combine // different attributes using bitmask operations: // -// box.SetBorderAttributes(tcell.AttrUnderline | tcell.AttrBold) +// box.SetBorderAttributes(tcell.AttrItalic | tcell.AttrBold) func (b *Box) SetBorderAttributes(attr tcell.AttrMask) *Box { b.borderStyle = b.borderStyle.Attributes(attr) return b diff --git a/vendor/github.com/rivo/tview/doc.go b/vendor/github.com/rivo/tview/doc.go index bfefa03a1..b4ddbc664 100644 --- a/vendor/github.com/rivo/tview/doc.go +++ b/vendor/github.com/rivo/tview/doc.go @@ -65,7 +65,7 @@ Throughout this package, styles are specified using the [tcell.Style] type. Styles specify colors with the [tcell.Color] type. Functions such as [tcell.GetColor], [tcell.NewHexColor], and [tcell.NewRGBColor] can be used to create colors from W3C color names or RGB values. The [tcell.Style] type also -allows you to specify text attributes such as "bold" or "underline" or a URL +allows you to specify text attributes such as "bold" or "italic" or a URL which some terminals use to display hyperlinks. Almost all strings which are displayed may contain style tags. A style tag's diff --git a/vendor/github.com/rivo/tview/inputfield.go b/vendor/github.com/rivo/tview/inputfield.go index 2edc98d5f..f5439343b 100644 --- a/vendor/github.com/rivo/tview/inputfield.go +++ b/vendor/github.com/rivo/tview/inputfield.go @@ -542,14 +542,11 @@ func (i *InputField) InputHandler() func(event *tcell.EventKey, setFocus func(p var skipAutocomplete bool currentText := i.textArea.GetText() defer func() { - newText := i.textArea.GetText() - if newText != currentText { - if !skipAutocomplete { - i.Autocomplete() - } - if i.changed != nil { - i.changed(newText) - } + if skipAutocomplete { + return + } + if i.textArea.GetText() != currentText { + i.Autocomplete() } }() @@ -649,14 +646,11 @@ func (i *InputField) MouseHandler() func(action MouseAction, event *tcell.EventM var skipAutocomplete bool currentText := i.GetText() defer func() { - newText := i.GetText() - if newText != currentText { - if !skipAutocomplete { - i.Autocomplete() - } - if i.changed != nil { - i.changed(newText) - } + if skipAutocomplete { + return + } + if i.textArea.GetText() != currentText { + i.Autocomplete() } }() diff --git a/vendor/github.com/rivo/tview/pages.go b/vendor/github.com/rivo/tview/pages.go index 83410ada0..d2b6dbd3c 100644 --- a/vendor/github.com/rivo/tview/pages.go +++ b/vendor/github.com/rivo/tview/pages.go @@ -66,12 +66,12 @@ func (p *Pages) GetPageNames(visibleOnly bool) []string { // AddPage adds a new page with the given name and primitive. If there was // previously a page with the same name, it is overwritten. Leaving the name -// empty may cause conflicts in other functions so always specify a non-empty -// name. +// empty may cause conflicts in other functions so you should always specify a +// non-empty name. // // Visible pages will be drawn in the order they were added (unless that order // was changed in one of the other functions). If "resize" is set to true, the -// primitive will be set to the size available to the Pages primitive whenever +// primitive will be set to the size available to the [Pages] primitive whenever // the pages are drawn. func (p *Pages) AddPage(name string, item Primitive, resize, visible bool) *Pages { hasFocus := p.HasFocus() @@ -248,6 +248,17 @@ func (p *Pages) GetFrontPage() (name string, item Primitive) { return } +// GetPage returns the page with the given name. If no such page exists, nil is +// returned. +func (p *Pages) GetPage(name string) Primitive { + for _, page := range p.pages { + if page.Name == name { + return page.Item + } + } + return nil +} + // HasFocus returns whether or not this primitive has focus. func (p *Pages) HasFocus() bool { for _, page := range p.pages { diff --git a/vendor/github.com/rivo/tview/strings.go b/vendor/github.com/rivo/tview/strings.go index 81c6a7112..1c13fe233 100644 --- a/vendor/github.com/rivo/tview/strings.go +++ b/vendor/github.com/rivo/tview/strings.go @@ -254,7 +254,6 @@ func parseTag(str string, state *stepState) (length int, style tcell.Style, regi // Attribute map. attrs := map[byte]tcell.AttrMask{ 'B': tcell.AttrBold, - 'U': tcell.AttrUnderline, 'I': tcell.AttrItalic, 'L': tcell.AttrBlink, 'D': tcell.AttrDim, @@ -284,17 +283,18 @@ func parseTag(str string, state *stepState) (length int, style tcell.Style, regi return } case tagStateStart: - if ch == '"' { // Start of a region tag. + switch { + case ch == '"': // Start of a region tag. tempStr.Reset() tagState = tagStateRegionStart - } else if !isOneOf(ch, "#:-") { // Invalid style tag. + case !isOneOf(ch, "#:-"): // Invalid style tag. return - } else if ch == '-' { // Reset foreground color. + case ch == '-': // Reset foreground color. tStyle = tStyle.Foreground(state.initialForeground) tagState = tagStateEndForeground - } else if ch == ':' { // No foreground color. + case ch == ':': // No foreground color. tagState = tagStateStartBackground - } else { + default: tempStr.Reset() tempStr.WriteByte(ch) if ch == '#' { // Numeric foreground color. @@ -304,11 +304,12 @@ func parseTag(str string, state *stepState) (length int, style tcell.Style, regi } } case tagStateEndForeground: - if ch == ']' { // End of tag. + switch ch { + case ']': // End of tag. tagState = tagStateDoneTag - } else if ch == ':' { + case ':': tagState = tagStateStartBackground - } else { // Invalid tag. + default: // Invalid tag. return } case tagStateNumericForeground: @@ -318,14 +319,15 @@ func parseTag(str string, state *stepState) (length int, style tcell.Style, regi } tStyle = tStyle.Foreground(tcell.GetColor(tempStr.String())) } - if ch == ']' { // End of tag. + switch { + case ch == ']': // End of tag. tagState = tagStateDoneTag - } else if ch == ':' { // Start of background color. + case ch == ':': // Start of background color. tagState = tagStateStartBackground - } else if strings.IndexByte("0123456789abcdefABCDEF", ch) >= 0 { // Hex digit. + case strings.IndexByte("0123456789abcdefABCDEF", ch) >= 0: // Hex digit. tempStr.WriteByte(ch) tagState = tagStateNumericForeground - } else { // Invalid tag. + default: // Invalid tag. return } case tagStateNameForeground: @@ -336,26 +338,28 @@ func parseTag(str string, state *stepState) (length int, style tcell.Style, regi } tStyle = tStyle.Foreground(tcell.ColorNames[name]) } - if !isOneOf(ch, "]:") { // Invalid tag. + switch { + case !isOneOf(ch, "]:"): // Invalid tag. return - } else if ch == ']' { // End of tag. + case ch == ']': // End of tag. tagState = tagStateDoneTag - } else if ch == ':' { // Start of background color. + case ch == ':': // Start of background color. tagState = tagStateStartBackground - } else { // Letters or numbers. + default: // Letters or numbers. tempStr.WriteByte(ch) } case tagStateStartBackground: - if !isOneOf(ch, "#:-]") { // Invalid style tag. + switch { + case !isOneOf(ch, "#:-]"): // Invalid style tag. return - } else if ch == ']' { // End of tag. + case ch == ']': // End of tag. tagState = tagStateDoneTag - } else if ch == '-' { // Reset background color. + case ch == '-': // Reset background color. tStyle = tStyle.Background(state.initialBackground) tagState = tagStateEndBackground - } else if ch == ':' { // No background color. + case ch == ':': // No background color. tagState = tagStateStartAttributes - } else { + default: tempStr.Reset() tempStr.WriteByte(ch) if ch == '#' { // Numeric background color. @@ -365,11 +369,12 @@ func parseTag(str string, state *stepState) (length int, style tcell.Style, regi } } case tagStateEndBackground: - if ch == ']' { // End of tag. + switch ch { + case ']': // End of tag. tagState = tagStateDoneTag - } else if ch == ':' { // Start of attributes. + case ':': // Start of attributes. tagState = tagStateStartAttributes - } else { // Invalid tag. + default: // Invalid tag. return } case tagStateNumericBackground: @@ -397,28 +402,30 @@ func parseTag(str string, state *stepState) (length int, style tcell.Style, regi } tStyle = tStyle.Background(tcell.ColorNames[name]) } - if !isOneOf(ch, "]:") { // Invalid tag. + switch { + case !isOneOf(ch, "]:"): // Invalid tag. return - } else if ch == ']' { // End of tag. + case ch == ']': // End of tag. tagState = tagStateDoneTag - } else if ch == ':' { // Start of background color. + case ch == ':': // Start of background color. tagState = tagStateStartAttributes - } else { // Letters or numbers. + default: // Letters or numbers. tempStr.WriteByte(ch) } case tagStateStartAttributes: - if ch == ']' { // End of tag. + switch { + case ch == ']': // End of tag. tagState = tagStateDoneTag - } else if ch == '-' { // Reset attributes. + case ch == '-': // Reset attributes. tStyle = tStyle.Attributes(state.initialAttributes) tagState = tagStateEndAttributes - } else if ch == ':' { // Start of URL. + case ch == ':': // Start of URL. tagState = tagStateStartURL - } else if strings.IndexByte("buildsrBUILDSR", ch) >= 0 { // Attribute tag. + case strings.IndexByte("buildsrBUILDSR", ch) >= 0: // Attribute tag. tempStr.Reset() tempStr.WriteByte(ch) tagState = tagStateAttributes - } else { // Invalid tag. + default: // Invalid tag. return } case tagStateAttributes: @@ -427,38 +434,46 @@ func parseTag(str string, state *stepState) (length int, style tcell.Style, regi _, _, a := tStyle.Decompose() for index := 0; index < len(flags); index++ { ch := flags[index] - if ch >= 'a' && ch <= 'z' { + switch { + case ch == 'u': + tStyle = tStyle.Underline(true) + case ch == 'U': + tStyle = tStyle.Underline(false) + case ch >= 'a' && ch <= 'z': a |= attrs[ch-('a'-'A')] - } else { + default: a &^= attrs[ch] } } tStyle = tStyle.Attributes(a) } - if ch == ']' { // End of tag. + switch { + case ch == ']': // End of tag. tagState = tagStateDoneTag - } else if ch == ':' { // Start of URL. + case ch == ':': // Start of URL. tagState = tagStateStartURL - } else if strings.IndexByte("buildsrBUILDSR", ch) >= 0 { // Attribute tag. + case strings.IndexByte("buildsrBUILDSR", ch) >= 0: // Attribute tag. tempStr.WriteByte(ch) - } else { // Invalid tag. + default: // Invalid tag. return } case tagStateEndAttributes: - if ch == ']' { // End of tag. + switch ch { + case ']': // End of tag. tagState = tagStateDoneTag - } else if ch == ':' { // Start of URL. + case ':': // Start of URL. tagState = tagStateStartURL - } else { // Invalid tag. + default: // Invalid tag. return } case tagStateStartURL: - if ch == ']' { // End of tag. + switch ch { + case ']': // End of tag. tagState = tagStateDoneTag - } else if ch == '-' { // Reset URL. + case '-': // Reset URL. tStyle = tStyle.Url("").UrlId("") tagState = tagStateEndURL - } else { // URL character. + default: // URL character. tempStr.Reset() tempStr.WriteByte(ch) tStyle = tStyle.UrlId(strconv.Itoa(int(rand.Uint32()))) // Generate a unique ID for this URL. @@ -478,12 +493,13 @@ func parseTag(str string, state *stepState) (length int, style tcell.Style, regi tempStr.WriteByte(ch) } case tagStateRegionStart: - if ch == '"' { // End of region tag. + switch { + case ch == '"': // End of region tag. tagState = tagStateRegionEnd - } else if isOneOf(ch, "_,;: -.") { // Region name. + case isOneOf(ch, "_,;: -."): // Region name. tempStr.WriteByte(ch) tagState = tagStateRegionName - } else { // Invalid tag. + default: // Invalid tag. return } case tagStateRegionEnd: @@ -494,11 +510,12 @@ func parseTag(str string, state *stepState) (length int, style tcell.Style, regi return } case tagStateRegionName: - if ch == '"' { // End of region tag. + switch { + case ch == '"': // End of region tag. tagState = tagStateRegionEnd - } else if isOneOf(ch, "_,;: -.") { // Region name. + case isOneOf(ch, "_,;: -."): // Region name. tempStr.WriteByte(ch) - } else { // Invalid tag. + default: // Invalid tag. return } } diff --git a/vendor/github.com/rivo/tview/table.go b/vendor/github.com/rivo/tview/table.go index 2dd88029b..c04fc4003 100644 --- a/vendor/github.com/rivo/tview/table.go +++ b/vendor/github.com/rivo/tview/table.go @@ -155,7 +155,7 @@ func (c *TableCell) SetTransparency(transparent bool) *TableCell { // SetAttributes sets the cell's text attributes. You can combine different // attributes using bitmask operations: // -// cell.SetAttributes(tcell.AttrUnderline | tcell.AttrBold) +// cell.SetAttributes(tcell.AttrItalic | tcell.AttrBold) func (c *TableCell) SetAttributes(attr tcell.AttrMask) *TableCell { if c.Style == tcell.StyleDefault { c.Attributes = attr @@ -1474,6 +1474,7 @@ func (t *Table) InputHandler() func(event *tcell.EventKey, setFocus func(p Primi down = func() { if t.rowsSelectable { + row, column := t.selectedRow, t.selectedColumn t.selectedRow++ if t.selectedRow >= rowCount { if t.wrapVertically { @@ -1482,7 +1483,6 @@ func (t *Table) InputHandler() func(event *tcell.EventKey, setFocus func(p Primi t.selectedRow = rowCount - 1 } } - row, column := t.selectedRow, t.selectedColumn finalRow, finalColumn := rowCount-1, lastColumn if t.wrapVertically { finalRow = row @@ -1499,6 +1499,7 @@ func (t *Table) InputHandler() func(event *tcell.EventKey, setFocus func(p Primi up = func() { if t.rowsSelectable { + row, column := t.selectedRow, t.selectedColumn t.selectedRow-- if t.selectedRow < 0 { if t.wrapVertically { @@ -1507,7 +1508,6 @@ func (t *Table) InputHandler() func(event *tcell.EventKey, setFocus func(p Primi t.selectedRow = 0 } } - row, column := t.selectedRow, t.selectedColumn finalRow, finalColumn := 0, 0 if t.wrapVertically { finalRow = row diff --git a/vendor/modules.txt b/vendor/modules.txt index dc74f006d..16e4f3038 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -262,7 +262,7 @@ github.com/prometheus/common/model github.com/prometheus/procfs github.com/prometheus/procfs/internal/fs github.com/prometheus/procfs/internal/util -# github.com/rivo/tview v0.0.0-20250501113434-0c592cd31026 +# github.com/rivo/tview v0.42.0 ## explicit; go 1.18 github.com/rivo/tview # github.com/rivo/uniseg v0.4.7