Browse Source

Revised some styling elements

- Colored block codes in a whole block
- Colored quotes
- Fixed a few bugs
pull/45/head
Casper Weiss Bang 5 years ago
parent
commit
1d95fea9f3
  1. 4
      cmdConfig.go
  2. 5
      cmdDownload.go
  3. 7
      cmdUploadFile.go
  4. 87
      colors.go
  5. 93
      defaultConfig.go
  6. 12
      go.mod
  7. 23
      go.sum
  8. 93
      kbtui.toml
  9. 63
      main.go
  10. 2
      types.go

4
cmdConfig.go

@ -31,7 +31,7 @@ func cmdConfig(cmd []string) { @@ -31,7 +31,7 @@ func cmdConfig(cmd []string) {
printError(err.Error())
return
}
printInfoF("Config file loaded: $TEXT", config.Colors.Message.Attachment.stylize(config.filepath))
printInfoF("Config file loaded: $TEXT", config.Colors.Feed.File.stylize(config.filepath))
return
}
case len(cmd) > 2:
@ -41,7 +41,7 @@ func cmdConfig(cmd []string) { @@ -41,7 +41,7 @@ func cmdConfig(cmd []string) {
printError(err.Error())
return
}
printInfoF("Config file loaded: $TEXT", config.Colors.Message.Attachment.stylize(config.filepath))
printInfoF("Config file loaded: $TEXT", config.Colors.Feed.File.stylize(config.filepath))
return
}
}

5
cmdDownload.go

