[GH-ISSUE #898] List.RemoveItem() #652

Closed
opened 2026-03-04 01:06:47 +03:00 by kerem · 3 comments
Owner

Originally created by @daniel-p-h on GitHub (Oct 6, 2023).
Original GitHub issue: https://github.com/rivo/tview/issues/898

Hi, I've just started toying with go so this might be my bad code, or a side effect of language features I don't understand.

When trying to put together a dynamic list the behaviour I'm experiencing is very unusal. I'm not entirely sure what it's doing to be honest, but it's not what I expected which is for items to be removed / added as per the result of strings.Contains(item, searchQuery).

Example code:

package main

import (
	"strconv"
	"strings"

	"github.com/gdamore/tcell/v2"
	"github.com/rivo/tview"
)

var (
	app        = tview.NewApplication()
	flex       = tview.NewFlex()
	testList   = tview.NewList()
	testSearch = tview.NewInputField()
	testOutput = tview.NewTextView()

	removedItems []string
)

func main() {

	testList.
		ShowSecondaryText(false).
		SetBorder(true).
		SetTitle("items")

	testList.AddItem("a", "", 0, nil)
	testList.AddItem("ants", "", 0, nil)
	testList.AddItem("antelope", "", 0, nil)
	testList.AddItem("assess", "", 0, nil)
	testList.AddItem("bears", "", 0, nil)
	testList.AddItem("london", "", 0, nil)
	testList.AddItem("bigtown-not-chicago", "", 0, nil)
	testList.AddItem("some-other-type-of-example", "", 0, nil)

	testSearch.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
		search(event)
		return event
	})

	flex.SetDirection(tview.FlexRow)
	flex.AddItem(testSearch, 0, 1, true)
	flex.AddItem(testList, 0, 10, false)
	flex.AddItem(testOutput, 0, 1, false)

	if err := app.SetRoot(flex, true).EnableMouse(true).Run(); err != nil {
		panic(err)
	}
}

func search(key *tcell.EventKey) {
	length := len(testSearch.GetText())
	previousSearch := testSearch.GetText()
	searchVal := ""

	if key.Key() == tcell.KeyBS {
		searchVal = previousSearch[:length-1]
	} else if key.Key() == tcell.KeyRune {
		searchVal = previousSearch + string(key.Rune())
	} else {
		return
	}

	if searchVal == "" {
		return
	}

	for i := 0; i < testList.GetItemCount(); i++ {
		primary, _ := testList.GetItemText(i)
		testOutput.Write([]byte(primary + " == " + searchVal + ": " + strconv.FormatBool(strings.Contains(primary, searchVal)) + "\n"))
		if !strings.Contains(primary, searchVal) {
			removedItems = append(removedItems, primary)
			testList = testList.RemoveItem(i)
		}
	}
	j := 0
	for i := 0; i < len(removedItems); i++ {
		if len(searchVal) >= 2 && !strings.Contains(removedItems[i], searchVal) {
			testList = testList.AddItem(removedItems[i], "", 0, nil)
		} else {
			removedItems[j] = removedItems[i]
			j++
		}
	}
	removedItems = removedItems[:j]
}
Originally created by @daniel-p-h on GitHub (Oct 6, 2023). Original GitHub issue: https://github.com/rivo/tview/issues/898 Hi, I've just started toying with go so this might be my bad code, or a side effect of language features I don't understand. When trying to put together a dynamic list the behaviour I'm experiencing is very unusal. I'm not entirely sure what it's doing to be honest, but it's not what I expected which is for items to be removed / added as per the result of strings.Contains(item, searchQuery). Example code: ```go package main import ( "strconv" "strings" "github.com/gdamore/tcell/v2" "github.com/rivo/tview" ) var ( app = tview.NewApplication() flex = tview.NewFlex() testList = tview.NewList() testSearch = tview.NewInputField() testOutput = tview.NewTextView() removedItems []string ) func main() { testList. ShowSecondaryText(false). SetBorder(true). SetTitle("items") testList.AddItem("a", "", 0, nil) testList.AddItem("ants", "", 0, nil) testList.AddItem("antelope", "", 0, nil) testList.AddItem("assess", "", 0, nil) testList.AddItem("bears", "", 0, nil) testList.AddItem("london", "", 0, nil) testList.AddItem("bigtown-not-chicago", "", 0, nil) testList.AddItem("some-other-type-of-example", "", 0, nil) testSearch.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { search(event) return event }) flex.SetDirection(tview.FlexRow) flex.AddItem(testSearch, 0, 1, true) flex.AddItem(testList, 0, 10, false) flex.AddItem(testOutput, 0, 1, false) if err := app.SetRoot(flex, true).EnableMouse(true).Run(); err != nil { panic(err) } } func search(key *tcell.EventKey) { length := len(testSearch.GetText()) previousSearch := testSearch.GetText() searchVal := "" if key.Key() == tcell.KeyBS { searchVal = previousSearch[:length-1] } else if key.Key() == tcell.KeyRune { searchVal = previousSearch + string(key.Rune()) } else { return } if searchVal == "" { return } for i := 0; i < testList.GetItemCount(); i++ { primary, _ := testList.GetItemText(i) testOutput.Write([]byte(primary + " == " + searchVal + ": " + strconv.FormatBool(strings.Contains(primary, searchVal)) + "\n")) if !strings.Contains(primary, searchVal) { removedItems = append(removedItems, primary) testList = testList.RemoveItem(i) } } j := 0 for i := 0; i < len(removedItems); i++ { if len(searchVal) >= 2 && !strings.Contains(removedItems[i], searchVal) { testList = testList.AddItem(removedItems[i], "", 0, nil) } else { removedItems[j] = removedItems[i] j++ } } removedItems = removedItems[:j] } ```
kerem closed this issue 2026-03-04 01:06:47 +03:00
Author
Owner

