From ba379a1b4a97ee7eb56bed726f1c4edd76f76bb8 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 17 Mar 2018 14:32:01 +0200 Subject: [PATCH] Add basic username/id autocompletion --- advanced-inputfield.go | 11 ++++++++--- view-main.go | 39 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/advanced-inputfield.go b/advanced-inputfield.go index 97fbfab..8b5b47a 100644 --- a/advanced-inputfield.go +++ b/advanced-inputfield.go @@ -79,7 +79,7 @@ type AdvancedInputField struct { done func(tcell.Key) // An optional function which is called when the user presses tab. - tabComplete func(text string, cursorOffset int) + tabComplete func(text string, cursorOffset int) string } // NewAdvancedInputField returns a new input field. @@ -205,7 +205,7 @@ func (field *AdvancedInputField) SetDoneFunc(handler func(key tcell.Key)) *Advan return field } -func (field *AdvancedInputField) SetTabCompleteFunc(handler func(text string, cursorOffset int)) *AdvancedInputField { +func (field *AdvancedInputField) SetTabCompleteFunc(handler func(text string, cursorOffset int) string) *AdvancedInputField { field.tabComplete = handler return field } @@ -429,7 +429,12 @@ func (field *AdvancedInputField) InputHandler() func(event *tcell.EventKey, setF } case tcell.KeyTab: // Tab-completion if field.tabComplete != nil { - field.tabComplete(field.text, field.cursorOffset) + oldWidth := runewidth.StringWidth(field.text) + field.text = field.tabComplete(field.text, field.cursorOffset) + newWidth := runewidth.StringWidth(field.text) + if oldWidth != newWidth { + field.cursorOffset += newWidth - oldWidth + } } case tcell.KeyEnter, tcell.KeyEscape: // We're done. if field.done != nil { diff --git a/view-main.go b/view-main.go index 5a3a70c..219e603 100644 --- a/view-main.go +++ b/view-main.go @@ -17,10 +17,13 @@ package main import ( + "fmt" "strings" "time" + "unicode" "github.com/gdamore/tcell" + "github.com/mattn/go-runewidth" "maunium.net/go/gomatrix" "maunium.net/go/tview" ) @@ -96,11 +99,43 @@ func (view *MainView) InputChanged(text string) { } } -func (view *MainView) InputTabComplete(text string, cursorOffset int) { +func findWordToTabComplete(text string) string { + output := "" + runes := []rune(text) + for i := len(runes) - 1; i >= 0; i-- { + if unicode.IsSpace(runes[i]) { + break + } + output = string(runes[i]) + output + } + return output +} + +func (view *RoomView) AutocompleteUser(existingText string) (completions []string) { + for _, user := range view.room.GetMembers() { + if strings.HasPrefix(user.DisplayName, existingText) { + completions = append(completions, user.DisplayName) + } else if strings.HasPrefix(user.UserID, existingText) { + completions = append(completions, user.UserID) + } + } + return +} + +func (view *MainView) InputTabComplete(text string, cursorOffset int) string { roomView, _ := view.rooms[view.CurrentRoomID()] if roomView != nil { - // text[0:cursorOffset] + str := runewidth.Truncate(text, cursorOffset, "") + word := findWordToTabComplete(str) + userCompletions := roomView.AutocompleteUser(word) + if len(userCompletions) == 1 { + text = str[0:len(str)-len(word)] + userCompletions[0] + text[len(str):] + } else if len(userCompletions) > 1 && len(userCompletions) < 6 { + roomView.status.Clear() + fmt.Fprintf(roomView.status, "Completions: %s", strings.Join(userCompletions, ", ")) + } } + return text } func (view *MainView) InputDone(key tcell.Key) {