@ -48,9 +48,10 @@ func cmdDownloadFile(cmd []string) { @@ -48,9 +48,10 @@ func cmdDownloadFile(cmd []string) {
_, err = chat.Download(messageID, fmt.Sprintf("%s/%s", config.Basics.DownloadPath, fileName))
channelName := config.Colors.Message.LinkKeybase.stylize(channel.Name)
fileNameStylizied := config.Colors.Feed.File.stylize(fileName)
if err != nil {
printErrorF(fmt.Sprintf("There was an error downloading %s from $TEXT", fileName), channelName)
printErrorF("There was an error downloading $TEXT from $TEXT", fileNameStylizied, channelName)
} else {
printInfoF(fmt.Sprintf("Downloaded %s from $TEXT", fileName), channelName)
printInfoF("Downloaded $TEXT from $TEXT", fileNameStylizied, channelName)
}
}

7
cmdUploadFile.go

@ -40,10 +40,11 @@ func cmdUploadFile(cmd []string) { @@ -40,10 +40,11 @@ func cmdUploadFile(cmd []string) {
}
chat := k.NewChat(channel)
_, err := chat.Upload(fileName, filePath)
channelName := config.Colors.Message.LinkKeybase.stylize(channel.Name).string()
channelName := config.Colors.Message.LinkKeybase.stylize(channel.Name)
fileNameStylized := config.Colors.Feed.File.stylize(filePath)
if err != nil {
printError(fmt.Sprintf("There was an error uploading %s to %s\n%+v", filePath, channelName, err))
printError(fmt.Sprintf("There was an error uploading %s to %s\n%+v", filePath, channel.Name, err))
} else {
printInfo(fmt.Sprintf("Uploaded %s to %s", filePath, channelName))
printInfoF("Uploaded $TEXT to $TEXT", fileNameStylized, channelName)
}
}

87
colors.go

@ -79,6 +79,7 @@ func (s Style) withBackground(color int) Style { @@ -79,6 +79,7 @@ func (s Style) withBackground(color int) Style {
s.Background = colorFromInt(color)
return s
}
func (s Style) withBold() Style {
s.Bold = true
return s
@ -107,30 +108,31 @@ func (s Style) toANSI() string { @@ -107,30 +108,31 @@ func (s Style) toANSI() string {
if config.Basics.Colorless {
return ""
}
output := "\x1b[0m\x1b[0"
styleSlice := []string{"0"}
if colorFromString(s.Foreground) != normal {
output += fmt.Sprintf(";%d", 30+colorFromString(s.Foreground))
styleSlice = append(styleSlice, fmt.Sprintf("%d", 30+colorFromString(s.Foreground)))
}
if colorFromString(s.Background) != normal {
output += fmt.Sprintf(";%d", 40+colorFromString(s.Background))
styleSlice = append(styleSlice, fmt.Sprintf("%d", 40+colorFromString(s.Background)))
}
if s.Bold {
output += ";1"
styleSlice = append(styleSlice, "1")
}
if s.Italic {
output += ";3"
styleSlice = append(styleSlice, "3")
}
if s.Underline {
output += ";4"
styleSlice = append(styleSlice, "4")
}
if s.Inverse {
output += ";7"
styleSlice = append(styleSlice, "7")
}
if s.Strikethrough {
output += ";9"
styleSlice = append(styleSlice, "9")
}
return output + "m"
return "\x1b[" + strings.Join(styleSlice, ";") + "m"
}
// End Colors
@ -142,6 +144,12 @@ type StyledString struct { @@ -142,6 +144,12 @@ type StyledString struct {
style Style
}
func (ss StyledString) withStyle(style Style) StyledString {
return StyledString{ss.message, style}
}
// TODO change StyledString to have styles at start-end indexes.
// TODO handle all formatting types
func (s Style) sprintf(base string, parts ...StyledString) StyledString {
text := s.stylize(removeFormatting(base))
@ -158,51 +166,58 @@ func (s Style) sprintf(base string, parts ...StyledString) StyledString { @@ -158,51 +166,58 @@ func (s Style) sprintf(base string, parts ...StyledString) StyledString {
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 (ss StyledString) stringFollowedByStyle(style Style) string {
return ss.style.toANSI() + ss.message + style.toANSI()
}
func (t StyledString) string() string {
return t.stringFollowedByStyle(basicStyle)
func (ss StyledString) string() string {
return ss.stringFollowedByStyle(basicStyle)
}
func (t StyledString) replace(match string, value StyledString) StyledString {
return t.replaceN(match, value, -1)
func (ss StyledString) replace(match string, value StyledString) StyledString {
return ss.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 (ss StyledString) replaceN(match string, value StyledString, n int) StyledString {
ss.message = strings.Replace(ss.message, match, value.stringFollowedByStyle(ss.style), n)
return ss
}
func (t StyledString) replaceString(match string, value string) StyledString {
t.message = strings.Replace(t.message, match, value, -1)
return t
func (ss StyledString) replaceString(match string, value string) StyledString {
ss.message = strings.Replace(ss.message, match, value, -1)
return ss
}
// Overrides current formatting
func (t StyledString) colorRegex(match string, style Style) StyledString {
re := regexp.MustCompile("(" + match + ")")
locations := re.FindAllStringIndex(t.message, -1)
func (ss StyledString) colorRegex(match string, style Style) StyledString {
return ss.regexReplaceFunc(match, func(subString string) string {
return style.stylize(removeFormatting(subString)).stringFollowedByStyle(ss.style)
})
}
// Replacer function takes the current match as input and should return how the match should be preseneted instead
func (ss StyledString) regexReplaceFunc(match string, replacer func(string) string) StyledString {
re := regexp.MustCompile(match)
locations := re.FindAllStringIndex(ss.message, -1)
var newMessage string
var prevIndex int
for _, loc := range locations {
cleanSubstring := style.stylize(removeFormatting(string(t.message[loc[0]:loc[1]])))
newMessage += t.message[prevIndex:loc[0]]
newMessage += cleanSubstring.stringFollowedByStyle(t.style)
newSubstring := replacer(ss.message[loc[0]:loc[1]])
newMessage += ss.message[prevIndex:loc[0]]
newMessage += newSubstring
prevIndex = loc[1]
}
// Append any string after the final match
newMessage += t.message[prevIndex:len(t.message)]
t.message = newMessage
return t
newMessage += ss.message[prevIndex:len(ss.message)]
ss.message = newMessage
return ss
}
// 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 (ss StyledString) append(other StyledString) StyledString {
ss.message = ss.message + other.stringFollowedByStyle(ss.style)
return ss
}
func (t StyledString) appendString(other string) StyledString {
t.message += other
return t
func (ss StyledString) appendString(other string) StyledString {
ss.message += other
return ss
}
// Begin Formatting

93
defaultConfig.go

@ -24,49 +24,54 @@ time_format = "15:04" @@ -24,49 +24,54 @@ time_format = "15:04"
[colors]
[colors.channels]
[colors.channels.basic]
foreground = "normal"
[colors.channels.header]
foreground = "magenta"
bold = true
[colors.channels.unread]
foreground = "green"
italic = true
[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"
[colors.message]
[colors.message.body]
foreground = "normal"
[colors.message.header]
foreground = "grey"
bold = true
[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.quote]
foreground = "green"
[colors.message.code]
foreground = "green"
background = "grey"
[colors.feed]
[colors.feed.basic]
foreground = "grey"
[colors.feed.error]
foreground = "red"
[colors.feed.file]
foreground = "yellow"
`

12
go.mod

@ -1,12 +0,0 @@ @@ -1,12 +0,0 @@
module github.com/Rudi9719/kbtui
go 1.12
require (
github.com/awesome-gocui/gocui v0.6.0
github.com/magefile/mage v1.9.0
github.com/mattn/go-runewidth v0.0.5 // indirect
github.com/pelletier/go-toml v1.6.0
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
samhofi.us/x/keybase v0.0.0-20191023034410-b00e56e8dd3c
)

23
go.sum

@ -1,23 +0,0 @@ @@ -1,23 +0,0 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/awesome-gocui/gocui v0.6.0 h1:hhDJiQC12tEsJNJ+iZBBVaSSLFYo9llFuYpQlL5JZVI=
github.com/awesome-gocui/gocui v0.6.0/go.mod h1:1QikxFaPhe2frKeKvEwZEIGia3haiOxOUXKinrv17mA=
github.com/awesome-gocui/termbox-go v0.0.0-20190427202837-c0aef3d18bcc h1:wGNpKcHU8Aadr9yOzsT3GEsFLS7HQu8HxQIomnekqf0=
github.com/awesome-gocui/termbox-go v0.0.0-20190427202837-c0aef3d18bcc/go.mod h1:tOy3o5Nf1bA17mnK4W41gD7PS3u4Cv0P0pqFcoWMy8s=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/magefile/mage v1.9.0 h1:t3AU2wNwehMCW97vuqQLtw6puppWXHO+O2MHo5a50XE=
github.com/magefile/mage v1.9.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.5 h1:jrGtp51JOKTWgvLFzfG6OtZOJcK2sEnzc/U+zw7TtbA=
github.com/mattn/go-runewidth v0.0.5/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/pelletier/go-toml v1.5.0 h1:5BakdOZdtKJ1FFk6QdL8iSGrMWsXgchNJcrnarjbmJQ=
github.com/pelletier/go-toml v1.5.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4=
github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
samhofi.us/x/keybase v0.0.0-20191023034410-b00e56e8dd3c h1:qIKOKqYnRCx+O2IOz3a/lplrD0p1e3n/VoGOdrTGrVo=
samhofi.us/x/keybase v0.0.0-20191023034410-b00e56e8dd3c/go.mod h1:fcva80IUFyWcHtV4bBSzgKg07K6Rvuvi3GtGCLNGkyE=

93
kbtui.toml

@ -21,48 +21,53 @@ time_format = "15:04" @@ -21,48 +21,53 @@ time_format = "15:04"
[colors]
[colors.channels]
[colors.channels.basic]
foreground = "normal"
[colors.channels.header]
foreground = "magenta"
bold = true
[colors.channels.unread]
foreground = "green"
italic = true
[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"
[colors.message]
[colors.message.body]
foreground = "normal"
[colors.message.header]
foreground = "grey"
bold = true
[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.quote]
foreground = "green"
[colors.message.code]
foreground = "green"
background = "grey"
[colors.feed]
[colors.feed.basic]
foreground = "grey"
[colors.feed.error]
foreground = "red"
[colors.feed.file]
foreground = "yellow"

63
main.go

@ -9,6 +9,7 @@ import ( @@ -9,6 +9,7 @@ import (
"github.com/awesome-gocui/gocui"
"samhofi.us/x/keybase"
"unicode/utf8"
)
var (
@ -333,6 +334,9 @@ func printErrorF(message string, parts ...StyledString) { @@ -333,6 +334,9 @@ func printErrorF(message string, parts ...StyledString) {
func printInfo(message string) {
printInfoF(message)
}
func printInfoStyledString(message StyledString) {
printInfoF("$TEXT", message)
}
// this removes formatting
func printInfoF(message string, parts ...StyledString) {
@ -343,12 +347,12 @@ func printToView(viewName string, message string) { @@ -343,12 +347,12 @@ func printToView(viewName string, message string) {
updatingView, err := g.View(viewName)
if err != nil {
return err
} else {
if config.Basics.UnicodeEmojis {
message = emojiUnicodeConvert(message)
}
fmt.Fprintf(updatingView, "%s\n", message)
}
if config.Basics.UnicodeEmojis {
message = emojiUnicodeConvert(message)
}
fmt.Fprintf(updatingView, "%s\n", message)
return nil
})
}
@ -459,21 +463,34 @@ func populateList() { @@ -459,21 +463,34 @@ func populateList() {
// Formatting
func formatMessageBody(body string) StyledString {
output := config.Colors.Message.Body.stylize(body)
message := config.Colors.Message.Body.stylize(body)
output = colorReplaceMentionMe(output)
output = output.colorRegex(`_[^_]*_`, config.Colors.Message.Body.withItalic())
output = output.colorRegex(`~[^~]*~`, config.Colors.Message.Body.withStrikethrough())
output = output.colorRegex(`@[\w_]*(\.[\w_]+)*`, config.Colors.Message.LinkKeybase)
message = colorReplaceMentionMe(message)
message = message.colorRegex(`_[^_]*_`, config.Colors.Message.Body.withItalic())
message = message.colorRegex(`~[^~]*~`, config.Colors.Message.Body.withStrikethrough())
message = message.colorRegex(`@[\w_]*([\.#][\w_]+)*`, config.Colors.Message.LinkKeybase)
// TODO change how bold, italic etc works, so it uses boldOn boldOff ([1m and [22m)
output = output.colorRegex(`\*[^\*]*\*`, config.Colors.Message.Body.withBold())
output = output.replaceString("```", "\n<code>\n")
// TODO make background color cover whole line
output = output.colorRegex("<code>(.*\n)*<code>", config.Colors.Message.Code)
output = output.colorRegex("`[^`]*`", config.Colors.Message.Code)
message = message.colorRegex(`\*[^\*]*\*`, config.Colors.Message.Body.withBold())
message = message.colorRegex(">.*$", config.Colors.Message.Quote)
message = message.regexReplaceFunc("```(.*\n)*```", func(match string) string {
maxWidth, _ := g.Size()
output := "\n"
match = strings.Replace(strings.Replace(match, "```", "<code>", -1), "\t", " ", -1)
lines := strings.Split(match, "\n")
for _, line := range lines {
maxLineLength := maxWidth/2 + maxWidth/3 - 2
spaces := maxLineLength - utf8.RuneCountInString(line)
for i := 1; spaces < 0; i++ {
spaces = i*maxLineLength - utf8.RuneCountInString(line)
}
output += line + strings.Repeat(" ", spaces) + "\n"
}
return config.Colors.Message.Code.stylize(output).stringFollowedByStyle(message.style)
})
message = message.colorRegex("`[^`]*`", config.Colors.Message.Code)
// mention URL
output = output.colorRegex(`(https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*))`, config.Colors.Message.LinkURL)
return output
message = message.colorRegex(`(https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*))`, config.Colors.Message.LinkURL)
return message
}
// TODO use this more
@ -497,7 +514,7 @@ func cleanChannelName(c string) string { @@ -497,7 +514,7 @@ func cleanChannelName(c string) string {
return strings.Replace(newChannelName, fmt.Sprintf(",%s", k.Username), "", 1)
}
func formatMessage(api keybase.ChatAPI, formatString string) string {
func formatMessage(api keybase.ChatAPI, formatString string) StyledString {
ret := config.Colors.Message.Header.stylize("")
msgType := api.Msg.Content.Type
switch msgType {
@ -527,14 +544,14 @@ func formatMessage(api keybase.ChatAPI, formatString string) string { @@ -527,14 +544,14 @@ func formatMessage(api keybase.ChatAPI, formatString string) string {
ret = ret.replace("$DATE", date)
ret = ret.replace("$TEAM", channelName)
}
return ret.string()
return ret
}
func formatOutput(api keybase.ChatAPI) string {
format := config.Formatting.OutputFormat
if stream {
format = config.Formatting.OutputStreamFormat
}
return formatMessage(api, format)
return formatMessage(api, format).string()
}
// End formatting
@ -560,7 +577,7 @@ func handleMessage(api keybase.ChatAPI) { @@ -560,7 +577,7 @@ func handleMessage(api keybase.ChatAPI) {
if m.Text == k.Username {
// We are in a team
if topicName != channel.TopicName {
printInfo(formatMessage(api, config.Formatting.OutputMentionFormat))
printInfoStyledString(formatMessage(api, config.Formatting.OutputMentionFormat))
fmt.Print("\a")
}
@ -569,7 +586,7 @@ func handleMessage(api keybase.ChatAPI) { @@ -569,7 +586,7 @@ func handleMessage(api keybase.ChatAPI) {
}
} else {
if msgSender != channel.Name {
printInfo(formatMessage(api, config.Formatting.PMFormat))
printInfoStyledString(formatMessage(api, config.Formatting.PMFormat))
fmt.Print("\a")
}
@ -587,7 +604,7 @@ func handleMessage(api keybase.ChatAPI) { @@ -587,7 +604,7 @@ func handleMessage(api keybase.ChatAPI) {
if api.Msg.Channel.MembersType == keybase.TEAM {
printToView("Chat", formatOutput(api))
} else {
printToView("Chat", formatMessage(api, config.Formatting.PMFormat))
printToView("Chat", formatMessage(api, config.Formatting.PMFormat).string())
}
}
} else {

2
types.go

@ -82,6 +82,7 @@ type Message struct { @@ -82,6 +82,7 @@ type Message struct {
LinkURL Style `toml:"link_url"`
LinkKeybase Style `toml:"link_keybase"`
Reaction Style `toml:"reaction"`
Quote Style `toml:"quote"`
Code Style `toml:"code"`
}
@ -89,4 +90,5 @@ type Message struct { @@ -89,4 +90,5 @@ type Message struct {
type Feed struct {
Basic Style `toml:"basic"`
Error Style `toml:"error"`
File Style `toml:"file"`
}

Loading…
Cancel
Save