From 38d5ef5603bba2241ec5ccf1c86f98ec24e023d6 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 17 Jun 2020 14:15:22 +0300 Subject: Add alias management command and alt_aliases rendering * /alias command can be used to create and remove local aliases * Changes to the alt_aliases are now rendered properly --- ui/command-processor.go | 18 ++++-- ui/commands.go | 85 +++++++++++++++++++++++++++- ui/messages/parser.go | 146 +++++++++++++++++++++++------------------------- 3 files changed, 168 insertions(+), 81 deletions(-) diff --git a/ui/command-processor.go b/ui/command-processor.go index 94b07b8..b8f41a2 100644 --- a/ui/command-processor.go +++ b/ui/command-processor.go @@ -41,11 +41,13 @@ type Command struct { Command string OrigCommand string Args []string + RawArgs string OrigText string } func (cmd *Command) Reply(message string, args ...interface{}) { cmd.Room.AddServiceMessage(fmt.Sprintf(message, args...)) + cmd.UI.Render() } type Alias struct { @@ -128,6 +130,7 @@ func NewCommandProcessor(parent *MainView) *CommandProcessor { "rainbow": cmdRainbow, "rainbowme": cmdRainbowMe, "notice": cmdNotice, + "alias": cmdAlias, "tags": cmdTags, "tag": cmdTag, "untag": cmdUntag, @@ -146,15 +149,22 @@ func (ch *CommandProcessor) ParseCommand(roomView *RoomView, text string) *Comma return nil } text = text[1:] - split := strings.SplitN(text, " ", -1) + split := strings.Fields(text) + command := split[0] + args := split[1:] + var rawArgs string + if len(text) > len(command)+1 { + rawArgs = text[len(command)+1:] + } return &Command{ gomuksPointerContainer: ch.gomuksPointerContainer, Handler: ch, Room: roomView, - Command: strings.ToLower(split[0]), - OrigCommand: split[0], - Args: split[1:], + Command: strings.ToLower(command), + OrigCommand: command, + Args: args, + RawArgs: rawArgs, OrigText: text, } } diff --git a/ui/commands.go b/ui/commands.go index 71cee21..49bff0f 100644 --- a/ui/commands.go +++ b/ui/commands.go @@ -33,6 +33,7 @@ import ( "unicode" "github.com/lucasb-eyer/go-colorful" + "github.com/pkg/errors" "github.com/russross/blackfriday/v2" "maunium.net/go/mautrix" @@ -124,7 +125,7 @@ func cmdAccept(cmd *Command) { _, server, _ := room.SessionMember.Sender.Parse() _, err := cmd.Matrix.JoinRoom(room.ID, server) if err != nil { - cmd.Reply("Failed to accept invite:", err) + cmd.Reply("Failed to accept invite: %v", err) } else { cmd.Reply("Successfully accepted invite") } @@ -183,7 +184,7 @@ func cmdCopy(cmd *Command) { if len(register) == 0 { register = "clipboard" } - if (register == "clipboard" || register == "primary") { + if register == "clipboard" || register == "primary" { cmd.Room.StartSelecting(SelectCopy, register) } else { cmd.Reply("Usage: /copy [register], where register is either \"clipboard\" or \"primary\". Defaults to \"clipboard\".") @@ -199,6 +200,85 @@ func cmdReact(cmd *Command) { cmd.Room.StartSelecting(SelectReact, strings.Join(cmd.Args, " ")) } +func readRoomAlias(cmd *Command) (alias id.RoomAlias, err error) { + param := strings.Join(cmd.Args[1:], " ") + if strings.ContainsRune(param, ':') { + if param[0] != '#' { + return "", errors.New("Full aliases must start with #") + } + + alias = id.RoomAlias(param) + } else { + _, homeserver, _ := cmd.Matrix.Client().UserID.Parse() + alias = id.NewRoomAlias(param, homeserver) + } + return +} + +func cmdAlias(cmd *Command) { + if len(cmd.Args) < 2 { + cmd.Reply("Usage: /alias ") + return + } + + alias, err := readRoomAlias(cmd) + if err != nil { + cmd.Reply(err.Error()) + return + } + + subcmd := strings.ToLower(cmd.Args[0]) + switch subcmd { + case "add", "create": + cmdAddAlias(cmd, alias) + case "remove", "delete", "del", "rm": + cmdRemoveAlias(cmd, alias) + case "resolve", "get": + cmdResolveAlias(cmd, alias) + default: + cmd.Reply("Usage: /alias ") + } +} + +func niceError(err error) string { + httpErr, ok := err.(mautrix.HTTPError) + if ok && httpErr.RespError != nil { + return httpErr.RespError.Error() + } + return err.Error() +} + +func cmdAddAlias(cmd *Command, alias id.RoomAlias) { + _, err := cmd.Matrix.Client().CreateAlias(alias, cmd.Room.MxRoom().ID) + if err != nil { + cmd.Reply("Failed to create alias: %v", niceError(err)) + } else { + cmd.Reply("Created alias %s", alias) + } +} + +func cmdRemoveAlias(cmd *Command, alias id.RoomAlias) { + _, err := cmd.Matrix.Client().DeleteAlias(alias) + if err != nil { + cmd.Reply("Failed to delete alias: %v", niceError(err)) + } else { + cmd.Reply("Deleted alias %s", alias) + } +} + +func cmdResolveAlias(cmd *Command, alias id.RoomAlias) { + resp, err := cmd.Matrix.Client().ResolveAlias(alias) + if err != nil { + cmd.Reply("Failed to resolve alias: %v", niceError(err)) + } else { + roomIDText := string(resp.RoomID) + if resp.RoomID == cmd.Room.MxRoom().ID { + roomIDText += " (this room)" + } + cmd.Reply("Alias %s points to room %s\nThere are %d servers in the room.", alias, roomIDText, len(resp.Servers)) + } +} + func cmdTags(cmd *Command) { tags := cmd.Room.MxRoom().RawTags if len(cmd.Args) > 0 && cmd.Args[0] == "--internal" { @@ -384,6 +464,7 @@ Things: rooms, users, baremessages, images, typingnotif /tag - Add the room to . /untag - Remove the room from . /tags - List the tags the room is in. +/alias - Add or remove local addresses. /leave - Leave the current room. /kick [reason] - Kick a user. diff --git a/ui/messages/parser.go b/ui/messages/parser.go index 4a214f1..0f92f11 100644 --- a/ui/messages/parser.go +++ b/ui/messages/parser.go @@ -93,35 +93,94 @@ func directParseEvent(matrix ifc.MatrixContainer, room *rooms.Room, evt *muksevt } } +func findAltAliasDifference(newList, oldList []string) (addedStr, removedStr tstring.TString) { + var addedList, removedList []tstring.TString +OldLoop: + for _, oldAlias := range oldList { + for _, newAlias := range newList { + if oldAlias == newAlias { + continue OldLoop + } + } + removedList = append(removedList, tstring.NewStyleTString(oldAlias, tcell.StyleDefault.Foreground(widget.GetHashColor(oldAlias)).Underline(true))) + } +NewLoop: + for _, newAlias := range newList { + for _, oldAlias := range oldList { + if newAlias == oldAlias { + continue NewLoop + } + } + addedList = append(addedList, tstring.NewStyleTString(newAlias, tcell.StyleDefault.Foreground(widget.GetHashColor(newAlias)).Underline(true))) + } + if len(addedList) == 1 { + addedStr = tstring.NewColorTString("added alternative address ", tcell.ColorGreen).AppendTString(addedList[0]) + } else if len(addedList) != 0 { + addedStr = tstring. + Join(addedList[:len(addedList)-1], ", "). + PrependColor("added alternative addresses ", tcell.ColorGreen). + AppendColor(" and ", tcell.ColorGreen). + AppendTString(addedList[len(addedList)-1]) + } + if len(removedList) == 1 { + removedStr = tstring.NewColorTString("removed alternative address ", tcell.ColorGreen).AppendTString(removedList[0]) + } else if len(removedList) != 0 { + removedStr = tstring. + Join(removedList[:len(removedList)-1], ", "). + PrependColor("removed alternative addresses ", tcell.ColorGreen). + AppendColor(" and ", tcell.ColorGreen). + AppendTString(removedList[len(removedList)-1]) + } + return +} + func ParseStateEvent(evt *muksevt.Event, displayname string) *UIMessage { - text := tstring.NewColorTString(displayname, widget.GetHashColor(evt.Sender)) + text := tstring.NewColorTString(displayname, widget.GetHashColor(evt.Sender)).Append(" ") switch content := evt.Content.Parsed.(type) { case *event.TopicEventContent: if len(content.Topic) == 0 { - text = text.AppendColor(" removed the topic.", tcell.ColorGreen) + text = text.AppendColor("removed the topic.", tcell.ColorGreen) } else { - text = text.AppendColor(" changed the topic to ", tcell.ColorGreen). + text = text.AppendColor("changed the topic to ", tcell.ColorGreen). AppendStyle(content.Topic, tcell.StyleDefault.Underline(true)). AppendColor(".", tcell.ColorGreen) } case *event.RoomNameEventContent: if len(content.Name) == 0 { - text = text.AppendColor(" removed the room name.", tcell.ColorGreen) + text = text.AppendColor("removed the room name.", tcell.ColorGreen) } else { - text = text.AppendColor(" changed the room name to ", tcell.ColorGreen). + text = text.AppendColor("changed the room name to ", tcell.ColorGreen). AppendStyle(content.Name, tcell.StyleDefault.Underline(true)). AppendColor(".", tcell.ColorGreen) } case *event.CanonicalAliasEventContent: - if len(content.Alias) == 0 { - text = text.AppendColor(" removed the main address of the room.", tcell.ColorGreen) + _ = evt.Unsigned.PrevContent.ParseRaw(evt.Type) + prevContent := evt.Unsigned.PrevContent.AsCanonicalAlias() + debug.Printf("%+v -> %+v", prevContent, content) + if len(content.Alias) == 0 && len(prevContent.Alias) != 0 { + text = text.AppendColor("removed the main address of the room", tcell.ColorGreen) + } else if content.Alias != prevContent.Alias { + text = text. + AppendColor("changed the main address of the room to ", tcell.ColorGreen). + AppendStyle(string(content.Alias), tcell.StyleDefault.Underline(true)) } else { - text = text.AppendColor(" changed the main address of the room to ", tcell.ColorGreen). - AppendStyle(string(content.Alias), tcell.StyleDefault.Underline(true)). - AppendColor(".", tcell.ColorGreen) + added, removed := findAltAliasDifference(content.AltAliases, prevContent.AltAliases) + if len(added) > 0 { + if len(removed) > 0 { + text = text. + AppendTString(added). + AppendColor(" and ", tcell.ColorGreen). + AppendTString(removed) + } else { + text = text.AppendTString(added) + } + } else if len(removed) > 0 { + text = text.AppendTString(removed) + } else { + text = text.AppendColor("changed nothing", tcell.ColorGreen) + } + text = text.AppendColor(" for this room", tcell.ColorGreen) } - //case event.StateAliases: - // text = ParseAliasEvent(evt, displayname) } return NewExpandedTextMessage(evt, displayname, text) } @@ -243,66 +302,3 @@ func ParseMembershipEvent(room *rooms.Room, evt *muksevt.Event) *UIMessage { return NewExpandedTextMessage(evt, displayname, text) } - -//func ParseAliasEvent(evt *muksevt.Event, displayname string) tstring.TString { -// var prevAliases []string -// if evt.Unsigned.PrevContent != nil { -// prevAliases = evt.Unsigned.PrevContent.Aliases -// } -// aliases := evt.Content.Aliases -// var added, removed []tstring.TString -//Outer1: -// for _, oldAlias := range prevAliases { -// for _, newAlias := range aliases { -// if oldAlias == newAlias { -// continue Outer1 -// } -// } -// removed = append(removed, tstring.NewStyleTString(oldAlias, tcell.StyleDefault.Foreground(widget.GetHashColor(oldAlias)).Underline(true))) -// } -//Outer2: -// for _, newAlias := range aliases { -// for _, oldAlias := range prevAliases { -// if oldAlias == newAlias { -// continue Outer2 -// } -// } -// added = append(added, tstring.NewStyleTString(newAlias, tcell.StyleDefault.Foreground(widget.GetHashColor(newAlias)).Underline(true))) -// } -// var addedStr, removedStr tstring.TString -// if len(added) == 1 { -// addedStr = added[0] -// } else if len(added) > 1 { -// addedStr = tstring. -// Join(added[:len(added)-1], ", "). -// Append(" and "). -// AppendTString(added[len(added)-1]) -// } -// if len(removed) == 1 { -// removedStr = removed[0] -// } else if len(removed) > 1 { -// removedStr = tstring. -// Join(removed[:len(removed)-1], ", "). -// Append(" and "). -// AppendTString(removed[len(removed)-1]) -// } -// text := tstring.NewBlankTString() -// if len(addedStr) > 0 && len(removedStr) > 0 { -// text = text.AppendColor(fmt.Sprintf("%s added ", displayname), tcell.ColorGreen). -// AppendTString(addedStr). -// AppendColor(" and removed ", tcell.ColorGreen). -// AppendTString(removedStr). -// AppendColor(" as addresses for this room.", tcell.ColorGreen) -// } else if len(addedStr) > 0 { -// text = text.AppendColor(fmt.Sprintf("%s added ", displayname), tcell.ColorGreen). -// AppendTString(addedStr). -// AppendColor(" as addresses for this room.", tcell.ColorGreen) -// } else if len(removedStr) > 0 { -// text = text.AppendColor(fmt.Sprintf("%s removed ", displayname), tcell.ColorGreen). -// AppendTString(removedStr). -// AppendColor(" as addresses for this room.", tcell.ColorGreen) -// } else { -// return nil -// } -// return text -//} -- cgit v1.2.3