Add room alias autocompletion
This commit is contained in:
parent
9c4788f6e2
commit
bfb5f0dd45
@ -23,6 +23,15 @@ import (
|
|||||||
"maunium.net/go/gomatrix"
|
"maunium.net/go/gomatrix"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type RoomNameSource int
|
||||||
|
|
||||||
|
const (
|
||||||
|
ExplicitRoomName RoomNameSource = iota
|
||||||
|
CanonicalAliasRoomName
|
||||||
|
AliasRoomName
|
||||||
|
MemberRoomName
|
||||||
|
)
|
||||||
|
|
||||||
// Room represents a single Matrix room.
|
// Room represents a single Matrix room.
|
||||||
type Room struct {
|
type Room struct {
|
||||||
*gomatrix.Room
|
*gomatrix.Room
|
||||||
@ -50,8 +59,14 @@ type Room struct {
|
|||||||
// The name of the room. Calculated from the state event name,
|
// The name of the room. Calculated from the state event name,
|
||||||
// canonical_alias or alias or the member cache.
|
// canonical_alias or alias or the member cache.
|
||||||
nameCache string
|
nameCache string
|
||||||
|
// The event type from which the name cache was calculated from.
|
||||||
|
nameCacheSource RoomNameSource
|
||||||
// The topic of the room. Directly fetched from the m.room.topic state event.
|
// The topic of the room. Directly fetched from the m.room.topic state event.
|
||||||
topicCache string
|
topicCache string
|
||||||
|
// The canonical alias of the room. Directly fetched from the m.room.canonical_alias state event.
|
||||||
|
canonicalAliasCache string
|
||||||
|
// The list of aliases. Directly fetched from the m.room.aliases state event.
|
||||||
|
aliasesCache []string
|
||||||
|
|
||||||
// fetchHistoryLock is used to make sure multiple goroutines don't fetch
|
// fetchHistoryLock is used to make sure multiple goroutines don't fetch
|
||||||
// history for this room at the same time.
|
// history for this room at the same time.
|
||||||
@ -90,12 +105,24 @@ func (room *Room) UpdateState(event *gomatrix.Event) {
|
|||||||
room.State[event.Type] = make(map[string]*gomatrix.Event)
|
room.State[event.Type] = make(map[string]*gomatrix.Event)
|
||||||
}
|
}
|
||||||
switch event.Type {
|
switch event.Type {
|
||||||
|
case "m.room.name":
|
||||||
|
room.nameCache = ""
|
||||||
|
case "m.room.canonical_alias":
|
||||||
|
if room.nameCacheSource >= CanonicalAliasRoomName {
|
||||||
|
room.nameCache = ""
|
||||||
|
}
|
||||||
|
room.canonicalAliasCache = ""
|
||||||
|
case "m.room.aliases":
|
||||||
|
if room.nameCacheSource >= AliasRoomName {
|
||||||
|
room.nameCache = ""
|
||||||
|
}
|
||||||
|
room.aliasesCache = nil
|
||||||
case "m.room.member":
|
case "m.room.member":
|
||||||
room.memberCache = nil
|
room.memberCache = nil
|
||||||
room.firstMemberCache = ""
|
room.firstMemberCache = ""
|
||||||
fallthrough
|
if room.nameCacheSource >= MemberRoomName {
|
||||||
case "m.room.name", "m.room.canonical_alias", "m.room.alias":
|
room.nameCache = ""
|
||||||
room.nameCache = ""
|
}
|
||||||
case "m.room.topic":
|
case "m.room.topic":
|
||||||
room.topicCache = ""
|
room.topicCache = ""
|
||||||
}
|
}
|
||||||
@ -126,6 +153,40 @@ func (room *Room) GetTopic() string {
|
|||||||
return room.topicCache
|
return room.topicCache
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (room *Room) GetCanonicalAlias() string {
|
||||||
|
if len(room.canonicalAliasCache) == 0 {
|
||||||
|
canonicalAliasEvt := room.GetStateEvent("m.room.canonical_alias", "")
|
||||||
|
if canonicalAliasEvt != nil {
|
||||||
|
room.canonicalAliasCache, _ = canonicalAliasEvt.Content["alias"].(string)
|
||||||
|
} else {
|
||||||
|
room.canonicalAliasCache = "-"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if room.canonicalAliasCache == "-" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return room.canonicalAliasCache
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAliases returns the list of aliases that point to this room.
|
||||||
|
func (room *Room) GetAliases() []string {
|
||||||
|
if room.aliasesCache == nil {
|
||||||
|
aliasEvents := room.GetStateEvents("m.room.aliases")
|
||||||
|
room.aliasesCache = []string{}
|
||||||
|
for _, event := range aliasEvents {
|
||||||
|
aliases, _ := event.Content["aliases"].([]interface{})
|
||||||
|
|
||||||
|
newAliases := make([]string, len(room.aliasesCache)+len(aliases))
|
||||||
|
copy(newAliases, room.aliasesCache)
|
||||||
|
for index, alias := range aliases {
|
||||||
|
newAliases[len(room.aliasesCache) + index], _ = alias.(string)
|
||||||
|
}
|
||||||
|
room.aliasesCache = newAliases
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return room.aliasesCache
|
||||||
|
}
|
||||||
|
|
||||||
// updateNameFromNameEvent updates the room display name to be the name set in the name event.
|
// updateNameFromNameEvent updates the room display name to be the name set in the name event.
|
||||||
func (room *Room) updateNameFromNameEvent() {
|
func (room *Room) updateNameFromNameEvent() {
|
||||||
nameEvt := room.GetStateEvent("m.room.name", "")
|
nameEvt := room.GetStateEvent("m.room.name", "")
|
||||||
@ -134,17 +195,9 @@ func (room *Room) updateNameFromNameEvent() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateNameFromCanonicalAlias updates the room display name to be the canonical alias of the room.
|
|
||||||
func (room *Room) updateNameFromCanonicalAlias() {
|
|
||||||
canonicalAliasEvt := room.GetStateEvent("m.room.canonical_alias", "")
|
|
||||||
if canonicalAliasEvt != nil {
|
|
||||||
room.nameCache, _ = canonicalAliasEvt.Content["alias"].(string)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// updateNameFromAliases updates the room display name to be the first room alias it finds.
|
// updateNameFromAliases updates the room display name to be the first room alias it finds.
|
||||||
//
|
//
|
||||||
// Deprecated: the Client-Server API recommends against using aliases as display name.
|
// Deprecated: the Client-Server API recommends against using non-canonical aliases as display name.
|
||||||
func (room *Room) updateNameFromAliases() {
|
func (room *Room) updateNameFromAliases() {
|
||||||
// TODO the spec says clients should not use m.room.aliases for room names.
|
// TODO the spec says clients should not use m.room.aliases for room names.
|
||||||
// However, Riot also uses m.room.aliases, so this is here now.
|
// However, Riot also uses m.room.aliases, so this is here now.
|
||||||
@ -183,15 +236,19 @@ func (room *Room) updateNameFromMembers() {
|
|||||||
func (room *Room) updateNameCache() {
|
func (room *Room) updateNameCache() {
|
||||||
if len(room.nameCache) == 0 {
|
if len(room.nameCache) == 0 {
|
||||||
room.updateNameFromNameEvent()
|
room.updateNameFromNameEvent()
|
||||||
|
room.nameCacheSource = ExplicitRoomName
|
||||||
}
|
}
|
||||||
if len(room.nameCache) == 0 {
|
if len(room.nameCache) == 0 {
|
||||||
room.updateNameFromCanonicalAlias()
|
room.nameCache = room.GetCanonicalAlias()
|
||||||
|
room.nameCacheSource = CanonicalAliasRoomName
|
||||||
}
|
}
|
||||||
if len(room.nameCache) == 0 {
|
if len(room.nameCache) == 0 {
|
||||||
room.updateNameFromAliases()
|
room.updateNameFromAliases()
|
||||||
|
room.nameCacheSource = AliasRoomName
|
||||||
}
|
}
|
||||||
if len(room.nameCache) == 0 {
|
if len(room.nameCache) == 0 {
|
||||||
room.updateNameFromMembers()
|
room.updateNameFromMembers()
|
||||||
|
room.nameCacheSource = MemberRoomName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,10 @@ type RoomView struct {
|
|||||||
input *widget.AdvancedInputField
|
input *widget.AdvancedInputField
|
||||||
Room *rooms.Room
|
Room *rooms.Room
|
||||||
|
|
||||||
|
parent *MainView
|
||||||
|
|
||||||
typing []string
|
typing []string
|
||||||
|
|
||||||
completions struct {
|
completions struct {
|
||||||
list []string
|
list []string
|
||||||
textCache string
|
textCache string
|
||||||
@ -53,7 +56,7 @@ type RoomView struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRoomView(room *rooms.Room) *RoomView {
|
func NewRoomView(parent *MainView, room *rooms.Room) *RoomView {
|
||||||
view := &RoomView{
|
view := &RoomView{
|
||||||
Box: tview.NewBox(),
|
Box: tview.NewBox(),
|
||||||
topic: tview.NewTextView(),
|
topic: tview.NewTextView(),
|
||||||
@ -62,6 +65,7 @@ func NewRoomView(room *rooms.Room) *RoomView {
|
|||||||
ulBorder: widget.NewBorder(),
|
ulBorder: widget.NewBorder(),
|
||||||
input: widget.NewAdvancedInputField(),
|
input: widget.NewAdvancedInputField(),
|
||||||
Room: room,
|
Room: room,
|
||||||
|
parent: parent,
|
||||||
}
|
}
|
||||||
view.content = NewMessageView(view)
|
view.content = NewMessageView(view)
|
||||||
|
|
||||||
@ -257,9 +261,18 @@ func (view *RoomView) autocompleteUser(existingText string) (completions []compl
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (view *RoomView) autocompleteRoom(existingText string) (completions []completion) {
|
func (view *RoomView) autocompleteRoom(existingText string) (completions []completion) {
|
||||||
// TODO - This was harder than I expected.
|
for _, room := range view.parent.rooms {
|
||||||
|
alias := room.Room.GetCanonicalAlias()
|
||||||
return []completion{}
|
if alias == existingText {
|
||||||
|
// Exact match, return that.
|
||||||
|
return []completion{{alias, room.Room.ID}}
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(alias, existingText) {
|
||||||
|
completions = append(completions, completion{alias, room.Room.ID})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *RoomView) InputTabComplete(text string, cursorOffset int) {
|
func (view *RoomView) InputTabComplete(text string, cursorOffset int) {
|
||||||
|
@ -299,7 +299,7 @@ func (view *MainView) addRoom(index int, room string) {
|
|||||||
|
|
||||||
view.roomList.Add(roomStore)
|
view.roomList.Add(roomStore)
|
||||||
if !view.roomView.HasPage(room) {
|
if !view.roomView.HasPage(room) {
|
||||||
roomView := NewRoomView(roomStore).
|
roomView := NewRoomView(view, roomStore).
|
||||||
SetInputSubmitFunc(view.InputSubmit).
|
SetInputSubmitFunc(view.InputSubmit).
|
||||||
SetInputChangedFunc(view.InputChanged).
|
SetInputChangedFunc(view.InputChanged).
|
||||||
SetInputCapture(view.KeyEventHandler).
|
SetInputCapture(view.KeyEventHandler).
|
||||||
|
Loading…
Reference in New Issue
Block a user