move autocomplete into separate file and improve event forwarding

This commit is contained in:
Marcel Schramm 2020-11-19 20:17:31 +01:00
parent 4c83b1448c
commit 61d36aebba
No known key found for this signature in database
GPG Key ID: 05971054C70EEDC7
3 changed files with 131 additions and 73 deletions

View File

@ -831,71 +831,71 @@ 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 {
case tcell.KeyTab, tcell.KeyDown, tcell.KeyRight:
t.movement = treeDown
case tcell.KeyBacktab, tcell.KeyUp, tcell.KeyLeft:
t.movement = treeUp
case tcell.KeyHome:
t.movement = treeHome
case tcell.KeyEnd:
t.movement = treeEnd
case tcell.KeyPgDn, tcell.KeyCtrlF:
t.movement = treePageDown
case tcell.KeyPgUp, tcell.KeyCtrlB:
t.movement = treePageUp
case tcell.KeyRune:
if t.vimBindings {
switch event.Rune() {
case 'g':
t.movement = treeHome
case 'G':
t.movement = treeEnd
case 'j':
t.movement = treeDown
case 'k':
t.movement = treeUp
default:
return event
}
} else if t.searchOnType {
if time.Since(t.jumpTime) > (500 * time.Millisecond) {
t.jumpBuffer = ""
}
if event.Key() == tcell.KeyRune {
t.jumpTime = time.Now()
t.jumpBuffer += strings.ToLower(string(event.Rune()))
node := t.FindFirstSelectableNode(t.GetRoot(), t.jumpBuffer)
if node != nil {
t.SetCurrentNode(node)
}
}
}
// 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 {
case tcell.KeyTab, tcell.KeyDown, tcell.KeyRight:
t.movement = treeDown
case tcell.KeyBacktab, tcell.KeyUp, tcell.KeyLeft:
t.movement = treeUp
case tcell.KeyHome:
t.movement = treeHome
case tcell.KeyEnd:
t.movement = treeEnd
case tcell.KeyPgDn, tcell.KeyCtrlF:
t.movement = treePageDown
case tcell.KeyPgUp, tcell.KeyCtrlB:
t.movement = treePageUp
case tcell.KeyRune:
if t.vimBindings {
switch event.Rune() {
case 'g':
t.movement = treeHome
case 'G':
t.movement = treeEnd
case 'j':
t.movement = treeDown
case 'k':
t.movement = treeUp
default:
return event
}
} else if t.searchOnType {
if time.Since(t.jumpTime) > (500 * time.Millisecond) {
t.jumpBuffer = ""
}
if event.Key() == tcell.KeyRune {
t.jumpTime = time.Now()
t.jumpBuffer += strings.ToLower(string(event.Rune()))
node := t.FindFirstSelectableNode(t.GetRoot(), t.jumpBuffer)
if node != nil {
t.SetCurrentNode(node)
}
}
case tcell.KeyEnter:
if t.currentNode != nil {
if t.selected != nil {
t.selected(t.currentNode)
}
if t.currentNode.selected != nil {
t.currentNode.selected()
}
case tcell.KeyEnter:
selectNode()
default:
return event
}
default:
return event
}
t.process()
return nil
})
t.process()
return nil
}
// FindFirstSelectableNode iterates through the tree from top to bottom, trying

View File

@ -0,0 +1,57 @@
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
}
}

View File

@ -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)