1
0
mirror of https://github.com/Rudi9719/kbtui.git synced 2026-03-22 17:57:23 +00:00

6 Commits

Author SHA1 Message Date
709ff33ae5 Update README.md 2022-03-07 18:17:27 -05:00
c36b278484 Fix versions for gocui to work 2021-07-22 09:22:29 -04:00
a7ae3b37bb Convert to go module and update gocui 2021-06-01 17:28:33 -04:00
68ab6db1e4 Merge pull request #56 from Rudi9719/dev
Sort conversationSlice
2020-02-11 08:35:08 -05:00
97e055dd61 Sort conversationSlice 2020-01-28 12:43:19 -05:00
9b6bd7442b Merge pull request #55 from Rudi9719/dev
Dev to Master
2020-01-08 09:46:36 -05:00
5 changed files with 79 additions and 86 deletions

View File

@ -1,39 +1,2 @@
# kbtui # Announcement
Keybase TUI written in Go using [@dxb](https://keybase.io/dxb)'s Development on this branch of kbtui has been stopped and migrated to https://git.hugfreevikings.wtf/keybase/kbtui
Keybase [bot framework](https://godoc.org/samhofi.us/x/keybase).
It started as a joke, then a bash script, and now here it is!
For support or suggestions check out the [kbtui team](https://keybase.io/team/kbtui)
## Features
* Dark Mode (or rather mode based on Terminal Theme)
* Read and reply to messages
* Feed view to see mentions
* Stream view to see all incoming messages
* List view to show activity
* Chat view to interact with the current channel
* Marks unread messages in the List view
* Reactions to messages
* Auto #general teams when not given a channel
* Pretty format headers in List view from window size
* Message editing
* Twitter-style feed reading public messages
* Message replies
## Todo
* Track multiple conversations at once
### Building and Running
Easiest Way:
```
go get -u github.com/rudi9719/kbtui
```
Or you can do the following:
```
go get github.com/magefile/mage/mage
go run build.go {build, buildBeta... etc}
./kbtui
```
Mage is a requirement for building `kbtui` as it will automatically handle/manage imports as well as mage is used to generate the
file for emoji completion.

View File

@ -1,25 +0,0 @@
// +build !rm_basic_commands allcommands devcmd
package main
import (
"fmt"
)
func init() {
command := Command{
Cmd: []string{"dev"},
Description: "- Switch to dev channels",
Help: "",
Exec: cmdDev,
}
RegisterCommand(command)
}
func cmdDev(cmd []string) {
dev = !dev
printInfo(fmt.Sprintf("You have toggled the dev flag to %+v", dev))
clearView("Chat")
}

16
go.mod Normal file
View File

@ -0,0 +1,16 @@
module github.com/rudi9719/kbtui
go 1.16
require (
github.com/awesome-gocui/gocui v1.0.1-0.20210720125732-36a608772b4d
github.com/gdamore/tcell/v2 v2.4.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/magefile/mage v1.11.0
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/pelletier/go-toml v1.9.1
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
golang.org/x/text v0.3.6 // indirect
samhofi.us/x/keybase v1.0.0
)

46
go.sum Normal file
View File

@ -0,0 +1,46 @@
github.com/awesome-gocui/gocui v1.0.0 h1:1bf0DAr2JqWNxGFS8Kex4fM/khICjEnCi+a1+NfWy+w=
github.com/awesome-gocui/gocui v1.0.0/go.mod h1:UvP3dP6+UsTGl9IuqP36wzz6Lemo90wn5p3tJvZ2OqY=
github.com/awesome-gocui/gocui v1.0.1-0.20210720125732-36a608772b4d h1:5TGmGxIeTNcsvqqL1kbcPNP7RMG0wZtvPgmNmqB/UeY=
github.com/awesome-gocui/gocui v1.0.1-0.20210720125732-36a608772b4d/go.mod h1:UvP3dP6+UsTGl9IuqP36wzz6Lemo90wn5p3tJvZ2OqY=
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
github.com/gdamore/tcell/v2 v2.0.0/go.mod h1:vSVL/GV5mCSlPC6thFP5kfOFdM9MGZcalipmpTxTgQA=
github.com/gdamore/tcell/v2 v2.3.5 h1:fSiuoOf40N1w1otj2kQf4IlJ7rI/dcF3zVZL+GRmwuQ=
github.com/gdamore/tcell/v2 v2.3.5/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU=
github.com/gdamore/tcell/v2 v2.4.0 h1:W6dxJEmaxYvhICFoTY3WrLLEXsQ11SaFnKGVEXW57KM=
github.com/gdamore/tcell/v2 v2.4.0/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU=
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/magefile/mage v1.11.0 h1:C/55Ywp9BpgVVclD3lRnSYCwXTYxmSppIgLeDYlNuls=
github.com/magefile/mage v1.11.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/pelletier/go-toml v1.9.1 h1:a6qW1EVNZWH9WGI6CsYdD8WAylkoXBS5yv0XHlh17Tc=
github.com/pelletier/go-toml v1.9.1/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210601080250-7ecdf8ef093b h1:qh4f65QIVFjq9eBURLEYWqaEXmOyqdUyiBSgaXWccWk=
golang.org/x/sys v0.0.0-20210601080250-7ecdf8ef093b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210503060354-a79de5458b56 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w=
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
samhofi.us/x/keybase v1.0.0 h1:ht//EtYMS/hQeZCznA1ibQ515JCKaEkvTD/tarw/9k8=
samhofi.us/x/keybase v1.0.0/go.mod h1:fcva80IUFyWcHtV4bBSzgKg07K6Rvuvi3GtGCLNGkyE=

37
main.go
View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"log" "log"
"os" "os"
"sort"
"strings" "strings"
"time" "time"
@ -42,11 +43,6 @@ func main() {
defer g.Close() defer g.Close()
g.SetManagerFunc(layout) g.SetManagerFunc(layout)
RunCommand("config", "load") RunCommand("config", "load")
if dev {
channel.TopicType = "dev"
} else {
channel.TopicType = "chat"
}
go populateList() go populateList()
go updateChatWindow() go updateChatWindow()
if len(os.Args) > 1 { if len(os.Args) > 1 {
@ -58,7 +54,7 @@ func main() {
if err := initKeybindings(); err != nil { if err := initKeybindings(); err != nil {
fmt.Printf("%+v", err) fmt.Printf("%+v", err)
} }
if err := g.MainLoop(); err != nil && !gocui.IsQuit(err) { if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
fmt.Printf("%+v", err) fmt.Printf("%+v", err)
} }
go generateChannelTabCompletionSlice() go generateChannelTabCompletionSlice()
@ -68,7 +64,7 @@ func main() {
func layout(g *gocui.Gui) error { func layout(g *gocui.Gui) error {
maxX, maxY := g.Size() maxX, maxY := g.Size()
if editView, err := g.SetView("Edit", maxX/2-maxX/3+1, maxY/2, maxX-2, maxY/2+10, 0); err != nil { if editView, err := g.SetView("Edit", maxX/2-maxX/3+1, maxY/2, maxX-2, maxY/2+10, 0); err != nil {
if !gocui.IsUnknownView(err) { if err != gocui.ErrUnknownView {
return err return err
} }
editView.Editable = true editView.Editable = true
@ -76,7 +72,7 @@ func layout(g *gocui.Gui) error {
fmt.Fprintln(editView, "Edit window. Should disappear") fmt.Fprintln(editView, "Edit window. Should disappear")
} }
if feedView, err := g.SetView("Feed", maxX/2-maxX/3, 0, maxX-1, maxY/5, 0); err != nil { if feedView, err := g.SetView("Feed", maxX/2-maxX/3, 0, maxX-1, maxY/5, 0); err != nil {
if !gocui.IsUnknownView(err) { if err != gocui.ErrUnknownView {
return err return err
} }
feedView.Autoscroll = true feedView.Autoscroll = true
@ -85,7 +81,7 @@ func layout(g *gocui.Gui) error {
printInfo("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 chatView, err2 := g.SetView("Chat", maxX/2-maxX/3, maxY/5+1, maxX-1, maxY-5, 0); err2 != nil {
if !gocui.IsUnknownView(err2) { if err2 != gocui.ErrUnknownView {
return err2 return err2
} }
chatView.Autoscroll = true chatView.Autoscroll = true
@ -96,7 +92,7 @@ func layout(g *gocui.Gui) error {
RunCommand("help") RunCommand("help")
} }
if inputView, err3 := g.SetView("Input", maxX/2-maxX/3, maxY-4, maxX-1, maxY-1, 0); err3 != nil { if inputView, err3 := g.SetView("Input", maxX/2-maxX/3, maxY-4, maxX-1, maxY-1, 0); err3 != nil {
if !gocui.IsUnknownView(err3) { if err3 != gocui.ErrUnknownView {
return err3 return err3
} }
if _, err := g.SetCurrentView("Input"); err != nil { if _, err := g.SetCurrentView("Input"); err != nil {
@ -108,7 +104,7 @@ func layout(g *gocui.Gui) error {
g.Cursor = true g.Cursor = true
} }
if listView, err4 := g.SetView("List", 0, 0, maxX/2-maxX/3-1, maxY-1, 0); err4 != nil { if listView, err4 := g.SetView("List", 0, 0, maxX/2-maxX/3-1, maxY-1, 0); err4 != nil {
if !gocui.IsUnknownView(err4) { if err4 != gocui.ErrUnknownView {
return err4 return err4
} }
listView.Title = "Channels" listView.Title = "Channels"
@ -275,7 +271,7 @@ func popupView(viewName string) {
if err != nil { if err != nil {
return err return err
} }
updatingView.MoveCursor(0, 0, true) updatingView.MoveCursor(0, 0)
return nil return nil
@ -294,7 +290,7 @@ func moveCursorToEnd(viewName string) {
y := stringLen / maxX y := stringLen / maxX
inputView.SetCursor(0, 0) inputView.SetCursor(0, 0)
inputView.SetOrigin(0, 0) inputView.SetOrigin(0, 0)
inputView.MoveCursor(x, y, true) inputView.MoveCursor(x, y)
return nil return nil
}) })
@ -386,11 +382,6 @@ func populateChat() {
if channel.Name == testChan.Name { if channel.Name == testChan.Name {
channel = testChan channel = testChan
channel.TopicName = "general" channel.TopicName = "general"
if dev {
channel.TopicType = "dev"
} else {
channel.TopicType = "chat"
}
} }
} }
chat = k.NewChat(channel) chat = k.NewChat(channel)
@ -434,13 +425,16 @@ func populateList() {
log.Printf("%+v", err) log.Printf("%+v", err)
} else { } else {
clearView("List") clearView("List")
conversationSlice := testVar.Result.Conversations
sort.SliceStable(conversationSlice, func(i, j int) bool {
return conversationSlice[i].ActiveAt > conversationSlice[j].ActiveAt
})
var textBase = config.Colors.Channels.Basic.stylize("") var textBase = config.Colors.Channels.Basic.stylize("")
var recentPMs = textBase.append(config.Colors.Channels.Header.stylize("---[PMs]---\n")) var recentPMs = textBase.append(config.Colors.Channels.Header.stylize("---[PMs]---\n"))
var recentPMsCount = 0 var recentPMsCount = 0
var recentChannels = textBase.append(config.Colors.Channels.Header.stylize("---[Teams]---\n")) var recentChannels = textBase.append(config.Colors.Channels.Header.stylize("---[Teams]---\n"))
var recentChannelsCount = 0 var recentChannelsCount = 0
for _, s := range testVar.Result.Conversations { for _, s := range conversationSlice {
channels = append(channels, s.Channel) channels = append(channels, s.Channel)
if s.Channel.MembersType == keybase.TEAM { if s.Channel.MembersType == keybase.TEAM {
recentChannelsCount++ recentChannelsCount++
@ -632,8 +626,7 @@ func handleMessage(api keybase.ChatAPI) {
} }
} }
if api.Msg.Channel.MembersType == channel.MembersType && cleanChannelName(api.Msg.Channel.Name) == channel.Name { if api.Msg.Channel.MembersType == channel.MembersType && cleanChannelName(api.Msg.Channel.Name) == channel.Name {
if channel.MembersType == keybase.USER || channel.MembersType == keybase.TEAM && channel.TopicName == api.Msg.Channel.TopicName && if channel.MembersType == keybase.USER || channel.MembersType == keybase.TEAM && channel.TopicName == api.Msg.Channel.TopicName {
channel.TopicType == api.Msg.Channel.TopicType {
printToView("Chat", formatOutput(api).string()) printToView("Chat", formatOutput(api).string())
chat := k.NewChat(channel) chat := k.NewChat(channel)
lastMessage.ID = api.Msg.ID lastMessage.ID = api.Msg.ID