aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTulir Asokan <tulir@maunium.net>2018-04-18 13:38:33 +0300
committerTulir Asokan <tulir@maunium.net>2018-04-18 13:38:33 +0300
commit3750d5007fe31b1a4d706357f43774d08944213e (patch)
treee3a41935dca8c2f7c3d8967d9f58979ecf29ea2b
parent127c89629149e223b5a0c625c935941d513f857e (diff)
Create pills when tab-completing or clicking nicks
-rw-r--r--ui/message-view.go28
-rw-r--r--ui/messages/base.go11
-rw-r--r--ui/messages/expandedtextmessage.go4
-rw-r--r--ui/messages/imagemessage.go4
-rw-r--r--ui/messages/message.go1
-rw-r--r--ui/messages/parser/parser.go29
-rw-r--r--ui/messages/textbase.go4
-rw-r--r--ui/messages/textmessage.go4
-rw-r--r--ui/room-view.go17
-rw-r--r--ui/view-main.go11
10 files changed, 70 insertions, 43 deletions
diff --git a/ui/message-view.go b/ui/message-view.go
index 83729ca..b78f135 100644
--- a/ui/message-view.go
+++ b/ui/message-view.go
@@ -21,7 +21,9 @@ import (
"fmt"
"math"
"os"
+ "strings"
+ "github.com/mattn/go-runewidth"
"maunium.net/go/gomuks/debug"
"maunium.net/go/gomuks/interface"
"maunium.net/go/gomuks/lib/open"
@@ -278,22 +280,28 @@ func (view *MessageView) handleUsernameClick(message ifc.MessageMeta, prevMessag
return false
}
- sender := []rune(uiMessage.Sender())
- if len(sender) == 0 {
+ if len(uiMessage.Sender()) == 0 {
return false
}
+ sender := fmt.Sprintf("[%s](https://matrix.to/#/%s)", uiMessage.Sender(), uiMessage.SenderID())
cursorPos := view.parent.input.GetCursorOffset()
- text := []rune(view.parent.input.GetText())
- var newText []rune
+ text := view.parent.input.GetText()
+ var buf strings.Builder
if cursorPos == 0 {
- newText = append(sender, ':', ' ')
- newText = append(newText, text...)
+ buf.WriteString(sender)
+ buf.WriteRune(':')
+ buf.WriteRune(' ')
+ buf.WriteString(text)
} else {
- newText = append(text[0:cursorPos], sender...)
- newText = append(newText, ' ')
- newText = append(newText, text[cursorPos:]...)
- }
+ textBefore := runewidth.Truncate(text, cursorPos, "")
+ textAfter := text[len(textBefore):]
+ buf.WriteString(textBefore)
+ buf.WriteString(sender)
+ buf.WriteRune(' ')
+ buf.WriteString(textAfter)
+ }
+ newText := buf.String()
view.parent.input.SetText(string(newText))
view.parent.input.SetCursorOffset(cursorPos + len(newText) - len(text))
return true
diff --git a/ui/messages/base.go b/ui/messages/base.go
index aed7903..50f2735 100644
--- a/ui/messages/base.go
+++ b/ui/messages/base.go
@@ -33,6 +33,7 @@ func init() {
type BaseMessage struct {
MsgID string
MsgType string
+ MsgSenderID string
MsgSender string
MsgSenderColor tcell.Color
MsgTimestamp time.Time
@@ -43,9 +44,10 @@ type BaseMessage struct {
prevBufferWidth int
}
-func newBaseMessage(id, sender, msgtype string, timestamp time.Time) BaseMessage {
+func newBaseMessage(id, sender, displayname, msgtype string, timestamp time.Time) BaseMessage {
return BaseMessage{
- MsgSender: sender,
+ MsgSenderID: sender,
+ MsgSender: displayname,
MsgTimestamp: timestamp,
MsgSenderColor: widget.GetHashColor(sender),
MsgType: msgtype,
@@ -66,6 +68,7 @@ func (msg *BaseMessage) CopyFrom(from ifc.MessageMeta) {
fromMsg, ok := from.(UIMessage)
if ok {
+ msg.MsgSenderID = fromMsg.SenderID()
msg.MsgSender = fromMsg.RealSender()
msg.MsgID = fromMsg.ID()
msg.MsgType = fromMsg.Type()
@@ -99,6 +102,10 @@ func (msg *BaseMessage) Sender() string {
}
}
+func (msg *BaseMessage) SenderID() string {
+ return msg.MsgSenderID
+}
+
func (msg *BaseMessage) RealSender() string {
return msg.MsgSender
}
diff --git a/ui/messages/expandedtextmessage.go b/ui/messages/expandedtextmessage.go
index 3ee15ad..ec359c9 100644
--- a/ui/messages/expandedtextmessage.go
+++ b/ui/messages/expandedtextmessage.go
@@ -34,9 +34,9 @@ type ExpandedTextMessage struct {
}
// NewExpandedTextMessage creates a new ExpandedTextMessage object with the provided values and the default state.
-func NewExpandedTextMessage(id, sender, msgtype string, text tstring.TString, timestamp time.Time) UIMessage {
+func NewExpandedTextMessage(id, sender, displayname, msgtype string, text tstring.TString, timestamp time.Time) UIMessage {
return &ExpandedTextMessage{
- BaseTextMessage: newBaseTextMessage(id, sender, msgtype, timestamp),
+ BaseTextMessage: newBaseTextMessage(id, sender, displayname, msgtype, timestamp),
MsgText: text,
}
}
diff --git a/ui/messages/imagemessage.go b/ui/messages/imagemessage.go
index 2fbf6ae..7478876 100644
--- a/ui/messages/imagemessage.go
+++ b/ui/messages/imagemessage.go
@@ -45,9 +45,9 @@ type ImageMessage struct {
}
// NewImageMessage creates a new ImageMessage object with the provided values and the default state.
-func NewImageMessage(gmx ifc.Gomuks, id, sender, msgtype, homeserver, fileID string, data []byte, timestamp time.Time) UIMessage {
+func NewImageMessage(gmx ifc.Gomuks, id, sender, displayname, msgtype, homeserver, fileID string, data []byte, timestamp time.Time) UIMessage {
return &ImageMessage{
- newBaseMessage(id, sender, msgtype, timestamp),
+ newBaseMessage(id, sender, displayname, msgtype, timestamp),
homeserver,
fileID,
data,
diff --git a/ui/messages/message.go b/ui/messages/message.go
index 6ebfb6d..0d5c9e4 100644
--- a/ui/messages/message.go
+++ b/ui/messages/message.go
@@ -30,6 +30,7 @@ type UIMessage interface {
Buffer() []tstring.TString
Height() int
+ SenderID() string
RealSender() string
RegisterGomuks(gmx ifc.Gomuks)
}
diff --git a/ui/messages/parser/parser.go b/ui/messages/parser/parser.go
index 939dd10..58b0248 100644
--- a/ui/messages/parser/parser.go
+++ b/ui/messages/parser/parser.go
@@ -31,15 +31,11 @@ import (
)
func ParseEvent(gmx ifc.Gomuks, room *rooms.Room, evt *gomatrix.Event) messages.UIMessage {
- member := room.GetMember(evt.Sender)
- if member != nil {
- evt.Sender = member.DisplayName
- }
switch evt.Type {
case "m.room.message":
return ParseMessage(gmx, room, evt)
case "m.room.member":
- return ParseMembershipEvent(evt)
+ return ParseMembershipEvent(room, evt)
}
return nil
}
@@ -53,6 +49,11 @@ func unixToTime(unix int64) time.Time {
}
func ParseMessage(gmx ifc.Gomuks, room *rooms.Room, evt *gomatrix.Event) messages.UIMessage {
+ displayname := evt.Sender
+ member := room.GetMember(evt.Sender)
+ if member != nil {
+ displayname = member.DisplayName
+ }
msgtype, _ := evt.Content["msgtype"].(string)
ts := unixToTime(evt.Timestamp)
switch msgtype {
@@ -60,10 +61,10 @@ func ParseMessage(gmx ifc.Gomuks, room *rooms.Room, evt *gomatrix.Event) message
format, hasFormat := evt.Content["format"].(string)
if hasFormat && format == "org.matrix.custom.html" {
text := ParseHTMLMessage(room, evt)
- return messages.NewExpandedTextMessage(evt.ID, evt.Sender, msgtype, text, ts)
+ return messages.NewExpandedTextMessage(evt.ID, evt.Sender, displayname, msgtype, text, ts)
} else {
text, _ := evt.Content["body"].(string)
- return messages.NewTextMessage(evt.ID, evt.Sender, msgtype, text, ts)
+ return messages.NewTextMessage(evt.ID, evt.Sender, displayname, msgtype, text, ts)
}
case "m.image":
url, _ := evt.Content["url"].(string)
@@ -71,12 +72,16 @@ func ParseMessage(gmx ifc.Gomuks, room *rooms.Room, evt *gomatrix.Event) message
if err != nil {
debug.Printf("Failed to download %s: %v", url, err)
}
- return messages.NewImageMessage(gmx, evt.ID, evt.Sender, msgtype, hs, id, data, ts)
+ return messages.NewImageMessage(gmx, evt.ID, evt.Sender, displayname, msgtype, hs, id, data, ts)
}
return nil
}
-func getMembershipEventContent(evt *gomatrix.Event) (sender string, text tstring.TString) {
+func getMembershipEventContent(room *rooms.Room, evt *gomatrix.Event) (sender string, text tstring.TString) {
+ member := room.GetMember(evt.Sender)
+ if member != nil {
+ evt.Sender = member.DisplayName
+ }
membership, _ := evt.Content["membership"].(string)
displayname, _ := evt.Content["displayname"].(string)
if len(displayname) == 0 {
@@ -121,8 +126,8 @@ func getMembershipEventContent(evt *gomatrix.Event) (sender string, text tstring
return
}
-func ParseMembershipEvent(evt *gomatrix.Event) messages.UIMessage {
- sender, text := getMembershipEventContent(evt)
+func ParseMembershipEvent(room *rooms.Room, evt *gomatrix.Event) messages.UIMessage {
+ displayname, text := getMembershipEventContent(room, evt)
ts := unixToTime(evt.Timestamp)
- return messages.NewExpandedTextMessage(evt.ID, sender, "m.room.membership", text, ts)
+ return messages.NewExpandedTextMessage(evt.ID, evt.Sender, displayname, "m.room.membership", text, ts)
}
diff --git a/ui/messages/textbase.go b/ui/messages/textbase.go
index d7eb16c..0960a57 100644
--- a/ui/messages/textbase.go
+++ b/ui/messages/textbase.go
@@ -32,8 +32,8 @@ type BaseTextMessage struct {
BaseMessage
}
-func newBaseTextMessage(id, sender, msgtype string, timestamp time.Time) BaseTextMessage {
- return BaseTextMessage{newBaseMessage(id, sender, msgtype, timestamp)}
+func newBaseTextMessage(id, sender, displayname, msgtype string, timestamp time.Time) BaseTextMessage {
+ return BaseTextMessage{newBaseMessage(id, sender, displayname, msgtype, timestamp)}
}
// Regular expressions used to split lines when calculating the buffer.
diff --git a/ui/messages/textmessage.go b/ui/messages/textmessage.go
index 4c99e5b..489e8a7 100644
--- a/ui/messages/textmessage.go
+++ b/ui/messages/textmessage.go
@@ -36,9 +36,9 @@ type TextMessage struct {
}
// NewTextMessage creates a new UITextMessage object with the provided values and the default state.
-func NewTextMessage(id, sender, msgtype, text string, timestamp time.Time) UIMessage {
+func NewTextMessage(id, sender, displayname, msgtype, text string, timestamp time.Time) UIMessage {
return &TextMessage{
- BaseTextMessage: newBaseTextMessage(id, sender, msgtype, timestamp),
+ BaseTextMessage: newBaseTextMessage(id, sender, displayname, msgtype, timestamp),
MsgText: text,
}
}
diff --git a/ui/room-view.go b/ui/room-view.go
index d7824fe..d38db94 100644
--- a/ui/room-view.go
+++ b/ui/room-view.go
@@ -23,11 +23,11 @@ import (
"strings"
"time"
- "maunium.net/go/tcell"
"maunium.net/go/gomuks/interface"
"maunium.net/go/gomuks/matrix/rooms"
"maunium.net/go/gomuks/ui/messages"
"maunium.net/go/gomuks/ui/widget"
+ "maunium.net/go/tcell"
"maunium.net/go/tview"
)
@@ -213,16 +213,15 @@ func (view *RoomView) SetTyping(users []string) {
}
}
-func (view *RoomView) AutocompleteUser(existingText string) (completions []string) {
+func (view *RoomView) AutocompleteUser(existingText string) (completions []*rooms.Member) {
textWithoutPrefix := existingText
if strings.HasPrefix(existingText, "@") {
textWithoutPrefix = existingText[1:]
}
for _, user := range view.Room.GetMembers() {
- if strings.HasPrefix(user.DisplayName, textWithoutPrefix) {
- completions = append(completions, user.DisplayName)
- } else if strings.HasPrefix(user.UserID, existingText) {
- completions = append(completions, user.UserID)
+ if strings.HasPrefix(user.DisplayName, textWithoutPrefix) ||
+ strings.HasPrefix(user.UserID, existingText) {
+ completions = append(completions, user)
}
}
return
@@ -257,10 +256,12 @@ func (view *RoomView) UpdateUserList() {
func (view *RoomView) newUIMessage(id, sender, msgtype, text string, timestamp time.Time) messages.UIMessage {
member := view.Room.GetMember(sender)
+ displayname := sender
if member != nil {
- sender = member.DisplayName
+ displayname = member.DisplayName
}
- return messages.NewTextMessage(id, sender, msgtype, text, timestamp)
+ msg := messages.NewTextMessage(id, sender, displayname, msgtype, text, timestamp)
+ return msg
}
func (view *RoomView) NewMessage(id, sender, msgtype, text string, timestamp time.Time) ifc.Message {
diff --git a/ui/view-main.go b/ui/view-main.go
index d4ffd39..018fb1a 100644
--- a/ui/view-main.go
+++ b/ui/view-main.go
@@ -104,17 +104,22 @@ func findWordToTabComplete(text string) string {
func (view *MainView) InputTabComplete(roomView *RoomView, text string, cursorOffset int) string {
str := runewidth.Truncate(text, cursorOffset, "")
word := findWordToTabComplete(str)
+
userCompletions := roomView.AutocompleteUser(word)
if len(userCompletions) == 1 {
startIndex := len(str) - len(word)
- completion := userCompletions[0]
+ member := userCompletions[0]
+ completion := fmt.Sprintf("[%s](https://matrix.to/#/%s)", member.DisplayName, member.UserID)
if startIndex == 0 {
completion = completion + ": "
}
text = str[0:startIndex] + completion + text[len(str):]
- } else if len(userCompletions) > 1 && len(userCompletions) < 6 {
- roomView.SetStatus(fmt.Sprintf("Completions: %s", strings.Join(userCompletions, ", ")))
+ } else if len(userCompletions) > 1 && len(userCompletions) <= 5 {
+ // roomView.SetStatus(fmt.Sprintf("Completions: %s", strings.Join(userCompletions, ", ")))
+ } else if len(userCompletions) > 5 {
+ roomView.SetStatus("Over 5 completion options.")
}
+
return text
}