Mo' colors
Changes: - Stream is colored now - Stream is formatted - Stream has it's own formatting option - Colors are now a style, and is a struct - Color struct has a pretty cool functional interface - colored mentions and PMs - Every message uses the same function (it's dry!!) - Colorize errors! - Create function for visualizing errors - colorized some of the command output! - Color is stored in a Style - Create a Text struct that can use to stylize strings "easily" - Text can be used to build strings - color highlighting on code - added tml config support - added different color for mention url - Added sprintf to use formatting with PrintFeed and PrintError Known Bugs: (added as todos whereever) - Cannot use multiple formatting at the same time (*bold _italic_* doesn't work - sprintf is pretty shit - background doesn't cover as a `block` in codeblocks - not possible to escape sprintf thing
This commit is contained in:
@ -3,7 +3,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
@ -28,7 +27,7 @@ func cmdDelete(cmd []string) {
|
||||
chat := k.NewChat(channel)
|
||||
_, err := chat.Delete(messageID)
|
||||
if err != nil {
|
||||
printToView("Feed", fmt.Sprintf("There was an error deleting your message."))
|
||||
printError("There was an error deleting your message.")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -21,22 +21,22 @@ func init() {
|
||||
func cmdDownloadFile(cmd []string) {
|
||||
|
||||
if len(cmd) < 2 {
|
||||
printToView("Feed", fmt.Sprintf("%s%s $messageId $fileName - Download a file to user's downloadpath", cmdPrefix, cmd[0]))
|
||||
printInfo(fmt.Sprintf("%s%s $messageId $fileName - Download a file to user's downloadpath", cmdPrefix, cmd[0]))
|
||||
return
|
||||
}
|
||||
messageID, err := strconv.Atoi(cmd[1])
|
||||
if err != nil {
|
||||
printToView("Feed", "There was an error converting your messageID to an int")
|
||||
printError("There was an error converting your messageID to an int")
|
||||
return
|
||||
}
|
||||
chat := k.NewChat(channel)
|
||||
api, err := chat.ReadMessage(messageID)
|
||||
if err != nil {
|
||||
printToView("Feed", fmt.Sprintf("There was an error pulling message %d", messageID))
|
||||
printError(fmt.Sprintf("There was an error pulling message %d", messageID))
|
||||
return
|
||||
}
|
||||
if api.Result.Messages[0].Msg.Content.Type != "attachment" {
|
||||
printToView("Feed", "No attachment detected")
|
||||
printError("No attachment detected")
|
||||
return
|
||||
}
|
||||
var fileName string
|
||||
@ -47,9 +47,10 @@ func cmdDownloadFile(cmd []string) {
|
||||
}
|
||||
|
||||
_, err = chat.Download(messageID, fmt.Sprintf("%s/%s", downloadPath, fileName))
|
||||
channelName := messageLinkKeybaseColor.stylize(channel.Name)
|
||||
if err != nil {
|
||||
printToView("Feed", fmt.Sprintf("There was an error downloading %s from %s", fileName, channel.Name))
|
||||
printErrorF(fmt.Sprintf("There was an error downloading %s from $TEXT", fileName), channelName)
|
||||
} else {
|
||||
printToView("Feed", fmt.Sprintf("Downloaded %s from %s", fileName, channel.Name))
|
||||
printInfoF(fmt.Sprintf("Downloaded %s from $TEXT", fileName), channelName)
|
||||
}
|
||||
}
|
||||
|
||||
12
cmdEdit.go
12
cmdEdit.go
@ -27,21 +27,21 @@ func cmdEdit(cmd []string) {
|
||||
messageID, _ = strconv.Atoi(cmd[1])
|
||||
} else if lastMessage.ID != 0 {
|
||||
if lastMessage.Type != "text" {
|
||||
printToView("Feed", "Last message isn't editable (is it an edit?)")
|
||||
printError("Last message isn't editable (is it an edit?)")
|
||||
return
|
||||
}
|
||||
messageID = lastMessage.ID
|
||||
} else {
|
||||
printToView("Feed", "No message to edit")
|
||||
printError("No message to edit")
|
||||
return
|
||||
}
|
||||
origMessage, _ := chat.ReadMessage(messageID)
|
||||
if origMessage.Result.Messages[0].Msg.Content.Type != "text" {
|
||||
printToView("Feed", fmt.Sprintf("%+v", origMessage))
|
||||
printInfo(fmt.Sprintf("%+v", origMessage))
|
||||
return
|
||||
}
|
||||
if origMessage.Result.Messages[0].Msg.Sender.Username != k.Username {
|
||||
printToView("Feed", "You cannot edit another user's messages.")
|
||||
printError("You cannot edit another user's messages.")
|
||||
return
|
||||
}
|
||||
editString := origMessage.Result.Messages[0].Msg.Content.Text.Body
|
||||
@ -53,14 +53,14 @@ func cmdEdit(cmd []string) {
|
||||
return
|
||||
}
|
||||
if len(cmd) < 3 {
|
||||
printToView("Feed", "Not enough options for Edit")
|
||||
printError("Not enough options for Edit")
|
||||
return
|
||||
}
|
||||
messageID, _ = strconv.Atoi(cmd[1])
|
||||
newMessage := strings.Join(cmd[2:], " ")
|
||||
_, err := chat.Edit(messageID, newMessage)
|
||||
if err != nil {
|
||||
printToView("Feed", fmt.Sprintf("Error editing message %d, %+v", messageID, err))
|
||||
printError(fmt.Sprintf("Error editing message %d, %+v", messageID, err))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -41,12 +41,12 @@ func cmdJoin(cmd []string) {
|
||||
channel.TopicName = ""
|
||||
channel.MembersType = keybase.USER
|
||||
}
|
||||
printToView("Feed", fmt.Sprintf("You are joining: %s", joinedName))
|
||||
printInfoF("You are joining: $TEXT", messageLinkKeybaseColor.stylize(joinedName))
|
||||
clearView("Chat")
|
||||
setViewTitle("Input", fmt.Sprintf(" %s ", joinedName))
|
||||
go populateChat()
|
||||
default:
|
||||
printToView("Feed", fmt.Sprintf("To join a team use %sjoin <team> <channel>", cmdPrefix))
|
||||
printToView("Feed", fmt.Sprintf("To join a PM use %sjoin <user>", cmdPrefix))
|
||||
printInfo(fmt.Sprintf("To join a team use %sjoin <team> <channel>", cmdPrefix))
|
||||
printInfo(fmt.Sprintf("To join a PM use %sjoin <user>", cmdPrefix))
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,8 +29,8 @@ func cmdPost(cmd []string) {
|
||||
chat := k.NewChat(pubChan)
|
||||
_, err := chat.Send(post)
|
||||
if err != nil {
|
||||
printToView("Feed", fmt.Sprintf("There was an error with your post: %+v", err))
|
||||
printError(fmt.Sprintf("There was an error with your post: %+v", err))
|
||||
} else {
|
||||
printToView("Feed", "You have publically posted to your wall, signed by your current device.")
|
||||
printInfo("You have publically posted to your wall, signed by your current device.")
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,6 +38,6 @@ func doReact(messageID int, reaction string) {
|
||||
chat := k.NewChat(channel)
|
||||
_, err := chat.React(messageID, reaction)
|
||||
if err != nil {
|
||||
printToView("Feed", "There was an error reacting to the message.")
|
||||
printError("There was an error reacting to the message.")
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,18 +22,17 @@ func init() {
|
||||
func cmdReply(cmd []string) {
|
||||
chat := k.NewChat(channel)
|
||||
if len(cmd) < 2 {
|
||||
printToView("Feed", fmt.Sprintf("%s%s $ID - Reply to message $ID", cmdPrefix, cmd[0]))
|
||||
printInfo(fmt.Sprintf("%s%s $ID - Reply to message $ID", cmdPrefix, cmd[0]))
|
||||
return
|
||||
}
|
||||
messageID, err := strconv.Atoi(cmd[1])
|
||||
if err != nil {
|
||||
printToView("Feed", fmt.Sprintf("There was an error determining message ID %s", cmd[1]))
|
||||
printError(fmt.Sprintf("There was an error determining message ID %s", cmd[1]))
|
||||
return
|
||||
}
|
||||
_, err = chat.Reply(messageID, strings.Join(cmd[2:], " "))
|
||||
if err != nil {
|
||||
printToView("Feed", "There was an error with your reply.")
|
||||
printError("There was an error with your reply.")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
46
cmdSet.go
46
cmdSet.go
@ -23,25 +23,24 @@ func printSetting(cmd []string) {
|
||||
switch cmd[1] {
|
||||
case "load":
|
||||
loadFromToml()
|
||||
printInfo("Loading config from toml")
|
||||
case "downloadPath":
|
||||
printToView("Feed", fmt.Sprintf("Setting for %s -> %s", cmd[1], downloadPath))
|
||||
printInfo(fmt.Sprintf("Setting for %s -> %s", cmd[1], downloadPath))
|
||||
case "outputFormat":
|
||||
printToView("Feed", fmt.Sprintf("Setting for %s -> %s", cmd[1], outputFormat))
|
||||
printInfo(fmt.Sprintf("Setting for %s -> %s", cmd[1], outputFormat))
|
||||
case "dateFormat":
|
||||
printToView("Feed", fmt.Sprintf("Setting for %s -> %s", cmd[1], dateFormat))
|
||||
printInfo(fmt.Sprintf("Setting for %s -> %s", cmd[1], dateFormat))
|
||||
case "timeFormat":
|
||||
printToView("Feed", fmt.Sprintf("Setting for %s -> %s", cmd[1], timeFormat))
|
||||
printInfo(fmt.Sprintf("Setting for %s -> %s", cmd[1], timeFormat))
|
||||
case "cmdPrefix":
|
||||
printToView("Feed", fmt.Sprintf("Setting for %s -> %s", cmd[1], cmdPrefix))
|
||||
printInfo(fmt.Sprintf("Setting for %s -> %s", cmd[1], cmdPrefix))
|
||||
default:
|
||||
printToView("Feed", fmt.Sprintf("Unknown config value %s", cmd[1]))
|
||||
printError(fmt.Sprintf("Unknown config value %s", cmd[1]))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
func cmdSet(cmd []string) {
|
||||
if len(cmd) < 2 {
|
||||
printToView("Feed", "No config value specified")
|
||||
printError("No config value specified")
|
||||
return
|
||||
}
|
||||
if len(cmd) < 3 {
|
||||
@ -51,7 +50,7 @@ func cmdSet(cmd []string) {
|
||||
switch cmd[1] {
|
||||
case "downloadPath":
|
||||
if len(cmd) != 3 {
|
||||
printToView("Feed", "Invalid download path.")
|
||||
printError("Invalid download path.")
|
||||
}
|
||||
downloadPath = cmd[2]
|
||||
case "outputFormat":
|
||||
@ -63,17 +62,17 @@ func cmdSet(cmd []string) {
|
||||
case "cmdPrefix":
|
||||
cmdPrefix = cmd[2]
|
||||
default:
|
||||
printToView("Feed", fmt.Sprintf("Unknown config value %s", cmd[1]))
|
||||
printError(fmt.Sprintf("Unknown config value %s", cmd[1]))
|
||||
}
|
||||
|
||||
}
|
||||
func loadFromToml() {
|
||||
printToView("Feed", fmt.Sprintf("Loading config from toml"))
|
||||
config, err := toml.LoadFile("kbtui.tml")
|
||||
if err != nil {
|
||||
printToView("Feed", fmt.Sprintf("Could not read config file: %+v", err))
|
||||
printError(fmt.Sprintf("Could not read config file: %+v", err))
|
||||
return
|
||||
}
|
||||
colorless = config.GetDefault("Basics.colorless", false).(bool)
|
||||
if config.Has("Basics.colorless") {
|
||||
colorless = config.Get("Basics.colorless").(bool)
|
||||
}
|
||||
@ -92,5 +91,26 @@ func loadFromToml() {
|
||||
if config.Has("Formatting.timeFormat") {
|
||||
timeFormat = config.Get("Formatting.timeFormat").(string)
|
||||
}
|
||||
channelsColor = styleFromConfig(config, "channels.basic")
|
||||
|
||||
channelsHeaderColor = styleFromConfig(config, "channels.header")
|
||||
channelUnreadColor = styleFromConfig(config, "channels.unread")
|
||||
|
||||
mentionColor = styleFromConfig(config, "message.mention")
|
||||
messageHeaderColor = styleFromConfig(config, "message.header")
|
||||
messageIDColor = styleFromConfig(config, "message.id")
|
||||
messageTimeColor = styleFromConfig(config, "message.time")
|
||||
messageSenderDefaultColor = styleFromConfig(config, "message.sender_default")
|
||||
messageSenderDeviceColor = styleFromConfig(config, "message.sender_device")
|
||||
messageBodyColor = styleFromConfig(config, "message.body")
|
||||
messageAttachmentColor = styleFromConfig(config, "message.attachment")
|
||||
messageLinkURLColor = styleFromConfig(config, "message.link_url")
|
||||
messageLinkKeybaseColor = styleFromConfig(config, "message.link_keybase")
|
||||
messageReactionColor = styleFromConfig(config, "message.reaction")
|
||||
messageCodeColor = styleFromConfig(config, "message.code")
|
||||
|
||||
feedColor = styleFromConfig(config, "feed.basic")
|
||||
errorColor = styleFromConfig(config, "feed.error")
|
||||
|
||||
RunCommand("clean")
|
||||
}
|
||||
|
||||
@ -2,6 +2,10 @@
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func init() {
|
||||
command := Command{
|
||||
Cmd: []string{"stream", "s"},
|
||||
@ -17,7 +21,7 @@ func cmdStream(cmd []string) {
|
||||
stream = true
|
||||
channel.Name = ""
|
||||
|
||||
printToView("Feed", "You are now viewing the formatted stream")
|
||||
setViewTitle("Input", " Stream - Not in a chat /j to join ")
|
||||
printInfo("You are now viewing the formatted stream")
|
||||
setViewTitle("Input", fmt.Sprintf(" Stream - Not in a chat. %sj to join ", cmdPrefix))
|
||||
clearView("Chat")
|
||||
}
|
||||
|
||||
@ -21,14 +21,14 @@ func init() {
|
||||
|
||||
func cmdUploadFile(cmd []string) {
|
||||
if len(cmd) < 2 {
|
||||
printToView("Feed", fmt.Sprintf("%s%s $filePath $fileName - Upload file from absolute path with optional name", cmdPrefix, cmd[0]))
|
||||
printInfo(fmt.Sprintf("%s%s $filePath $fileName - Upload file from absolute path with optional name", cmdPrefix, cmd[0]))
|
||||
return
|
||||
}
|
||||
filePath := cmd[1]
|
||||
if !strings.HasPrefix(filePath, "/") {
|
||||
dir, err := os.Getwd()
|
||||
if err != nil {
|
||||
printToView("Feed", fmt.Sprintf("There was an error determining path %+v", err))
|
||||
printError(fmt.Sprintf("There was an error determining path %+v", err))
|
||||
}
|
||||
filePath = fmt.Sprintf("%s/%s", dir, filePath)
|
||||
}
|
||||
@ -40,9 +40,10 @@ func cmdUploadFile(cmd []string) {
|
||||
}
|
||||
chat := k.NewChat(channel)
|
||||
_, err := chat.Upload(fileName, filePath)
|
||||
channelName := messageLinkKeybaseColor.stylize(channel.Name).string()
|
||||
if err != nil {
|
||||
printToView("Feed", fmt.Sprintf("There was an error uploading %s to %s\n%+v", filePath, channel.Name, err))
|
||||
printError(fmt.Sprintf("There was an error uploading %s to %s\n%+v", filePath, channelName, err))
|
||||
} else {
|
||||
printToView("Feed", fmt.Sprintf("Uploaded %s to %s", filePath, channel.Name))
|
||||
printInfo(fmt.Sprintf("Uploaded %s to %s", filePath, channelName))
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,13 +64,14 @@ func cmdPopulateWall(cmd []string) {
|
||||
if len(users) < 1 {
|
||||
return
|
||||
}
|
||||
printToView("Feed", fmt.Sprintf("Displaying public messages for user %s", requestedUsers))
|
||||
|
||||
printInfoF("Displaying public messages for user $TEXT", messageLinkKeybaseColor.stylize(requestedUsers))
|
||||
for _, chann := range users {
|
||||
chat := k.NewChat(chann)
|
||||
api, err := chat.Read()
|
||||
if err != nil {
|
||||
if len(users) < 6 {
|
||||
printToView("Feed", fmt.Sprintf("There was an error for user %s: %+v", cleanChannelName(chann.Name), err))
|
||||
printError(fmt.Sprintf("There was an error for user %s: %+v", cleanChannelName(chann.Name), err))
|
||||
return
|
||||
}
|
||||
} else {
|
||||
|
||||
@ -42,20 +42,20 @@ func cmdWallet(cmd []string) {
|
||||
walletConfirmationCode = b.String()
|
||||
walletConfirmationUser = cmd[1]
|
||||
walletTransactionAmnt = cmd[2]
|
||||
printToView("Feed", fmt.Sprintf("To confirm sending %s to %s, type /confirm %s %s", cmd[2], cmd[1], cmd[1], walletConfirmationCode))
|
||||
printInfo(fmt.Sprintf("To confirm sending %s to %s, type /confirm %s %s", cmd[2], cmd[1], cmd[1], walletConfirmationCode))
|
||||
|
||||
} else if cmd[0] == "confirm" {
|
||||
if cmd[1] == walletConfirmationUser && cmd[2] == walletConfirmationCode {
|
||||
txWallet := k.NewWallet()
|
||||
wAPI, err := txWallet.SendXLM(walletConfirmationUser, walletTransactionAmnt, "")
|
||||
if err != nil {
|
||||
printToView("Feed", fmt.Sprintf("There was an error with your wallet tx:\n\t%+v", err))
|
||||
printError(fmt.Sprintf("There was an error with your wallet tx:\n\t%+v", err))
|
||||
} else {
|
||||
printToView("Feed", fmt.Sprintf("You have sent %sXLM to %s with tx ID: %s", wAPI.Result.Amount, wAPI.Result.ToUsername, wAPI.Result.TxID))
|
||||
printInfo(fmt.Sprintf("You have sent %sXLM to %s with tx ID: %s", wAPI.Result.Amount, wAPI.Result.ToUsername, wAPI.Result.TxID))
|
||||
}
|
||||
|
||||
} else {
|
||||
printToView("Feed", "There was an error validating your confirmation. Your wallet has been untouched.")
|
||||
printError("There was an error validating your confirmation. Your wallet has been untouched.")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
238
colors.go
238
colors.go
@ -2,42 +2,230 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/pelletier/go-toml"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// TODO maybe datastructure
|
||||
// BASH-like PS1 variable equivalent (without colours)
|
||||
// TODO bold? cursive etc?
|
||||
func color(c int) string {
|
||||
// Begin Colors
|
||||
type color int
|
||||
|
||||
const (
|
||||
black color = iota
|
||||
red
|
||||
green
|
||||
yellow
|
||||
purple
|
||||
magenta
|
||||
cyan
|
||||
grey
|
||||
normal color = -1
|
||||
)
|
||||
|
||||
func colorFromString(s string) color {
|
||||
s = strings.ToLower(s)
|
||||
switch s {
|
||||
case "black":
|
||||
return black
|
||||
case "red":
|
||||
return red
|
||||
case "green":
|
||||
return green
|
||||
case "yellow":
|
||||
return yellow
|
||||
case "purple":
|
||||
return purple
|
||||
case "magenta":
|
||||
return magenta
|
||||
case "cyan":
|
||||
return cyan
|
||||
case "grey":
|
||||
return grey
|
||||
case "normal":
|
||||
return normal
|
||||
default:
|
||||
printError(fmt.Sprintf("color `%s` cannot be parsed.", s))
|
||||
}
|
||||
return normal
|
||||
}
|
||||
|
||||
// Style struct for specializing the style/color of a stylize
|
||||
type Style struct {
|
||||
foregroundColor color
|
||||
backgroundColor color
|
||||
bold bool
|
||||
italic bool // Currently not supported by the UI library
|
||||
underline bool
|
||||
strikethrough bool // Currently not supported by the UI library
|
||||
inverse bool
|
||||
}
|
||||
|
||||
var basicStyle = Style{normal, normal, false, false, false, false, false}
|
||||
|
||||
func styleFromConfig(config *toml.Tree, key string) Style {
|
||||
key = "Colors." + key + "."
|
||||
style := basicStyle
|
||||
if config.Has(key + "foreground") {
|
||||
style = style.withForeground(colorFromString(config.Get(key + "foreground").(string)))
|
||||
}
|
||||
if config.Has(key + "background") {
|
||||
style = style.withForeground(colorFromString(config.Get(key + "background").(string)))
|
||||
}
|
||||
if config.GetDefault(key+"bold", false).(bool) {
|
||||
style = style.withBold()
|
||||
}
|
||||
if config.GetDefault(key+"italic", false).(bool) {
|
||||
style = style.withItalic()
|
||||
}
|
||||
if config.GetDefault(key+"underline", false).(bool) {
|
||||
style = style.withUnderline()
|
||||
}
|
||||
if config.GetDefault(key+"strikethrough", false).(bool) {
|
||||
style = style.withStrikethrough()
|
||||
}
|
||||
if config.GetDefault(key+"inverse", false).(bool) {
|
||||
style = style.withInverse()
|
||||
}
|
||||
|
||||
return style
|
||||
}
|
||||
|
||||
func (s Style) withForeground(f color) Style {
|
||||
s.foregroundColor = f
|
||||
return s
|
||||
}
|
||||
func (s Style) withBackground(f color) Style {
|
||||
s.backgroundColor = f
|
||||
return s
|
||||
}
|
||||
func (s Style) withBold() Style {
|
||||
s.bold = true
|
||||
return s
|
||||
}
|
||||
func (s Style) withInverse() Style {
|
||||
s.inverse = true
|
||||
return s
|
||||
}
|
||||
func (s Style) withItalic() Style {
|
||||
s.italic = true
|
||||
return s
|
||||
}
|
||||
func (s Style) withStrikethrough() Style {
|
||||
s.strikethrough = true
|
||||
return s
|
||||
}
|
||||
func (s Style) withUnderline() Style {
|
||||
s.underline = true
|
||||
return s
|
||||
}
|
||||
|
||||
// TODO create both as `reset` (which it is now) as well as `append`
|
||||
// which essentially just adds on top. that is relevant in the case of
|
||||
// bold/italic etc - it should add style - not clear.
|
||||
func (s Style) toANSI() string {
|
||||
if colorless {
|
||||
return ""
|
||||
}
|
||||
if c < 0 {
|
||||
return "\033[0m"
|
||||
} else {
|
||||
return fmt.Sprintf("\033[0;%dm", 29+c)
|
||||
output := "\x1b[0m\x1b[0"
|
||||
if s.foregroundColor != normal {
|
||||
output += fmt.Sprintf(";%d", 30+s.foregroundColor)
|
||||
}
|
||||
if s.backgroundColor != normal {
|
||||
output += fmt.Sprintf(";%d", 40+s.backgroundColor)
|
||||
}
|
||||
if s.bold {
|
||||
output += ";1"
|
||||
}
|
||||
if s.italic {
|
||||
output += ";3"
|
||||
}
|
||||
if s.underline {
|
||||
output += ";4"
|
||||
}
|
||||
if s.inverse {
|
||||
output += ";7"
|
||||
}
|
||||
if s.strikethrough {
|
||||
output += ";9"
|
||||
}
|
||||
|
||||
// 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)
|
||||
return output + "m"
|
||||
}
|
||||
|
||||
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))
|
||||
// End Colors
|
||||
// Begin StyledString
|
||||
|
||||
// StyledString is used to save a message with a style, which can then later be rendered to a string
|
||||
type StyledString struct {
|
||||
message string
|
||||
style Style
|
||||
}
|
||||
|
||||
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)
|
||||
// TODO handle all formatting types
|
||||
func (s Style) sprintf(base string, parts ...StyledString) StyledString {
|
||||
text := s.stylize(removeFormatting(base))
|
||||
//TODO handle posibility to escape
|
||||
re := regexp.MustCompile(`\$TEXT`)
|
||||
for len(re.FindAllString(text.message, 1)) > 0 {
|
||||
part := parts[0]
|
||||
parts = parts[1:]
|
||||
text = text.replaceN("$TEXT", part, 1)
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
func (s Style) stylize(msg string) StyledString {
|
||||
return StyledString{msg, s}
|
||||
}
|
||||
func (t StyledString) stringFollowedByStyle(style Style) string {
|
||||
return t.style.toANSI() + t.message + style.toANSI()
|
||||
}
|
||||
func (t StyledString) string() string {
|
||||
return t.stringFollowedByStyle(basicStyle)
|
||||
}
|
||||
|
||||
func (t StyledString) replace(match string, value StyledString) StyledString {
|
||||
return t.replaceN(match, value, -1)
|
||||
}
|
||||
func (t StyledString) replaceN(match string, value StyledString, n int) StyledString {
|
||||
t.message = strings.Replace(t.message, match, value.stringFollowedByStyle(t.style), n)
|
||||
return t
|
||||
}
|
||||
func (t StyledString) replaceString(match string, value string) StyledString {
|
||||
t.message = strings.Replace(t.message, match, value, -1)
|
||||
return t
|
||||
}
|
||||
func (t StyledString) replaceRegex(match string, value StyledString) StyledString {
|
||||
var re = regexp.MustCompile("(" + match + ")")
|
||||
t.message = re.ReplaceAllString(t.message, value.stringFollowedByStyle(t.style))
|
||||
return t
|
||||
}
|
||||
|
||||
// Overrides current formatting
|
||||
func (t StyledString) colorRegex(match string, style Style) StyledString {
|
||||
re := regexp.MustCompile("(" + match + ")")
|
||||
subStrings := re.FindAllString(t.message, -1)
|
||||
for _, element := range subStrings {
|
||||
cleanSubstring := style.stylize(removeFormatting(element))
|
||||
t.message = strings.Replace(t.message, element, cleanSubstring.stringFollowedByStyle(t.style), -1)
|
||||
}
|
||||
return t
|
||||
// Old versionreturn t.replaceRegex(match, style.stylize(`$1`))
|
||||
}
|
||||
|
||||
// Appends the other stylize at the end, but retains same style
|
||||
func (t StyledString) append(other StyledString) StyledString {
|
||||
t.message = t.message + other.stringFollowedByStyle(t.style)
|
||||
return t
|
||||
}
|
||||
func (t StyledString) appendString(other string) StyledString {
|
||||
t.message += other
|
||||
return t
|
||||
}
|
||||
|
||||
// Begin Formatting
|
||||
|
||||
func removeFormatting(s string) string {
|
||||
reFormatting := regexp.MustCompile(`(?m)\x1b\[(\d*;?)*m`)
|
||||
return reFormatting.ReplaceAllString(s, "")
|
||||
}
|
||||
|
||||
57
kbtui.tml
57
kbtui.tml
@ -16,15 +16,48 @@ timeFormat = "15:04"
|
||||
|
||||
|
||||
[Colors]
|
||||
channelsColor = 8
|
||||
channelsHeaderColor = 6
|
||||
noColor = -1
|
||||
mentionColor = 3
|
||||
messageHeaderColor = 8
|
||||
messageIdColor = 7
|
||||
messageTimeColor = 6
|
||||
messageSenderDefaultColor = 8
|
||||
messageSenderDeviceColor = 8
|
||||
messageBodyColor = -1
|
||||
messageAttachmentColor = 2
|
||||
messageLinkColor = 4
|
||||
[Colors.channels]
|
||||
[Colors.channels.basic]
|
||||
foreground = "normal"
|
||||
[Colors.channels.header]
|
||||
foreground = "magenta"
|
||||
bold = true
|
||||
[Colors.channels.unread]
|
||||
foreground = "green"
|
||||
italic = true
|
||||
|
||||
[Colors.message]
|
||||
[Colors.message.body]
|
||||
foreground = "normal"
|
||||
[Colors.message.header]
|
||||
foreground = "grey"
|
||||
[Colors.message.mention]
|
||||
foreground = "green"
|
||||
italic = true
|
||||
bold = true
|
||||
[Colors.message.id]
|
||||
foreground = "yellow"
|
||||
[Colors.message.time]
|
||||
foreground = "magenta"
|
||||
[Colors.message.sender_default]
|
||||
foreground = "cyan"
|
||||
bold = true
|
||||
[Colors.message.sender_device]
|
||||
foreground = "cyan"
|
||||
[Colors.message.attachment]
|
||||
foreground = "red"
|
||||
[Colors.message.link_url]
|
||||
foreground = "yellow"
|
||||
[Colors.message.link_keybase]
|
||||
foreground = "yellow"
|
||||
[Colors.message.reaction]
|
||||
foreground = "magenta"
|
||||
bold = true
|
||||
[Colors.message.code]
|
||||
foreground = "cyan"
|
||||
background = "grey"
|
||||
[Colors.feed]
|
||||
[Colors.feed.basic]
|
||||
foreground = "grey"
|
||||
[Colors.feed.error]
|
||||
foreground = "red"
|
||||
160
main.go
160
main.go
@ -72,7 +72,7 @@ func layout(g *gocui.Gui) error {
|
||||
feedView.Autoscroll = true
|
||||
feedView.Wrap = true
|
||||
feedView.Title = "Feed Window"
|
||||
fmt.Fprintln(feedView, "Feed Window - If you are mentioned or receive a PM it will show here")
|
||||
printInfo("Feed Window - If you are mentioned or receive a PM it will show here")
|
||||
}
|
||||
if chatView, err2 := g.SetView("Chat", maxX/2-maxX/3, maxY/5+1, maxX-1, maxY-5, 0); err2 != nil {
|
||||
if !gocui.IsUnknownView(err2) {
|
||||
@ -80,7 +80,9 @@ func layout(g *gocui.Gui) error {
|
||||
}
|
||||
chatView.Autoscroll = true
|
||||
chatView.Wrap = true
|
||||
fmt.Fprintf(chatView, "Welcome %s!\n\nYour chats will appear here.\nSupported commands are as follows:\n\n", k.Username)
|
||||
welcomeText := basicStyle.stylize("Welcome $USER!\n\nYour chats will appear here.\nSupported commands are as follows:\n")
|
||||
welcomeText = welcomeText.replace("$USER", mentionColor.stylize(k.Username))
|
||||
fmt.Fprintln(chatView, welcomeText.string())
|
||||
RunCommand("help")
|
||||
}
|
||||
if inputView, err3 := g.SetView("Input", maxX/2-maxX/3, maxY-4, maxX-1, maxY-1, 0); err3 != nil {
|
||||
@ -176,20 +178,19 @@ func getViewTitle(viewName string) string {
|
||||
view, err := g.View(viewName)
|
||||
if err != nil {
|
||||
// in case there is active tab completion, filter that to just the view title and not the completion options.
|
||||
printToView("Feed", fmt.Sprintf("Error getting view title: %s", err))
|
||||
printError(fmt.Sprintf("Error getting view title: %s", err))
|
||||
return ""
|
||||
}
|
||||
return strings.Split(view.Title, "||")[0]
|
||||
|
||||
}
|
||||
func popupView(viewName string) {
|
||||
_, err := g.SetCurrentView(viewName)
|
||||
if err != nil {
|
||||
printToView("Feed", fmt.Sprintf("%+v", err))
|
||||
printError(fmt.Sprintf("%+v", err))
|
||||
}
|
||||
_, err = g.SetViewOnTop(viewName)
|
||||
if err != nil {
|
||||
printToView("Feed", fmt.Sprintf("%+v", err))
|
||||
printError(fmt.Sprintf("%+v", err))
|
||||
}
|
||||
g.Update(func(g *gocui.Gui) error {
|
||||
updatingView, err := g.View(viewName)
|
||||
@ -247,6 +248,24 @@ func writeToView(viewName string, message string) {
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// this removes formatting
|
||||
func printError(message string) {
|
||||
printErrorF(message)
|
||||
}
|
||||
func printErrorF(message string, parts ...StyledString) {
|
||||
printToView("Feed", errorColor.sprintf(removeFormatting(message), parts...).string())
|
||||
}
|
||||
|
||||
// this removes formatting
|
||||
func printInfo(message string) {
|
||||
printInfoF(message)
|
||||
}
|
||||
|
||||
// this removes formatting
|
||||
func printInfoF(message string, parts ...StyledString) {
|
||||
printToView("Feed", feedColor.sprintf(removeFormatting(message), parts...).string())
|
||||
}
|
||||
func printToView(viewName string, message string) {
|
||||
g.Update(func(g *gocui.Gui) error {
|
||||
updatingView, err := g.View(viewName)
|
||||
@ -287,13 +306,12 @@ func populateChat() {
|
||||
chat = k.NewChat(channel)
|
||||
_, err2 := chat.Read(2)
|
||||
if err2 != nil {
|
||||
printToView("Feed", fmt.Sprintf("%+v", err))
|
||||
printError(fmt.Sprintf("%+v", err))
|
||||
return
|
||||
}
|
||||
go populateChat()
|
||||
go generateChannelTabCompletionSlice()
|
||||
return
|
||||
|
||||
}
|
||||
var printMe []string
|
||||
var actuallyPrintMe string
|
||||
@ -325,75 +343,122 @@ func populateList() {
|
||||
if testVar, err := k.ChatList(); err != nil {
|
||||
log.Printf("%+v", err)
|
||||
} else {
|
||||
|
||||
clearView("List")
|
||||
var recentPMs = fmt.Sprintf("%s---[PMs]---%s\n", channelsHeaderColor, channelsColor)
|
||||
var textBase = channelsColor.stylize("")
|
||||
var recentPMs = textBase.append(channelsHeaderColor.stylize("---[PMs]---\n"))
|
||||
var recentPMsCount = 0
|
||||
var recentChannels = fmt.Sprintf("%s---[Teams]---%s\n", channelsHeaderColor, channelsColor)
|
||||
var recentChannels = textBase.append(channelsHeaderColor.stylize("---[Teams]---\n"))
|
||||
var recentChannelsCount = 0
|
||||
for _, s := range testVar.Result.Conversations {
|
||||
channels = append(channels, s.Channel)
|
||||
if s.Channel.MembersType == keybase.TEAM {
|
||||
recentChannelsCount++
|
||||
if recentChannelsCount <= ((maxY - 2) / 3) {
|
||||
channel := fmt.Sprintf("%s\n\t#%s\n", s.Channel.Name, s.Channel.TopicName)
|
||||
if s.Unread {
|
||||
recentChannels += fmt.Sprintf("%s*", color(0))
|
||||
recentChannels = recentChannels.append(channelUnreadColor.stylize("*" + channel))
|
||||
} else {
|
||||
recentChannels = recentChannels.appendString(channel)
|
||||
}
|
||||
recentChannels += fmt.Sprintf("%s\n\t#%s\n%s", s.Channel.Name, s.Channel.TopicName, channelsColor)
|
||||
}
|
||||
} else {
|
||||
recentPMsCount++
|
||||
if recentPMsCount <= ((maxY - 2) / 3) {
|
||||
pmName := fmt.Sprintf("%s\n", cleanChannelName(s.Channel.Name))
|
||||
if s.Unread {
|
||||
recentChannels += fmt.Sprintf("%s*", color(0))
|
||||
recentPMs = recentPMs.append(channelUnreadColor.stylize("*" + pmName))
|
||||
} else {
|
||||
recentPMs = recentPMs.appendString(pmName)
|
||||
}
|
||||
recentPMs += fmt.Sprintf("%s\n%s", cleanChannelName(s.Channel.Name), channelsColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
printToView("List", fmt.Sprintf("%s%s%s%s", channelsColor, recentPMs, recentChannels, noColor))
|
||||
go generateRecentTabCompletionSlice()
|
||||
printToView("List", fmt.Sprintf("%s%s", recentPMs.string(), recentChannels.string()))
|
||||
generateRecentTabCompletionSlice()
|
||||
}
|
||||
}
|
||||
|
||||
// End update/populate views automatically
|
||||
|
||||
// Formatting
|
||||
func formatMessageBody(body string) StyledString {
|
||||
output := messageBodyColor.stylize(body)
|
||||
|
||||
output = colorReplaceMentionMe(output)
|
||||
output = output.colorRegex(`_[^_]*_`, messageBodyColor.withItalic())
|
||||
output = output.colorRegex(`~[^~]*~`, messageBodyColor.withStrikethrough())
|
||||
output = output.colorRegex(`@[\w_]*(\.[\w_]+)*`, messageLinkKeybaseColor)
|
||||
// TODO change how bold, italic etc works, so it uses boldOn boldOff ([1m and [22m)
|
||||
output = output.colorRegex(`\*[^\*]*\*`, messageBodyColor.withBold())
|
||||
output = output.replaceString("```", "<code>")
|
||||
// TODO make background color cover whole line
|
||||
output = output.colorRegex("<code>(.*\n)*<code>", messageCodeColor)
|
||||
output = output.colorRegex("`[^`]*`", messageCodeColor)
|
||||
// mention URL
|
||||
output = output.colorRegex(`(https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*))`, messageLinkURLColor)
|
||||
return output
|
||||
}
|
||||
|
||||
// TODO use this more
|
||||
func formatChannel(ch keybase.Channel) StyledString {
|
||||
return messageLinkKeybaseColor.stylize(fmt.Sprintf("@%s#%s", ch.Name, ch.TopicName))
|
||||
}
|
||||
|
||||
func colorReplaceMentionMe(msg StyledString) StyledString {
|
||||
return msg.colorRegex("(@?"+k.Username+")", mentionColor)
|
||||
}
|
||||
func colorUsername(username string) StyledString {
|
||||
var color = messageSenderDefaultColor
|
||||
if username == k.Username {
|
||||
color = mentionColor
|
||||
}
|
||||
return color.stylize(username)
|
||||
}
|
||||
|
||||
func cleanChannelName(c string) string {
|
||||
newChannelName := strings.Replace(c, fmt.Sprintf("%s,", k.Username), "", 1)
|
||||
return strings.Replace(newChannelName, fmt.Sprintf(",%s", k.Username), "", 1)
|
||||
}
|
||||
func formatOutput(api keybase.ChatAPI) string {
|
||||
ret := ""
|
||||
|
||||
func formatMessage(api keybase.ChatAPI, formatString string) string {
|
||||
ret := messageHeaderColor.stylize("")
|
||||
msgType := api.Msg.Content.Type
|
||||
switch msgType {
|
||||
case "text", "attachment":
|
||||
var c = messageHeaderColor
|
||||
ret = colorText(outputFormat, c, noColor)
|
||||
ret = messageHeaderColor.stylize(formatString)
|
||||
tm := time.Unix(int64(api.Msg.SentAt), 0)
|
||||
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)
|
||||
var msg = formatMessageBody(api.Msg.Content.Text.Body)
|
||||
if msgType == "attachment" {
|
||||
msg = fmt.Sprintf("%s\n%s", api.Msg.Content.Attachment.Object.Title, colorText(fmt.Sprintf("[Attachment: %s]", api.Msg.Content.Attachment.Object.Filename), messageAttachmentColor, c))
|
||||
msg = messageBodyColor.stylize("$TITLE\n$FILE")
|
||||
attachment := api.Msg.Content.Attachment
|
||||
msg = msg.replaceString("$TITLE", attachment.Object.Title)
|
||||
msg = msg.replace("$FILE", messageAttachmentColor.stylize(fmt.Sprintf("[Attachment: %s]", attachment.Object.Filename)))
|
||||
}
|
||||
user := colorUsername(api.Msg.Sender.Username, c)
|
||||
device := colorText(api.Msg.Sender.DeviceName, messageSenderDeviceColor, c)
|
||||
msgID := colorText(fmt.Sprintf("%d", api.Msg.ID), messageIdColor, c)
|
||||
ts := colorText(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, "$DATE", colorText(tm.Format(dateFormat), messageTimeColor, c), 1)
|
||||
ret = strings.Replace(ret, "```", fmt.Sprintf("\n<code>\n"), -1)
|
||||
|
||||
user := colorUsername(api.Msg.Sender.Username)
|
||||
device := messageSenderDeviceColor.stylize(api.Msg.Sender.DeviceName)
|
||||
msgID := messageIDColor.stylize(fmt.Sprintf("%d", api.Msg.ID))
|
||||
date := messageTimeColor.stylize(tm.Format(dateFormat))
|
||||
msgTime := messageTimeColor.stylize(tm.Format(timeFormat))
|
||||
|
||||
channelName := messageIDColor.stylize(fmt.Sprintf("@%s#%s", api.Msg.Channel.Name, api.Msg.Channel.TopicName))
|
||||
ret = ret.replace("$MSG", msg)
|
||||
ret = ret.replace("$USER", user)
|
||||
ret = ret.replace("$DEVICE", device)
|
||||
ret = ret.replace("$ID", msgID)
|
||||
ret = ret.replace("$TIME", msgTime)
|
||||
ret = ret.replace("$DATE", date)
|
||||
ret = ret.replace("$TEAM", channelName)
|
||||
}
|
||||
return ret
|
||||
return ret.string()
|
||||
}
|
||||
func formatOutput(api keybase.ChatAPI) string {
|
||||
format := outputFormat
|
||||
if stream {
|
||||
format = outputStreamFormat
|
||||
}
|
||||
return formatMessage(api, format)
|
||||
}
|
||||
|
||||
// End formatting
|
||||
@ -410,9 +475,7 @@ func handleMessage(api keybase.ChatAPI) {
|
||||
}
|
||||
if api.Msg.Content.Type == "text" || api.Msg.Content.Type == "attachment" {
|
||||
go populateList()
|
||||
msgBody := api.Msg.Content.Text.Body
|
||||
msgSender := api.Msg.Sender.Username
|
||||
channelName := api.Msg.Channel.Name
|
||||
if !stream {
|
||||
if msgSender != k.Username {
|
||||
if api.Msg.Channel.MembersType == keybase.TEAM {
|
||||
@ -421,7 +484,7 @@ func handleMessage(api keybase.ChatAPI) {
|
||||
if m.Text == k.Username {
|
||||
// We are in a team
|
||||
if topicName != channel.TopicName {
|
||||
printToView("Feed", fmt.Sprintf("[ %s#%s ] %s: %s", channelName, topicName, msgSender, msgBody))
|
||||
printInfo(formatMessage(api, mentionFormat))
|
||||
fmt.Print("\a")
|
||||
}
|
||||
|
||||
@ -430,7 +493,7 @@ func handleMessage(api keybase.ChatAPI) {
|
||||
}
|
||||
} else {
|
||||
if msgSender != channel.Name {
|
||||
printToView("Feed", fmt.Sprintf("PM from @%s: %s", cleanChannelName(channelName), msgBody))
|
||||
printInfo(formatMessage(api, pmFormat))
|
||||
fmt.Print("\a")
|
||||
}
|
||||
|
||||
@ -446,10 +509,9 @@ func handleMessage(api keybase.ChatAPI) {
|
||||
}
|
||||
} else {
|
||||
if api.Msg.Channel.MembersType == keybase.TEAM {
|
||||
topicName := api.Msg.Channel.TopicName
|
||||
printToView("Chat", fmt.Sprintf("@%s#%s [%s]: %s", channelName, topicName, msgSender, msgBody))
|
||||
printToView("Chat", formatOutput(api))
|
||||
} else {
|
||||
printToView("Chat", fmt.Sprintf("PM @%s [%s]: %s", cleanChannelName(channelName), msgSender, msgBody))
|
||||
printToView("Chat", formatMessage(api, pmFormat))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -494,7 +556,7 @@ func handleInput(viewName string) error {
|
||||
} else if cmd[0] == "q" || cmd[0] == "quit" {
|
||||
return gocui.ErrQuit
|
||||
} else {
|
||||
printToView("Feed", fmt.Sprintf("Command '%s' not recognized", cmd[0]))
|
||||
printError(fmt.Sprintf("Command '%s' not recognized", cmd[0]))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@ -517,7 +579,7 @@ func sendChat(message string) {
|
||||
chat := k.NewChat(channel)
|
||||
_, err := chat.Send(message)
|
||||
if err != nil {
|
||||
printToView("Feed", fmt.Sprintf("There was an error %+v", err))
|
||||
printError(fmt.Sprintf("There was an error %+v", err))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -20,15 +20,17 @@ func init() {
|
||||
}
|
||||
|
||||
func tcmdShowReactions(m keybase.ChatAPI) {
|
||||
where := ""
|
||||
team := false
|
||||
user := colorUsername(m.Msg.Sender.Username)
|
||||
id := messageIDColor.stylize(fmt.Sprintf("%d", m.Msg.Content.Reaction.M))
|
||||
reaction := messageReactionColor.stylize(m.Msg.Content.Reaction.B)
|
||||
where := messageLinkKeybaseColor.stylize("a PM")
|
||||
if m.Msg.Channel.MembersType == keybase.TEAM {
|
||||
team = true
|
||||
where = fmt.Sprintf("in @%s#%s", m.Msg.Channel.Name, m.Msg.Channel.TopicName)
|
||||
where = formatChannel(m.Msg.Channel)
|
||||
} else {
|
||||
where = fmt.Sprintf("in a PM")
|
||||
}
|
||||
printToView("Feed", fmt.Sprintf("%s reacted to %d with %s %s", m.Msg.Sender.Username, m.Msg.Content.Reaction.M, m.Msg.Content.Reaction.B, where))
|
||||
printInfoF("$TEXT reacted to [$TEXT] with $TEXT in $TEXT", user, id, reaction, where)
|
||||
if channel.Name == m.Msg.Channel.Name {
|
||||
if team {
|
||||
if channel.TopicName == m.Msg.Channel.TopicName {
|
||||
|
||||
@ -3,22 +3,32 @@ 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)
|
||||
var colorless bool = false
|
||||
var channelsColor = basicStyle
|
||||
var channelUnreadColor = channelsColor.withForeground(green).withItalic()
|
||||
var channelsHeaderColor = channelsColor.withForeground(magenta).withBold()
|
||||
|
||||
var mentionColor = basicStyle.withForeground(green)
|
||||
var messageHeaderColor = basicStyle.withForeground(grey)
|
||||
var messageIDColor = basicStyle.withForeground(yellow)
|
||||
var messageTimeColor = basicStyle.withForeground(magenta)
|
||||
var messageSenderDefaultColor = basicStyle.withForeground(cyan)
|
||||
var messageSenderDeviceColor = messageSenderDefaultColor
|
||||
var messageBodyColor = basicStyle
|
||||
var messageAttachmentColor = basicStyle.withForeground(red)
|
||||
var messageLinkURLColor = basicStyle.withForeground(yellow)
|
||||
var messageLinkKeybaseColor = basicStyle.withForeground(yellow)
|
||||
var messageReactionColor = basicStyle.withForeground(magenta)
|
||||
var messageCodeColor = basicStyle.withBackground(grey).withForeground(cyan)
|
||||
|
||||
var feedColor = basicStyle.withForeground(grey)
|
||||
var errorColor = basicStyle.withForeground(red)
|
||||
|
||||
// BASH-like PS1 variable equivalent
|
||||
var outputFormat = "┌──[$USER@$DEVICE] [$ID] [$DATE - $TIME]\n└╼ $MSG"
|
||||
var outputStreamFormat = "┌──[$TEAM] [$USER@$DEVICE] [$ID] [$DATE - $TIME]\n└╼ $MSG"
|
||||
var mentionFormat = outputStreamFormat
|
||||
var pmFormat = "PM from $USER@$DEVICE: $MSG"
|
||||
|
||||
// 02 = Day, Jan = Month, 06 = Year
|
||||
var dateFormat = "02Jan06"
|
||||
|
||||
Reference in New Issue
Block a user