From a73e52d3a33fa9e2097472f6d5cdc4950c5e07e4 Mon Sep 17 00:00:00 2001 From: Gregory Rudolph Date: Fri, 11 Oct 2019 11:48:08 -0400 Subject: [PATCH 1/5] ReplaceAll reduced to Replace to avoid requiring go1.12+ --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index f1247fd..d3f7064 100644 --- a/main.go +++ b/main.go @@ -404,7 +404,7 @@ func getInputString(viewName string) (string, error) { return "", err } retString := inputView.Buffer() - retString = strings.ReplaceAll(retString, "\n", "") + retString = strings.Replace(retString, "\n", "", 800) return retString, err } From 76511afc4f731dffe9f8f2d71a755ed20764e265 Mon Sep 17 00:00:00 2001 From: Casper Weiss Bang Date: Thu, 10 Oct 2019 22:35:05 +0200 Subject: [PATCH 2/5] Added colors & minor bugfix - Created new file colors.go - Added color options to the UserConfig - Possible to disable colors (in UserConfig) - Fixed a bug where the login screen says `/j` and not `{cmdChar}j` - Changed how attachments look - so it's clear it isn't just a message saying that - Changed how formatOutput works (to be more DRY) - Colored unread messages Changes to be committed: new file: colors.go modified: main.go modified: userConfigs.go --- colors.go | 42 ++++++++++++++++++++++++++++++++++ main.go | 61 +++++++++++++++++++++++++++----------------------- userConfigs.go | 15 ++++++++++++- 3 files changed, 89 insertions(+), 29 deletions(-) create mode 100644 colors.go diff --git a/colors.go b/colors.go new file mode 100644 index 0000000..3ddf629 --- /dev/null +++ b/colors.go @@ -0,0 +1,42 @@ +package main + +import ( + "fmt" + "regexp" +) + +// TODO maybe datastructure +// BASH-like PS1 variable equivalent (without colours) +// TODO bold? cursive etc? +func color(c int) string { + if colorless { + return "" + } + if c < 0 { + return "\033[0m" + } else { + return fmt.Sprintf("\033[0;%dm", 29+c) + } +} +// TODO maybe make the text into some datastructure which remembers the color +func colorText(text string, color string, offColor string) string { + return fmt.Sprintf("%s%s%s", color, text, offColor) +} + +func colorUsername(username string, offColor string) string { + var color = messageSenderDefaultColor + if username == k.Username { + color = mentionColor + } + return colorText(username, color, offColor) +} +func colorRegex(msg string, match string, color string, offColor string) string { + var re = regexp.MustCompile(match) + return re.ReplaceAllString(msg, colorText(`$1`, color, offColor)) +} + +func colorReplaceMentionMe(msg string, offColor string) string { + //var coloredOwnName = colorText(k.Username, mentionColor, offColor) + //return strings.Replace(msg, k.Username, coloredOwnName, -1) + return colorRegex(msg, "(@?"+k.Username+")", mentionColor, offColor) +} diff --git a/main.go b/main.go index f1247fd..c260fbe 100644 --- a/main.go +++ b/main.go @@ -141,28 +141,33 @@ func sendChat(message string) { } func formatOutput(api keybase.ChatAPI) string { ret := "" - if api.Msg.Content.Type == "text" { - ret = outputFormat + msgType := api.Msg.Content.Type + switch (msgType) { + case "text", "attachment": + var c = messageHeaderColor + ret = colorText(outputFormat, c, noColor) tm := time.Unix(int64(api.Msg.SentAt), 0) - ret = strings.Replace(ret, "$MSG", api.Msg.Content.Text.Body, 1) - ret = strings.Replace(ret, "$USER", api.Msg.Sender.Username, 1) - ret = strings.Replace(ret, "$DEVICE", api.Msg.Sender.DeviceName, 1) - ret = strings.Replace(ret, "$ID", fmt.Sprintf("%d", api.Msg.ID), 1) - ret = strings.Replace(ret, "$DATE", fmt.Sprintf("%s", tm.Format(dateFormat)), 1) - ret = strings.Replace(ret, "$TIME", fmt.Sprintf("%s", tm.Format(timeFormat)), 1) - ret = strings.Replace(ret, "```", fmt.Sprintf("\n\n"), 10) - } - if api.Msg.Content.Type == "attachment" { - ret = outputFormat - tm := time.Unix(int64(api.Msg.SentAt), 0) - ret = strings.Replace(ret, "$MSG", "ATTACHMENT MSG", 1) - ret = strings.Replace(ret, "$USER", api.Msg.Sender.Username, 1) - ret = strings.Replace(ret, "$DEVICE", api.Msg.Sender.DeviceName, 1) - ret = strings.Replace(ret, "$ID", fmt.Sprintf("%d", api.Msg.ID), 1) - ret = strings.Replace(ret, "$DATE", fmt.Sprintf("%s", tm.Format(dateFormat)), 1) - ret = strings.Replace(ret, "$TIME", fmt.Sprintf("%s", tm.Format(timeFormat)), 1) - } + var msg = api.Msg.Content.Text.Body + // mention teams or users + msg = colorRegex(msg, `(@\w*(\.\w+)*)`, messageLinkColor, messageBodyColor) + // mention URL + msg = colorRegex(msg, `(https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*))`, messageLinkColor, messageBodyColor) + msg = colorText(colorReplaceMentionMe(msg, messageBodyColor), messageBodyColor,c) + if msgType == "attachment" { + msg = fmt.Sprintf("%s\n%s", msg, colorText("[Attachment]", messageAttachmentColor, c)) + } + user := colorUsername(api.Msg.Sender.Username, c) + device := colorText(api.Msg.Sender.Username, messageSenderDeviceColor, c) + msgId := colorText(fmt.Sprintf("%d", api.Msg.ID), messageIdColor, c) + ts := colorText(fmt.Sprintf("%s", tm.Format(timeFormat)), messageTimeColor, c) + ret = strings.Replace(ret, "$MSG", msg, 1) + ret = strings.Replace(ret, "$USER", user, 1) + ret = strings.Replace(ret, "$DEVICE", device, 1) + ret = strings.Replace(ret, "$ID", msgId, 1) + ret = strings.Replace(ret, "$TIME", ts, 1) + ret = strings.Replace(ret, "```", fmt.Sprintf("\n\n"), -1) + } return ret } @@ -173,9 +178,9 @@ func populateList() { } else { clearView("List") - var recentPMs = "---[PMs]---\n" + var recentPMs = fmt.Sprintf("%s---[PMs]---%s\n", channelsHeaderColor, channelsColor); var recentPMsCount = 0 - var recentChannels = "---[Teams]---\n" + var recentChannels = fmt.Sprintf("%s---[Teams]---%s\n", channelsHeaderColor, channelsColor); var recentChannelsCount = 0 for _, s := range testVar.Result.Conversations { channels = append(channels, s.Channel) @@ -183,22 +188,22 @@ func populateList() { recentChannelsCount++ if recentChannelsCount <= ((maxY - 2) / 3) { if s.Unread { - recentChannels += "*" + recentChannels += fmt.Sprintf("%s*",color(0)) } - recentChannels += fmt.Sprintf("%s\n\t#%s\n", s.Channel.Name, s.Channel.TopicName) + recentChannels += fmt.Sprintf("%s\n\t#%s\n%s", s.Channel.Name, s.Channel.TopicName, channelsColor) } } else { recentPMsCount++ if recentPMsCount <= ((maxY - 2) / 3) { if s.Unread { - recentPMs += "*" + recentChannels += fmt.Sprintf("%s*",color(0)) } - recentPMs += fmt.Sprintf("%s\n", cleanChannelName(s.Channel.Name)) + recentPMs += fmt.Sprintf("%s\n%s", cleanChannelName(s.Channel.Name), channelsColor) } } } time.Sleep(1 * time.Millisecond) - printToView("List", fmt.Sprintf("%s%s", recentPMs, recentChannels)) + printToView("List", fmt.Sprintf("%s%s%s%s", channelsColor, recentPMs, recentChannels, noColor)) } } @@ -385,7 +390,7 @@ func layout(g *gocui.Gui) error { } inputView.Editable = true inputView.Wrap = true - inputView.Title = " Not in a chat /j to join" + inputView.Title = fmt.Sprintf(" Not in a chat - write `%sj` to join", cmdPrefix) g.Cursor = true } if listView, err4 := g.SetView("List", 0, 0, maxX/2-maxX/3-1, maxY-1, 0); err4 != nil { diff --git a/userConfigs.go b/userConfigs.go index 85dd744..d27ef61 100644 --- a/userConfigs.go +++ b/userConfigs.go @@ -1,8 +1,21 @@ package main - // Path where Downloaded files will default to var downloadPath = "/tmp/" +var colorless = false +var channelsColor = color(8) +var channelsHeaderColor = color(6) +var noColor = color(-1) +var mentionColor = color(3) +var messageHeaderColor = color(8) +var messageIdColor = color(7) +var messageTimeColor = color(6) +var messageSenderDefaultColor = color(8) +var messageSenderDeviceColor = color(8) +var messageBodyColor = noColor +var messageAttachmentColor = color(2) +var messageLinkColor = color(4) + // BASH-like PS1 variable equivalent (without colours) var outputFormat = "┌──[$USER@$DEVICE] [$ID] [$DATE - $TIME]\n└╼ $MSG" From d536cbd6cd87e0a3c3c7578100fd7a436b22413c Mon Sep 17 00:00:00 2001 From: Casper Weiss Bang Date: Mon, 14 Oct 2019 21:45:14 +0200 Subject: [PATCH 3/5] Fixed bugs regarding the join command Changes: - made it possible join with @ and # prepended as well - Also made it possible if it's written in a singular string ie `@team#channel` - also made this work with auto complete - doesn't bug out if you do `/j @person` (with a space at the end) (which it previously thought was a team + channel, with empty channel name --- cmdJoin.go | 40 ++++++++++++++++++++++++---------------- main.go | 16 ++++++++++++++-- 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/cmdJoin.go b/cmdJoin.go index 8d040d4..1e66613 100644 --- a/cmdJoin.go +++ b/cmdJoin.go @@ -4,8 +4,8 @@ package main import ( "fmt" - "samhofi.us/x/keybase" + "strings" ) func init() { @@ -21,23 +21,31 @@ func init() { func cmdJoin(cmd []string) { stream = false - if len(cmd) == 3 { - channel.MembersType = keybase.TEAM - channel.Name = cmd[1] - channel.TopicName = cmd[2] - printToView("Feed", fmt.Sprintf("You are joining: @%s#%s", channel.Name, channel.TopicName)) - clearView("Chat") - viewTitle("Input", fmt.Sprintf(" @%s#%s ", channel.Name, channel.TopicName)) - go populateChat() - } else if len(cmd) == 2 { - channel.MembersType = keybase.USER - channel.Name = cmd[1] - channel.TopicName = "" - printToView("Feed", fmt.Sprintf("You are joining: @%s", channel.Name)) + switch l := len(cmd); l { + case 3: + fallthrough + case 2: + // if people write it in one singular line, with a `#` + firstArgSplit := strings.Split(cmd[1], "#") + channel.Name = strings.Replace(firstArgSplit[0], "@", "", 1) + joinedName := fmt.Sprintf("@%s", channel.Name) + if l == 3 || len(firstArgSplit) == 2 { + channel.MembersType = keybase.TEAM + if l == 3 { + channel.TopicName = strings.Replace(cmd[2], "#", "", 1) + } else { + channel.TopicName = firstArgSplit[1] + } + joinedName = fmt.Sprintf("%s#%s", joinedName, channel.TopicName) + } else { + channel.TopicName = "" + channel.MembersType = keybase.USER + } + printToView("Feed", fmt.Sprintf("You are joining: %s", joinedName)) clearView("Chat") - viewTitle("Input", fmt.Sprintf(" @%s ", channel.Name)) + viewTitle("Input", fmt.Sprintf(" %s ", joinedName)) go populateChat() - } else { + default: printToView("Feed", fmt.Sprintf("To join a team use %sjoin ", cmdPrefix)) printToView("Feed", fmt.Sprintf("To join a PM use %sjoin ", cmdPrefix)) } diff --git a/main.go b/main.go index f1247fd..fa628b2 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,7 @@ import ( "fmt" "log" "os" + "regexp" "strings" "time" @@ -290,7 +291,7 @@ func handleTab() error { return err } else { // if you successfully get an input string, grab the last word from the string - ss := strings.Split(inputString, " ") + ss := regexp.MustCompile(`[ #]`).Split(inputString, -1) s := ss[len(ss)-1] // now in case the word (s) is a mention @something, lets remove it to normalize if strings.HasPrefix(s, "@") { @@ -530,6 +531,17 @@ func handleMessage(api keybase.ChatAPI) { } } +// It seems that golang doesn't have filter and other high order functions :'( +func delete_empty(s []string) []string { + var r []string + for _, str := range s { + if str != "" { + r = append(r, str) + } + } + return r +} + func handleInput(viewName string) error { clearView(viewName) inputString, _ := getInputString(viewName) @@ -537,7 +549,7 @@ func handleInput(viewName string) error { return nil } if strings.HasPrefix(inputString, cmdPrefix) { - cmd := strings.Split(inputString[len(cmdPrefix):], " ") + cmd := delete_empty(strings.Split(inputString[len(cmdPrefix):], " ")) if c, ok := commands[cmd[0]]; ok { c.Exec(cmd) return nil From cdc35483c66bf55b14da4446eafca9b964ea5e92 Mon Sep 17 00:00:00 2001 From: Gregory Rudolph Date: Tue, 15 Oct 2019 07:31:03 -0400 Subject: [PATCH 4/5] Bugfix: Show user device instead of username twice, and show date post coloring --- main.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main.go b/main.go index 6c9e622..5229fa4 100644 --- a/main.go +++ b/main.go @@ -159,7 +159,7 @@ func formatOutput(api keybase.ChatAPI) string { } user := colorUsername(api.Msg.Sender.Username, c) - device := colorText(api.Msg.Sender.Username, messageSenderDeviceColor, c) + device := colorText(api.Msg.Sender.DeviceName, messageSenderDeviceColor, c) msgId := colorText(fmt.Sprintf("%d", api.Msg.ID), messageIdColor, c) ts := colorText(fmt.Sprintf("%s", tm.Format(timeFormat)), messageTimeColor, c) ret = strings.Replace(ret, "$MSG", msg, 1) @@ -167,6 +167,7 @@ func formatOutput(api keybase.ChatAPI) string { ret = strings.Replace(ret, "$DEVICE", device, 1) ret = strings.Replace(ret, "$ID", msgId, 1) ret = strings.Replace(ret, "$TIME", ts, 1) + ret = strings.Replace(ret, "$DATE", fmt.Sprintf("%s", tm.Format(dateFormat)), 1) ret = strings.Replace(ret, "```", fmt.Sprintf("\n\n"), -1) } return ret From 10ada5cd5f9029363742bf4e319e1ee74acf02b5 Mon Sep 17 00:00:00 2001 From: Gregory Rudolph Date: Tue, 15 Oct 2019 07:39:20 -0400 Subject: [PATCH 5/5] Go fmt --- colors.go | 5 +++-- main.go | 14 +++++++------- userConfigs.go | 1 + 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/colors.go b/colors.go index 3ddf629..2625b13 100644 --- a/colors.go +++ b/colors.go @@ -2,10 +2,10 @@ package main import ( "fmt" - "regexp" + "regexp" ) -// TODO maybe datastructure +// TODO maybe datastructure // BASH-like PS1 variable equivalent (without colours) // TODO bold? cursive etc? func color(c int) string { @@ -18,6 +18,7 @@ func color(c int) string { return fmt.Sprintf("\033[0;%dm", 29+c) } } + // TODO maybe make the text into some datastructure which remembers the color func colorText(text string, color string, offColor string) string { return fmt.Sprintf("%s%s%s", color, text, offColor) diff --git a/main.go b/main.go index 5229fa4..5adaa97 100644 --- a/main.go +++ b/main.go @@ -143,8 +143,8 @@ func sendChat(message string) { func formatOutput(api keybase.ChatAPI) string { ret := "" msgType := api.Msg.Content.Type - switch (msgType) { - case "text", "attachment": + switch msgType { + case "text", "attachment": var c = messageHeaderColor ret = colorText(outputFormat, c, noColor) tm := time.Unix(int64(api.Msg.SentAt), 0) @@ -153,7 +153,7 @@ func formatOutput(api keybase.ChatAPI) string { msg = colorRegex(msg, `(@\w*(\.\w+)*)`, messageLinkColor, messageBodyColor) // mention URL msg = colorRegex(msg, `(https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*))`, messageLinkColor, messageBodyColor) - msg = colorText(colorReplaceMentionMe(msg, messageBodyColor), messageBodyColor,c) + msg = colorText(colorReplaceMentionMe(msg, messageBodyColor), messageBodyColor, c) if msgType == "attachment" { msg = fmt.Sprintf("%s\n%s", msg, colorText("[Attachment]", messageAttachmentColor, c)) } @@ -180,9 +180,9 @@ func populateList() { } else { clearView("List") - var recentPMs = fmt.Sprintf("%s---[PMs]---%s\n", channelsHeaderColor, channelsColor); + var recentPMs = fmt.Sprintf("%s---[PMs]---%s\n", channelsHeaderColor, channelsColor) var recentPMsCount = 0 - var recentChannels = fmt.Sprintf("%s---[Teams]---%s\n", channelsHeaderColor, channelsColor); + var recentChannels = fmt.Sprintf("%s---[Teams]---%s\n", channelsHeaderColor, channelsColor) var recentChannelsCount = 0 for _, s := range testVar.Result.Conversations { channels = append(channels, s.Channel) @@ -190,7 +190,7 @@ func populateList() { recentChannelsCount++ if recentChannelsCount <= ((maxY - 2) / 3) { if s.Unread { - recentChannels += fmt.Sprintf("%s*",color(0)) + recentChannels += fmt.Sprintf("%s*", color(0)) } recentChannels += fmt.Sprintf("%s\n\t#%s\n%s", s.Channel.Name, s.Channel.TopicName, channelsColor) } @@ -198,7 +198,7 @@ func populateList() { recentPMsCount++ if recentPMsCount <= ((maxY - 2) / 3) { if s.Unread { - recentChannels += fmt.Sprintf("%s*",color(0)) + recentChannels += fmt.Sprintf("%s*", color(0)) } recentPMs += fmt.Sprintf("%s\n%s", cleanChannelName(s.Channel.Name), channelsColor) } diff --git a/userConfigs.go b/userConfigs.go index d27ef61..2319247 100644 --- a/userConfigs.go +++ b/userConfigs.go @@ -1,4 +1,5 @@ package main + // Path where Downloaded files will default to var downloadPath = "/tmp/"