@daniel-p-h commented on GitHub (Oct 7, 2023):

Closed, my bad code! Logic for moving items back into the list is to blame

<!-- gh-comment-id:1751602334 --> @daniel-p-h commented on GitHub (Oct 7, 2023): Closed, my bad code! Logic for moving items back into the list is to blame
Author
Owner

@rivo commented on GitHub (Oct 7, 2023):

Ok. You may also want to think about using SetChangedFunc() instead of SetInputCapture(). SetInputCapture() is meant to intercept actual key stroke events while SetChangedFunc() handles all common key strokes for you and then simply informs you that the content of the InputField has changed.

<!-- gh-comment-id:1751640189 --> @rivo commented on GitHub (Oct 7, 2023): Ok. You may also want to think about using [`SetChangedFunc()`](https://pkg.go.dev/github.com/rivo/tview#InputField.SetChangedFunc) instead of `SetInputCapture()`. `SetInputCapture()` is meant to intercept actual key stroke events while `SetChangedFunc()` handles all common key strokes for you and then simply informs you that the content of the `InputField` has changed.
Author
Owner

@daniel-p-h commented on GitHub (Oct 7, 2023):

Ok. You may also want to think about using SetChangedFunc() instead of SetInputCapture(). SetInputCapture() is meant to intercept actual key stroke events while SetChangedFunc() handles all common key strokes for you and then simply informs you that the content of the InputField has changed.

I did notice this after I posted and it works much better, but thanks for taking the time to read!

<!-- gh-comment-id:1751655493 --> @daniel-p-h commented on GitHub (Oct 7, 2023): > Ok. You may also want to think about using [`SetChangedFunc()`](https://pkg.go.dev/github.com/rivo/tview#InputField.SetChangedFunc) instead of `SetInputCapture()`. `SetInputCapture()` is meant to intercept actual key stroke events while `SetChangedFunc()` handles all common key strokes for you and then simply informs you that the content of the `InputField` has changed. I did notice this after I posted and it works much better, but thanks for taking the time to read!
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/tview#652
No description provided.