move autocomplete into separate file and improve event forwarding
MODIFY
tview/treeview.go
tview/treeview.go
@@ -831,18 +831,12 @@ func (t *TreeView) Draw(screen tcell.Screen) bool {
// InputHandler returns the handler for this primitive.
func (t *TreeView) InputHandler() InputHandlerFunc {
- return t.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) *tcell.EventKey {
- selectNode := func() {
- if t.currentNode != nil {
- if t.selected != nil {
- t.selected(t.currentNode)
- }
- if t.currentNode.selected != nil {
- t.currentNode.selected()
- }
- }
+ return t.WrapInputHandler(t.DefaultInputHandler)
}
+// DefaultInputHandler handles basic navigation and interaction with the
+// TreeView.
+func (t *TreeView) DefaultInputHandler(event *tcell.EventKey, setFocus func(p Primitive)) *tcell.EventKey {
// Because the tree is flattened into a list only at drawing time, we also
// postpone the (selection) movement to drawing time.
switch key := event.Key(); key {
@@ -888,14 +882,20 @@ func (t *TreeView) InputHandler() InputHandlerFunc {
}
}
case tcell.KeyEnter:
- selectNode()
+ if t.currentNode != nil {
+ if t.selected != nil {
+ t.selected(t.currentNode)
+ }
+ if t.currentNode.selected != nil {
+ t.currentNode.selected()
+ }
+ }
default:
return event
}
t.process()
return nil
- })
}
// FindFirstSelectableNode iterates through the tree from top to bottom, trying

ADD
ui/components/autocomplete.go
+package components
+
+import (
+ "github.com/Bios-Marcel/cordless/tview"
+ tcell "github.com/gdamore/tcell/v2"
+)
+
+// AutocompleteView is a simple treeview meant for displaying autocomplete
+// choices. The speccial part about this component is, that it can redirect
+// certain events to a different component, as only certain events are
+// treated directly.
+type AutocompleteView struct {
+ *tview.TreeView
+}
+
+// NewAutocompleteView creates a ready-to-use AutocompleteView.
+func NewAutocompleteView() *AutocompleteView {
+ treeView := tview.NewTreeView()
+ //Has to be disabled, as we need the events for the related editor.
+ treeView.
+ SetSearchOnTypeEnabled(false).
+ SetVimBindingsEnabled(false).
+ SetTopLevel(1).
+ SetCycleSelection(true)
+
+ return &AutocompleteView{treeView}
+}
+
+// InputHandler returns the handler for this primitive.
+func (a *AutocompleteView) InputHandler() tview.InputHandlerFunc {
+ return a.WrapInputHandler(a.DefaultInputHandler)
+}
+
+// WrapInputHandler unlike Box.WrapInputHandler calls the default handler
+// first, as all other shortcuts are meant to be forwarded. However, not
+// all events are handled by the TreeView, as some features aren't desired.
+func (a *AutocompleteView) WrapInputHandler(inputHandler tview.InputHandlerFunc) tview.InputHandlerFunc {
+ return func(event *tcell.EventKey, setFocus func(p tview.Primitive)) *tcell.EventKey {
+ switch key := event.Key(); key {
+ //FIXME Maybe this should be made configurable as well
+ case tcell.KeyDown, tcell.KeyUp, tcell.KeyPgDn, tcell.KeyPgUp,
+ tcell.KeyEnter, tcell.KeyHome, tcell.KeyEnd:
+ if inputHandler != nil {
+ event = inputHandler(event, setFocus)
+ }
+ }
+
+ if event != nil {
+ inputCapture := a.GetInputCapture()
+ if inputCapture != nil {
+ event = inputCapture(event)
+ }
+ }
+
+ return event
+ }
+}

MODIFY
ui/window.go
ui/window.go
@@ -133,13 +133,11 @@ func NewWindow(app *tview.Application, session *discordgo.Session, readyEvent *d
guilds := readyEvent.Guilds
mentionWindowRootNode := tview.NewTreeNode("")
- autocompleteView := tview.NewTreeView().
- SetVimBindingsEnabled(false).
+ autocompleteView := components.NewAutocompleteView()
+ autocompleteView.
SetRoot(mentionWindowRootNode).
- SetTopLevel(1).
- SetCycleSelection(true)
- autocompleteView.SetBorder(true)
- autocompleteView.SetBorderSides(false, true, false, true)
+ SetBorder(true).
+ SetBorderSides(false, true, false, true)
window.leftArea = tview.NewFlex().SetDirection(tview.FlexRow)
@@ -423,7 +421,12 @@ func NewWindow(app *tview.Application, session *discordgo.Session, readyEvent *d
autocompleteView.SetCurrentNode(rootNode)
autocompleteView.SetVisible(true)
window.app.SetFocus(autocompleteView)
- window.chatArea.ResizeItem(autocompleteView, maths.Min(10, len(values)), 0)
+ _, _, _, height := window.app.GetRoot().GetRect()
+ //The preferred height is limited to a certain to avoid the
+ //autocomplete taking too much space in small windows, or
+ //furthermore terminals with a big font size.
+ prefHeight := maths.Min(maths.Min(10, height/4), len(values))
+ window.chatArea.ResizeItem(autocompleteView, prefHeight, 0)
}
})
@@ -881,14 +884,12 @@ func NewWindow(app *tview.Application, session *discordgo.Session, readyEvent *d
window.updateUserList()
autocompleteView.SetVisible(false)
- //FIXME this probably needs to be adapted to custom bindings
+
+ //All uncaptured events, e.g. events not relevant for TreeViews, will be
+ //forwarded to the message input, as both full typing capability, but also
+ //autocomplete capability should work at the same time.
autocompleteView.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
- switch key := event.Key(); key {
- case tcell.KeyRune, tcell.KeyDelete, tcell.KeyBackspace, tcell.KeyBackspace2, tcell.KeyLeft, tcell.KeyRight, tcell.KeyCtrlA, tcell.KeyCtrlV:
- window.messageInput.internalTextView.GetInputCapture()(event)
- return nil
- }
- return event
+ return window.messageInput.internalTextView.GetInputCapture()(event)
})
window.chatArea.AddItem(window.messageContainer, 0, 1, false)

move autocomplete into separate file and improve event forwarding