From f96e4a5f0d6b1c8b507623c7ddad7af95966a9d6 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Fri, 30 Dec 2022 14:16:34 +0530 Subject: [PATCH 01/70] Rewrite --- channels_tree.go | 18 +++++++++++++ config.go | 68 ++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 23 ++++++++++++++++ go.sum | 39 +++++++++++++++++++++++++++ guilds_tree.go | 45 +++++++++++++++++++++++++++++++ main.go | 70 ++++++++++++++++++++++++++++++++++++++++++++++++ message_input.go | 18 +++++++++++++ messages_text.go | 23 ++++++++++++++++ state.go | 53 ++++++++++++++++++++++++++++++++++++ 9 files changed, 357 insertions(+) create mode 100644 channels_tree.go create mode 100644 config.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 guilds_tree.go create mode 100644 main.go create mode 100644 message_input.go create mode 100644 messages_text.go create mode 100644 state.go diff --git a/channels_tree.go b/channels_tree.go new file mode 100644 index 0000000..38c3d2e --- /dev/null +++ b/channels_tree.go @@ -0,0 +1,18 @@ +package main + +import "github.com/rivo/tview" + +type ChannelsTree struct { + *tview.TreeView +} + +func newChannelsTree() *ChannelsTree { + ct := &ChannelsTree{ + TreeView: tview.NewTreeView(), + } + + ct.SetBorder(true) + ct.SetBorderPadding(cfg.BorderPadding()) + + return ct +} diff --git a/config.go b/config.go new file mode 100644 index 0000000..731750b --- /dev/null +++ b/config.go @@ -0,0 +1,68 @@ +package main + +import ( + "encoding/json" + "os" + "path/filepath" +) + +const name = "discordo" + +type ThemeConfig struct { + BorderPadding [4]int +} + +type Config struct { + Mouse bool + Theme ThemeConfig +} + +func (c *Config) BorderPadding() (int, int, int, int) { + pad := c.Theme.BorderPadding + return pad[0], pad[1], pad[2], pad[3] +} + +func newConfig() (*Config, error) { + path, err := os.UserConfigDir() + if err != nil { + return nil, err + } + + path = filepath.Join(path, name) + if err = os.MkdirAll(path, os.ModePerm); err != nil { + return nil, err + } + + c := Config{ + Mouse: true, + Theme: ThemeConfig{ + BorderPadding: [...]int{1, 1, 1, 1}, + }, + } + path = filepath.Join(path, "config.json") + if _, err = os.Stat(path); os.IsNotExist(err) { + f, err := os.Create(path) + if err != nil { + return nil, err + } + defer f.Close() + + e := json.NewEncoder(f) + e.SetIndent("", "\t") + if err = e.Encode(c); err != nil { + return nil, err + } + } else { + f, err := os.Open(path) + if err != nil { + return nil, err + } + defer f.Close() + + if err = json.NewDecoder(f).Decode(&c); err != nil { + return nil, err + } + } + + return &c, nil +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..8ec05de --- /dev/null +++ b/go.mod @@ -0,0 +1,23 @@ +module github.com/ayn2op/discordo + +go 1.19 + +require ( + github.com/diamondburned/arikawa/v3 v3.1.0 + github.com/rivo/tview v0.0.0-20221221172820-02e38ea9604c +) + +require ( + github.com/gdamore/encoding v1.0.0 // indirect + github.com/gdamore/tcell/v2 v2.5.3 // indirect + github.com/gorilla/schema v1.2.0 // indirect + github.com/gorilla/websocket v1.4.2 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/mattn/go-runewidth v0.0.13 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/rivo/uniseg v0.4.2 // indirect + golang.org/x/sys v0.0.0-20220318055525-2edf467146b5 // indirect + golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect + golang.org/x/text v0.3.7 // indirect + golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..cdfe7bd --- /dev/null +++ b/go.sum @@ -0,0 +1,39 @@ +github.com/diamondburned/arikawa/v3 v3.1.0 h1:M7ZyjoCM4o1+rzai2NMXjOSukSrPdP6OxV68WKvKZ6E= +github.com/diamondburned/arikawa/v3 v3.1.0/go.mod h1:5jBSNnp82Z/EhsKa6Wk9FsOqSxfVkNZDTDBPOj47LpY= +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.5.3 h1:b9XQrT6QGbgI7JvZOJXFNczOQeIYbo8BfeSMzt2sAV0= +github.com/gdamore/tcell/v2 v2.5.3/go.mod h1:wSkrPaXoiIWZqW/g7Px4xc79di6FTcpB8tvaKJ6uGBo= +github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc= +github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +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/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/rivo/tview v0.0.0-20221221172820-02e38ea9604c h1:Y4GSXEYKYAtguH10lmQmYb7hRkJ7U+m8GvnFHKU2jrk= +github.com/rivo/tview v0.0.0-20221221172820-02e38ea9604c/go.mod h1:lBUy/T5kyMudFzWUH/C2moN+NlU5qF505vzOyINXuUQ= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8= +github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211001092434-39dca1131b70/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220318055525-2edf467146b5 h1:saXMvIOKvRFwbOMicHXr0B1uwoxq9dGmLe5ExMES6c4= +golang.org/x/sys v0.0.0-20220318055525-2edf467146b5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +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.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/guilds_tree.go b/guilds_tree.go new file mode 100644 index 0000000..bc6e2f7 --- /dev/null +++ b/guilds_tree.go @@ -0,0 +1,45 @@ +package main + +import ( + "github.com/diamondburned/arikawa/v3/discord" + "github.com/rivo/tview" +) + +type GuildsTree struct { + *tview.TreeView +} + +func newGuildsTree() *GuildsTree { + gt := &GuildsTree{ + TreeView: tview.NewTreeView(), + } + + root := tview.NewTreeNode("") + gt.SetRoot(root) + gt.SetTopLevel(1) + gt.SetSelectedFunc(gt.onSelected) + + gt.SetBorder(true) + gt.SetBorderPadding(cfg.BorderPadding()) + + return gt +} + +func (gt *GuildsTree) newGuild(n *tview.TreeNode, gid discord.GuildID) error { + g, err := discordState.Cabinet.Guild(gid) + if err != nil { + return err + } + + gn := tview.NewTreeNode(g.Name) + gn.SetReference(g.ID) + n.AddChild(gn) + return nil +} + +func (gt *GuildsTree) onSelected(n *tview.TreeNode) { + ref := n.GetReference() + if ref == nil { + + } +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..f38fa5e --- /dev/null +++ b/main.go @@ -0,0 +1,70 @@ +package main + +import ( + "context" + "flag" + "log" + + "github.com/rivo/tview" +) + +var ( + token string + + cfg *Config + discordState *State + + app *tview.Application + flex *tview.Flex + guildsTree *GuildsTree + channelsTree *ChannelsTree + messagesText *MessagesText + messageInput *MessageInput +) + +func init() { + flag.StringVar(&token, "token", "", "The authentication token.") +} + +func main() { + flag.Parse() + + var err error + cfg, err = newConfig() + if err != nil { + log.Fatal(err) + } + + // Initialize UI + app = tview.NewApplication() + + guildsTree = newGuildsTree() + channelsTree = newChannelsTree() + messagesText = newMessagesText() + messageInput = newMessageInput() + + discordState = newState(token) + if err = discordState.Open(context.Background()); err != nil { + log.Fatal(err) + } + + left := tview.NewFlex() + left.SetDirection(tview.FlexRow) + left.AddItem(guildsTree, 0, 1, true) + left.AddItem(channelsTree, 0, 1, false) + + right := tview.NewFlex() + right.SetDirection(tview.FlexRow) + right.AddItem(messagesText, 0, 1, false) + right.AddItem(messageInput, 3, 1, false) + + flex = tview.NewFlex() + flex.AddItem(left, 0, 1, false) + flex.AddItem(right, 0, 4, false) + + app.EnableMouse(cfg.Mouse) + app.SetRoot(flex, true) + if err = app.Run(); err != nil { + log.Fatal(err) + } +} diff --git a/message_input.go b/message_input.go new file mode 100644 index 0000000..d4f497b --- /dev/null +++ b/message_input.go @@ -0,0 +1,18 @@ +package main + +import "github.com/rivo/tview" + +type MessageInput struct { + *tview.InputField +} + +func newMessageInput() *MessageInput { + mi := &MessageInput{ + InputField: tview.NewInputField(), + } + + mi.SetBorder(true) + mi.SetBorderPadding(cfg.BorderPadding()) + + return mi +} diff --git a/messages_text.go b/messages_text.go new file mode 100644 index 0000000..01b15d0 --- /dev/null +++ b/messages_text.go @@ -0,0 +1,23 @@ +package main + +import ( + "github.com/rivo/tview" +) + +type MessagesText struct { + *tview.TextView +} + +func newMessagesText() *MessagesText { + mt := &MessagesText{ + TextView: tview.NewTextView(), + } + + mt.SetDynamicColors(true) + mt.SetRegions(true) + + mt.SetBorder(true) + mt.SetBorderPadding(cfg.BorderPadding()) + + return mt +} diff --git a/state.go b/state.go new file mode 100644 index 0000000..e2966cb --- /dev/null +++ b/state.go @@ -0,0 +1,53 @@ +package main + +import ( + "log" + + "github.com/diamondburned/arikawa/v3/gateway" + "github.com/diamondburned/arikawa/v3/state" + "github.com/rivo/tview" +) + +type State struct { + *state.State +} + +func newState(token string) *State { + s := &State{ + State: state.New(token), + } + + s.AddHandler(s.onReady) + + return s +} + +func (s *State) onReady(r *gateway.ReadyEvent) { + root := guildsTree.GetRoot() + + dmNode := tview.NewTreeNode("Direct Messages") + root.AddChild(dmNode) + + for _, gf := range r.UserSettings.GuildFolders { + /// If the ID of the guild folder is zero, the guild folder only contains single guild. + if gf.ID == 0 { + if err := guildsTree.newGuild(root, gf.GuildIDs[0]); err != nil { + log.Println(err) + continue + } + } else { + gfNode := tview.NewTreeNode("Folder") + root.AddChild(gfNode) + + for _, gid := range gf.GuildIDs { + if err := guildsTree.newGuild(gfNode, gid); err != nil { + log.Println(err) + continue + } + } + } + } + + guildsTree.SetCurrentNode(root) + app.SetFocus(guildsTree) +} From 7111df5c82b9fd591c254c77652368624b0b0797 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Fri, 30 Dec 2022 20:05:26 +0530 Subject: [PATCH 02/70] Rewrite --- channels_tree.go | 18 -------- config.go | 19 +++++---- go.mod | 16 +++---- go.sum | 27 +++++++----- guilds_tree.go | 109 ++++++++++++++++++++++++++++++++++++++++++++--- main.go | 9 +--- messages_text.go | 22 ++++++++++ out.log | 3 ++ state.go | 12 +++--- 9 files changed, 169 insertions(+), 66 deletions(-) delete mode 100644 channels_tree.go create mode 100644 out.log diff --git a/channels_tree.go b/channels_tree.go deleted file mode 100644 index 38c3d2e..0000000 --- a/channels_tree.go +++ /dev/null @@ -1,18 +0,0 @@ -package main - -import "github.com/rivo/tview" - -type ChannelsTree struct { - *tview.TreeView -} - -func newChannelsTree() *ChannelsTree { - ct := &ChannelsTree{ - TreeView: tview.NewTreeView(), - } - - ct.SetBorder(true) - ct.SetBorderPadding(cfg.BorderPadding()) - - return ct -} diff --git a/config.go b/config.go index 731750b..a8545a4 100644 --- a/config.go +++ b/config.go @@ -13,13 +13,9 @@ type ThemeConfig struct { } type Config struct { - Mouse bool - Theme ThemeConfig -} - -func (c *Config) BorderPadding() (int, int, int, int) { - pad := c.Theme.BorderPadding - return pad[0], pad[1], pad[2], pad[3] + Mouse bool + MessagesLimit uint + Theme ThemeConfig } func newConfig() (*Config, error) { @@ -34,7 +30,9 @@ func newConfig() (*Config, error) { } c := Config{ - Mouse: true, + Mouse: true, + MessagesLimit: 50, + Theme: ThemeConfig{ BorderPadding: [...]int{1, 1, 1, 1}, }, @@ -66,3 +64,8 @@ func newConfig() (*Config, error) { return &c, nil } + +func (c *Config) BorderPadding() (int, int, int, int) { + pad := c.Theme.BorderPadding + return pad[0], pad[1], pad[2], pad[3] +} diff --git a/go.mod b/go.mod index 8ec05de..7c986c3 100644 --- a/go.mod +++ b/go.mod @@ -4,20 +4,20 @@ go 1.19 require ( github.com/diamondburned/arikawa/v3 v3.1.0 - github.com/rivo/tview v0.0.0-20221221172820-02e38ea9604c + github.com/rivo/tview v0.0.0-20221229180733-b86a50a5126c ) require ( github.com/gdamore/encoding v1.0.0 // indirect github.com/gdamore/tcell/v2 v2.5.3 // indirect github.com/gorilla/schema v1.2.0 // indirect - github.com/gorilla/websocket v1.4.2 // indirect + github.com/gorilla/websocket v1.5.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect - github.com/mattn/go-runewidth v0.0.13 // indirect + github.com/mattn/go-runewidth v0.0.14 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/rivo/uniseg v0.4.2 // indirect - golang.org/x/sys v0.0.0-20220318055525-2edf467146b5 // indirect - golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect - golang.org/x/text v0.3.7 // indirect - golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect + github.com/rivo/uniseg v0.4.3 // indirect + golang.org/x/sys v0.3.0 // indirect + golang.org/x/term v0.3.0 // indirect + golang.org/x/text v0.5.0 // indirect + golang.org/x/time v0.3.0 // indirect ) diff --git a/go.sum b/go.sum index cdfe7bd..6085ebd 100644 --- a/go.sum +++ b/go.sum @@ -6,34 +6,39 @@ github.com/gdamore/tcell/v2 v2.5.3 h1:b9XQrT6QGbgI7JvZOJXFNczOQeIYbo8BfeSMzt2sAV github.com/gdamore/tcell/v2 v2.5.3/go.mod h1:wSkrPaXoiIWZqW/g7Px4xc79di6FTcpB8tvaKJ6uGBo= github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc= github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= -github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 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/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= +github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/rivo/tview v0.0.0-20221221172820-02e38ea9604c h1:Y4GSXEYKYAtguH10lmQmYb7hRkJ7U+m8GvnFHKU2jrk= -github.com/rivo/tview v0.0.0-20221221172820-02e38ea9604c/go.mod h1:lBUy/T5kyMudFzWUH/C2moN+NlU5qF505vzOyINXuUQ= +github.com/rivo/tview v0.0.0-20221229180733-b86a50a5126c h1:Xa0IDAwI/b4D3AQwFOhvOeYB/H0N8Bhhe3XJWSa2vjg= +github.com/rivo/tview v0.0.0-20221229180733-b86a50a5126c/go.mod h1:lBUy/T5kyMudFzWUH/C2moN+NlU5qF505vzOyINXuUQ= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8= -github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw= +github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211001092434-39dca1131b70/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220318055525-2edf467146b5 h1:saXMvIOKvRFwbOMicHXr0B1uwoxq9dGmLe5ExMES6c4= golang.org/x/sys v0.0.0-20220318055525-2edf467146b5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= -golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= 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.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= +golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/guilds_tree.go b/guilds_tree.go index bc6e2f7..6dc2ca1 100644 --- a/guilds_tree.go +++ b/guilds_tree.go @@ -1,31 +1,37 @@ package main import ( + "log" + "github.com/diamondburned/arikawa/v3/discord" "github.com/rivo/tview" ) type GuildsTree struct { *tview.TreeView + + root *tview.TreeNode } func newGuildsTree() *GuildsTree { gt := &GuildsTree{ TreeView: tview.NewTreeView(), + + root: tview.NewTreeNode(""), } - root := tview.NewTreeNode("") - gt.SetRoot(root) + gt.SetRoot(gt.root) gt.SetTopLevel(1) gt.SetSelectedFunc(gt.onSelected) + gt.SetTitle("Guilds") gt.SetBorder(true) gt.SetBorderPadding(cfg.BorderPadding()) return gt } -func (gt *GuildsTree) newGuild(n *tview.TreeNode, gid discord.GuildID) error { +func (gt *GuildsTree) newGuildFromID(n *tview.TreeNode, gid discord.GuildID) error { g, err := discordState.Cabinet.Guild(gid) if err != nil { return err @@ -37,9 +43,100 @@ func (gt *GuildsTree) newGuild(n *tview.TreeNode, gid discord.GuildID) error { return nil } -func (gt *GuildsTree) onSelected(n *tview.TreeNode) { - ref := n.GetReference() - if ref == nil { +func (gt *GuildsTree) newChannel(n *tview.TreeNode, c discord.Channel) { + cn := tview.NewTreeNode(gt.channelToString(c)) + cn.SetReference(c.ID) + n.AddChild(cn) +} +func (gt *GuildsTree) channelToString(c discord.Channel) string { + switch c.Type { + case discord.GuildText: + return "#" + c.Name + case discord.GuildVoice: + return "v-" + c.Name + case discord.GuildNews: + return "n-" + c.Name + case discord.GuildStore: + return "s-" + c.Name + default: + return c.Name + } +} + +func (gt *GuildsTree) onSelected(n *tview.TreeNode) { + if len(n.GetChildren()) != 0 { + n.SetExpanded(!n.IsExpanded()) + } + + switch ref := n.GetReference().(type) { + case discord.GuildID: + cs, err := discordState.Cabinet.Channels(ref) + if err != nil { + log.Println(err) + return + } + + // Orphan (top-level) channels + for _, c := range cs { + if c.Type != discord.GuildCategory && !c.ParentID.IsValid() { + gt.newChannel(n, c) + } + } + + // Category channels + CATEGORY: + for _, c := range cs { + if c.Type == discord.GuildCategory { + for _, nestedChannel := range cs { + if nestedChannel.ParentID == c.ID { + gt.newChannel(n, c) + continue CATEGORY + } + } + + gt.newChannel(n, c) + } + } + + // Children (category-bound) channels + for _, c := range cs { + if c.ParentID.IsValid() { + var parent *tview.TreeNode + n.Walk(func(node, _ *tview.TreeNode) bool { + if node.GetReference() == c.ParentID { + parent = node + return false + } + + return true + }) + + if parent != nil { + gt.newChannel(parent, c) + } + } + } + case discord.ChannelID: + messagesText.Clear() + + c, err := discordState.Cabinet.Channel(ref) + if err != nil { + log.Println(err) + return + } + + ms, err := discordState.Messages(ref, cfg.MessagesLimit) + if err != nil { + log.Println(err) + return + } + + for _, m := range ms { + messagesText.newMessage(&m) + } + + messagesText.SetTitle(gt.channelToString(*c)) + app.SetFocus(messagesText) } } diff --git a/main.go b/main.go index f38fa5e..ea85325 100644 --- a/main.go +++ b/main.go @@ -17,7 +17,6 @@ var ( app *tview.Application flex *tview.Flex guildsTree *GuildsTree - channelsTree *ChannelsTree messagesText *MessagesText messageInput *MessageInput ) @@ -39,7 +38,6 @@ func main() { app = tview.NewApplication() guildsTree = newGuildsTree() - channelsTree = newChannelsTree() messagesText = newMessagesText() messageInput = newMessageInput() @@ -48,18 +46,13 @@ func main() { log.Fatal(err) } - left := tview.NewFlex() - left.SetDirection(tview.FlexRow) - left.AddItem(guildsTree, 0, 1, true) - left.AddItem(channelsTree, 0, 1, false) - right := tview.NewFlex() right.SetDirection(tview.FlexRow) right.AddItem(messagesText, 0, 1, false) right.AddItem(messageInput, 3, 1, false) flex = tview.NewFlex() - flex.AddItem(left, 0, 1, false) + flex.AddItem(guildsTree, 0, 1, false) flex.AddItem(right, 0, 4, false) app.EnableMouse(cfg.Mouse) diff --git a/messages_text.go b/messages_text.go index 01b15d0..e2299b6 100644 --- a/messages_text.go +++ b/messages_text.go @@ -1,11 +1,17 @@ package main import ( + "fmt" + "strings" + + "github.com/diamondburned/arikawa/v3/discord" "github.com/rivo/tview" ) type MessagesText struct { *tview.TextView + + builder strings.Builder } func newMessagesText() *MessagesText { @@ -21,3 +27,19 @@ func newMessagesText() *MessagesText { return mt } + +func (mt *MessagesText) newMessage(m *discord.Message) { + switch m.Type { + case discord.DefaultMessage: + { + mt.builder.WriteString("[blue::b]") + mt.builder.WriteString(m.Author.Username) + mt.builder.WriteString("[-:-:-]") + } + + mt.builder.WriteByte('\n') + mt.builder.WriteByte('\n') + } + + fmt.Fprintln(mt, mt.builder.String()) +} diff --git a/out.log b/out.log new file mode 100644 index 0000000..c3a53e5 --- /dev/null +++ b/out.log @@ -0,0 +1,3 @@ +2022/12/30 20:03:24 Discord 403 error: Missing Access +2022/12/30 20:03:44 Discord 403 error: Missing Access +2022/12/30 20:03:58 Discord 403 error: Missing Access diff --git a/state.go b/state.go index e2966cb..bc9fe73 100644 --- a/state.go +++ b/state.go @@ -23,24 +23,22 @@ func newState(token string) *State { } func (s *State) onReady(r *gateway.ReadyEvent) { - root := guildsTree.GetRoot() - dmNode := tview.NewTreeNode("Direct Messages") - root.AddChild(dmNode) + guildsTree.root.AddChild(dmNode) for _, gf := range r.UserSettings.GuildFolders { /// If the ID of the guild folder is zero, the guild folder only contains single guild. if gf.ID == 0 { - if err := guildsTree.newGuild(root, gf.GuildIDs[0]); err != nil { + if err := guildsTree.newGuildFromID(guildsTree.root, gf.GuildIDs[0]); err != nil { log.Println(err) continue } } else { gfNode := tview.NewTreeNode("Folder") - root.AddChild(gfNode) + guildsTree.root.AddChild(gfNode) for _, gid := range gf.GuildIDs { - if err := guildsTree.newGuild(gfNode, gid); err != nil { + if err := guildsTree.newGuildFromID(gfNode, gid); err != nil { log.Println(err) continue } @@ -48,6 +46,6 @@ func (s *State) onReady(r *gateway.ReadyEvent) { } } - guildsTree.SetCurrentNode(root) + guildsTree.SetCurrentNode(guildsTree.root) app.SetFocus(guildsTree) } From 54d0cd9b128c9544d3d3d418cc08e8f94598baef Mon Sep 17 00:00:00 2001 From: ayn2op Date: Fri, 30 Dec 2022 20:05:44 +0530 Subject: [PATCH 03/70] Remove out.log --- out.log | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 out.log diff --git a/out.log b/out.log deleted file mode 100644 index c3a53e5..0000000 --- a/out.log +++ /dev/null @@ -1,3 +0,0 @@ -2022/12/30 20:03:24 Discord 403 error: Missing Access -2022/12/30 20:03:44 Discord 403 error: Missing Access -2022/12/30 20:03:58 Discord 403 error: Missing Access From 456ce6739cd467fd01383fd37af472b62b792bc6 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sat, 31 Dec 2022 00:46:35 +0530 Subject: [PATCH 04/70] Rewrite --- config.go | 4 ++++ guilds_tree.go | 6 +++++- message_input.go | 4 +++- messages_text.go | 35 ++++++++++++++++++++++++----------- 4 files changed, 36 insertions(+), 13 deletions(-) diff --git a/config.go b/config.go index a8545a4..2dc0120 100644 --- a/config.go +++ b/config.go @@ -10,6 +10,7 @@ const name = "discordo" type ThemeConfig struct { BorderPadding [4]int + MessageFormat string } type Config struct { @@ -35,6 +36,9 @@ func newConfig() (*Config, error) { Theme: ThemeConfig{ BorderPadding: [...]int{1, 1, 1, 1}, + MessageFormat: `{{.Author.Username}} + {{.Content}} + `, }, } path = filepath.Join(path, "config.json") diff --git a/guilds_tree.go b/guilds_tree.go index 6dc2ca1..1e49349 100644 --- a/guilds_tree.go +++ b/guilds_tree.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "log" "github.com/diamondburned/arikawa/v3/discord" @@ -133,7 +134,10 @@ func (gt *GuildsTree) onSelected(n *tview.TreeNode) { } for _, m := range ms { - messagesText.newMessage(&m) + if messagesText.newMessage(&m); err != nil { + fmt.Println(err) + continue + } } messagesText.SetTitle(gt.channelToString(*c)) diff --git a/message_input.go b/message_input.go index d4f497b..8d33d35 100644 --- a/message_input.go +++ b/message_input.go @@ -1,6 +1,8 @@ package main -import "github.com/rivo/tview" +import ( + "github.com/rivo/tview" +) type MessageInput struct { *tview.InputField diff --git a/messages_text.go b/messages_text.go index e2299b6..c92da19 100644 --- a/messages_text.go +++ b/messages_text.go @@ -2,16 +2,21 @@ package main import ( "fmt" - "strings" + "sync" + "text/template" "github.com/diamondburned/arikawa/v3/discord" "github.com/rivo/tview" ) +var p = sync.Pool{ + New: func() any { + return new(template.Template) + }, +} + type MessagesText struct { *tview.TextView - - builder strings.Builder } func newMessagesText() *MessagesText { @@ -28,18 +33,26 @@ func newMessagesText() *MessagesText { return mt } -func (mt *MessagesText) newMessage(m *discord.Message) { +func (mt *MessagesText) newMessage(m *discord.Message) error { switch m.Type { case discord.DefaultMessage: - { - mt.builder.WriteString("[blue::b]") - mt.builder.WriteString(m.Author.Username) - mt.builder.WriteString("[-:-:-]") + // Region tags are square brackets that contain a region ID in double quotes + // https://pkg.go.dev/github.com/rivo/tview#hdr-Regions_and_Highlights + fmt.Fprintf(mt, `["%s"]`, m.ID) + + if m.ReferencedMessage != nil { + fmt.Fprintf(mt, "[blue::bd]%s[-:-:-] [::-]", m.ReferencedMessage.Author.Username) + fmt.Fprint(mt, m.ReferencedMessage.Content) + fmt.Fprintln(mt) } - mt.builder.WriteByte('\n') - mt.builder.WriteByte('\n') + fmt.Fprintf(mt, "[blue::b]%s[-:-:-] ", m.Author.Username) + fmt.Fprint(mt, m.Content) + // Tags with no region ID ([""]) don't start new regions. They can therefore be used to mark the end of a region. + fmt.Fprint(mt, `[""]`) + + fmt.Fprintln(mt) } - fmt.Fprintln(mt, mt.builder.String()) + return nil } From 07d431a219224a1b57d04317c0acc71ae0764b6a Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 1 Jan 2023 13:30:10 +0530 Subject: [PATCH 05/70] rewrite --- config.go | 25 ++++++++++++++---- go.mod | 2 +- guilds_tree.go | 13 ++++++--- messages_text.go | 68 ++++++++++++++++++++++++++++++++++-------------- 4 files changed, 79 insertions(+), 29 deletions(-) diff --git a/config.go b/config.go index 2dc0120..92d7e68 100644 --- a/config.go +++ b/config.go @@ -10,13 +10,27 @@ const name = "discordo" type ThemeConfig struct { BorderPadding [4]int - MessageFormat string +} + +type GuildsTreeKeysConfig struct { + Graphics bool +} + +type MessagesTextKeysConfig struct { + SelectPreviousMessage string +} + +type KeysConfig struct { + GuildsTree GuildsTreeKeysConfig + MessagesText MessagesTextKeysConfig } type Config struct { Mouse bool MessagesLimit uint - Theme ThemeConfig + + Theme ThemeConfig + Keys KeysConfig } func newConfig() (*Config, error) { @@ -36,9 +50,10 @@ func newConfig() (*Config, error) { Theme: ThemeConfig{ BorderPadding: [...]int{1, 1, 1, 1}, - MessageFormat: `{{.Author.Username}} - {{.Content}} - `, + }, + Keys: KeysConfig{ + GuildsTree: GuildsTreeKeysConfig{Graphics: true}, + MessagesText: MessagesTextKeysConfig{SelectPreviousMessage: "Up"}, }, } path = filepath.Join(path, "config.json") diff --git a/go.mod b/go.mod index 7c986c3..f7373dd 100644 --- a/go.mod +++ b/go.mod @@ -4,12 +4,12 @@ go 1.19 require ( github.com/diamondburned/arikawa/v3 v3.1.0 + github.com/gdamore/tcell/v2 v2.5.3 github.com/rivo/tview v0.0.0-20221229180733-b86a50a5126c ) require ( github.com/gdamore/encoding v1.0.0 // indirect - github.com/gdamore/tcell/v2 v2.5.3 // indirect github.com/gorilla/schema v1.2.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect diff --git a/guilds_tree.go b/guilds_tree.go index 1e49349..ad67bd2 100644 --- a/guilds_tree.go +++ b/guilds_tree.go @@ -3,6 +3,7 @@ package main import ( "fmt" "log" + "sort" "github.com/diamondburned/arikawa/v3/discord" "github.com/rivo/tview" @@ -21,6 +22,7 @@ func newGuildsTree() *GuildsTree { root: tview.NewTreeNode(""), } + gt.SetGraphics(cfg.Keys.GuildsTree.Graphics) gt.SetRoot(gt.root) gt.SetTopLevel(1) gt.SetSelectedFunc(gt.onSelected) @@ -68,6 +70,7 @@ func (gt *GuildsTree) channelToString(c discord.Channel) string { func (gt *GuildsTree) onSelected(n *tview.TreeNode) { if len(n.GetChildren()) != 0 { n.SetExpanded(!n.IsExpanded()) + return } switch ref := n.GetReference().(type) { @@ -78,6 +81,10 @@ func (gt *GuildsTree) onSelected(n *tview.TreeNode) { return } + sort.Slice(cs, func(i, j int) bool { + return cs[i].Position < cs[j].Position + }) + // Orphan (top-level) channels for _, c := range cs { if c.Type != discord.GuildCategory && !c.ParentID.IsValid() { @@ -102,7 +109,7 @@ func (gt *GuildsTree) onSelected(n *tview.TreeNode) { // Children (category-bound) channels for _, c := range cs { - if c.ParentID.IsValid() { + if c.Type != discord.GuildCategory && c.ParentID.IsValid() { var parent *tview.TreeNode n.Walk(func(node, _ *tview.TreeNode) bool { if node.GetReference() == c.ParentID { @@ -133,8 +140,8 @@ func (gt *GuildsTree) onSelected(n *tview.TreeNode) { return } - for _, m := range ms { - if messagesText.newMessage(&m); err != nil { + for i := len(ms) - 1; i >= 0; i-- { + if messagesText.newMessage(&ms[i]); err != nil { fmt.Println(err) continue } diff --git a/messages_text.go b/messages_text.go index c92da19..be5eb83 100644 --- a/messages_text.go +++ b/messages_text.go @@ -1,22 +1,17 @@ package main import ( - "fmt" - "sync" - "text/template" + "bytes" + "time" "github.com/diamondburned/arikawa/v3/discord" "github.com/rivo/tview" ) -var p = sync.Pool{ - New: func() any { - return new(template.Template) - }, -} - type MessagesText struct { *tview.TextView + + buffer bytes.Buffer } func newMessagesText() *MessagesText { @@ -26,7 +21,9 @@ func newMessagesText() *MessagesText { mt.SetDynamicColors(true) mt.SetRegions(true) + mt.SetWordWrap(true) + mt.SetTitle("Messages") mt.SetBorder(true) mt.SetBorderPadding(cfg.BorderPadding()) @@ -35,24 +32,55 @@ func newMessagesText() *MessagesText { func (mt *MessagesText) newMessage(m *discord.Message) error { switch m.Type { - case discord.DefaultMessage: + case discord.DefaultMessage, discord.InlinedReplyMessage: // Region tags are square brackets that contain a region ID in double quotes // https://pkg.go.dev/github.com/rivo/tview#hdr-Regions_and_Highlights - fmt.Fprintf(mt, `["%s"]`, m.ID) + mt.buffer.WriteString(`["`) + mt.buffer.WriteString(m.ID.String()) + mt.buffer.WriteString(`"]`) if m.ReferencedMessage != nil { - fmt.Fprintf(mt, "[blue::bd]%s[-:-:-] [::-]", m.ReferencedMessage.Author.Username) - fmt.Fprint(mt, m.ReferencedMessage.Content) - fmt.Fprintln(mt) + mt.buffer.WriteString("> [::d]") + + // Author + mt.newAuthor(m.ReferencedMessage) + // Content + mt.newContent(m.ReferencedMessage) + + mt.buffer.WriteString("[::-]") + mt.buffer.WriteByte('\n') } - fmt.Fprintf(mt, "[blue::b]%s[-:-:-] ", m.Author.Username) - fmt.Fprint(mt, m.Content) - // Tags with no region ID ([""]) don't start new regions. They can therefore be used to mark the end of a region. - fmt.Fprint(mt, `[""]`) + // Author + mt.newAuthor(m) + // Timestamps + mt.newTimestamp(m) + // Content + mt.buffer.WriteByte('\n') + mt.newContent(m) - fmt.Fprintln(mt) + // Tags with no region ID ([""]) don't start new regions. They can therefore be used to mark the end of a region. + mt.buffer.WriteString(`[""]`) } - return nil + mt.buffer.WriteString("\n\n") + + _, err := mt.buffer.WriteTo(mt) + return err +} + +func (mt *MessagesText) newAuthor(m *discord.Message) { + mt.buffer.WriteString("[blue]") + mt.buffer.WriteString(m.Author.Username) + mt.buffer.WriteString("[-] ") +} + +func (mt *MessagesText) newTimestamp(m *discord.Message) { + mt.buffer.WriteString("[::d]") + mt.buffer.WriteString(m.Timestamp.Format(time.Kitchen)) + mt.buffer.WriteString("[-:-:-] ") +} + +func (mt *MessagesText) newContent(m *discord.Message) { + mt.buffer.WriteString(m.Content) } From ae058e25c2a4582499fd22ef9ff4ba60aaca3c9d Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 1 Jan 2023 13:44:36 +0530 Subject: [PATCH 06/70] Add more Theme configuration --- config.go | 40 +++++++++++++++++++++++++++++++++------- guilds_tree.go | 5 ++--- message_input.go | 2 +- messages_text.go | 3 +-- 4 files changed, 37 insertions(+), 13 deletions(-) diff --git a/config.go b/config.go index 92d7e68..b0f004b 100644 --- a/config.go +++ b/config.go @@ -8,20 +8,33 @@ import ( const name = "discordo" -type ThemeConfig struct { - BorderPadding [4]int +type GuildsTreeThemeConfig struct { + Border bool + Graphics bool } -type GuildsTreeKeysConfig struct { - Graphics bool +type MessagesTextThemeConfig struct { + Border bool +} + +type MessageInputThemeConfig struct { + Border bool +} + +type ThemeConfig struct { + BorderPadding [4]int + + GuildsTree GuildsTreeThemeConfig + MessagesText MessagesTextThemeConfig + MessageInput MessageInputThemeConfig } type MessagesTextKeysConfig struct { SelectPreviousMessage string + SelectNextMessage string } type KeysConfig struct { - GuildsTree GuildsTreeKeysConfig MessagesText MessagesTextKeysConfig } @@ -50,10 +63,23 @@ func newConfig() (*Config, error) { Theme: ThemeConfig{ BorderPadding: [...]int{1, 1, 1, 1}, + + GuildsTree: GuildsTreeThemeConfig{ + Border: true, + Graphics: true, + }, + MessagesText: MessagesTextThemeConfig{ + Border: true, + }, + MessageInput: MessageInputThemeConfig{ + Border: true, + }, }, Keys: KeysConfig{ - GuildsTree: GuildsTreeKeysConfig{Graphics: true}, - MessagesText: MessagesTextKeysConfig{SelectPreviousMessage: "Up"}, + MessagesText: MessagesTextKeysConfig{ + SelectPreviousMessage: "Up", + SelectNextMessage: "Down", + }, }, } path = filepath.Join(path, "config.json") diff --git a/guilds_tree.go b/guilds_tree.go index ad67bd2..df23d1a 100644 --- a/guilds_tree.go +++ b/guilds_tree.go @@ -22,13 +22,12 @@ func newGuildsTree() *GuildsTree { root: tview.NewTreeNode(""), } - gt.SetGraphics(cfg.Keys.GuildsTree.Graphics) + gt.SetGraphics(cfg.Theme.GuildsTree.Graphics) gt.SetRoot(gt.root) gt.SetTopLevel(1) gt.SetSelectedFunc(gt.onSelected) - gt.SetTitle("Guilds") - gt.SetBorder(true) + gt.SetBorder(cfg.Theme.GuildsTree.Border) gt.SetBorderPadding(cfg.BorderPadding()) return gt diff --git a/message_input.go b/message_input.go index 8d33d35..656e3f5 100644 --- a/message_input.go +++ b/message_input.go @@ -13,7 +13,7 @@ func newMessageInput() *MessageInput { InputField: tview.NewInputField(), } - mi.SetBorder(true) + mi.SetBorder(cfg.Theme.MessageInput.Border) mi.SetBorderPadding(cfg.BorderPadding()) return mi diff --git a/messages_text.go b/messages_text.go index be5eb83..e4af360 100644 --- a/messages_text.go +++ b/messages_text.go @@ -23,8 +23,7 @@ func newMessagesText() *MessagesText { mt.SetRegions(true) mt.SetWordWrap(true) - mt.SetTitle("Messages") - mt.SetBorder(true) + mt.SetBorder(cfg.Theme.MessagesText.Border) mt.SetBorderPadding(cfg.BorderPadding()) return mt From b211eb08aecac6710331abd1567bf10a8dead237 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 1 Jan 2023 15:44:49 +0530 Subject: [PATCH 07/70] Switch to yaml --- config.go | 73 +++++++++++++++++++----------------------------- go.mod | 1 + go.sum | 3 ++ guilds_tree.go | 4 ++- message_input.go | 4 ++- messages_text.go | 4 ++- 6 files changed, 42 insertions(+), 47 deletions(-) diff --git a/config.go b/config.go index b0f004b..f229133 100644 --- a/config.go +++ b/config.go @@ -1,49 +1,43 @@ package main import ( - "encoding/json" "os" "path/filepath" + + "gopkg.in/yaml.v3" ) const name = "discordo" +type CommonThemeConfig struct { + Border bool `yaml:"border"` + BorderPadding [4]int `yaml:"border_padding"` +} + type GuildsTreeThemeConfig struct { - Border bool - Graphics bool + CommonThemeConfig `yaml:",inline"` + Graphics bool `yaml:"graphics"` } type MessagesTextThemeConfig struct { - Border bool + CommonThemeConfig `yaml:",inline"` } type MessageInputThemeConfig struct { - Border bool + CommonThemeConfig `yaml:",inline"` } type ThemeConfig struct { - BorderPadding [4]int - - GuildsTree GuildsTreeThemeConfig - MessagesText MessagesTextThemeConfig - MessageInput MessageInputThemeConfig -} - -type MessagesTextKeysConfig struct { - SelectPreviousMessage string - SelectNextMessage string -} - -type KeysConfig struct { - MessagesText MessagesTextKeysConfig + GuildsTree GuildsTreeThemeConfig `yaml:"guilds_tree"` + MessagesText MessagesTextThemeConfig `yaml:"messages_text"` + MessageInput MessageInputThemeConfig `yaml:"message_input"` } type Config struct { - Mouse bool - MessagesLimit uint + Mouse bool `yaml:"mouse"` + MessagesLimit uint `yaml:"messages_limit"` - Theme ThemeConfig - Keys KeysConfig + Theme ThemeConfig `yaml:"theme"` } func newConfig() (*Config, error) { @@ -57,32 +51,29 @@ func newConfig() (*Config, error) { return nil, err } + common := CommonThemeConfig{ + Border: true, + BorderPadding: [...]int{1, 1, 1, 1}, + } + c := Config{ Mouse: true, MessagesLimit: 50, Theme: ThemeConfig{ - BorderPadding: [...]int{1, 1, 1, 1}, - GuildsTree: GuildsTreeThemeConfig{ - Border: true, - Graphics: true, + CommonThemeConfig: common, + Graphics: true, }, MessagesText: MessagesTextThemeConfig{ - Border: true, + CommonThemeConfig: common, }, MessageInput: MessageInputThemeConfig{ - Border: true, - }, - }, - Keys: KeysConfig{ - MessagesText: MessagesTextKeysConfig{ - SelectPreviousMessage: "Up", - SelectNextMessage: "Down", + CommonThemeConfig: common, }, }, } - path = filepath.Join(path, "config.json") + path = filepath.Join(path, "config.yaml") if _, err = os.Stat(path); os.IsNotExist(err) { f, err := os.Create(path) if err != nil { @@ -90,8 +81,7 @@ func newConfig() (*Config, error) { } defer f.Close() - e := json.NewEncoder(f) - e.SetIndent("", "\t") + e := yaml.NewEncoder(f) if err = e.Encode(c); err != nil { return nil, err } @@ -102,15 +92,10 @@ func newConfig() (*Config, error) { } defer f.Close() - if err = json.NewDecoder(f).Decode(&c); err != nil { + if err = yaml.NewDecoder(f).Decode(&c); err != nil { return nil, err } } return &c, nil } - -func (c *Config) BorderPadding() (int, int, int, int) { - pad := c.Theme.BorderPadding - return pad[0], pad[1], pad[2], pad[3] -} diff --git a/go.mod b/go.mod index f7373dd..1fc2a0e 100644 --- a/go.mod +++ b/go.mod @@ -20,4 +20,5 @@ require ( golang.org/x/term v0.3.0 // indirect golang.org/x/text v0.5.0 // indirect golang.org/x/time v0.3.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 6085ebd..096b877 100644 --- a/go.sum +++ b/go.sum @@ -42,3 +42,6 @@ golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/guilds_tree.go b/guilds_tree.go index df23d1a..a955865 100644 --- a/guilds_tree.go +++ b/guilds_tree.go @@ -28,7 +28,9 @@ func newGuildsTree() *GuildsTree { gt.SetSelectedFunc(gt.onSelected) gt.SetBorder(cfg.Theme.GuildsTree.Border) - gt.SetBorderPadding(cfg.BorderPadding()) + + padding := cfg.Theme.GuildsTree.BorderPadding + gt.SetBorderPadding(padding[0], padding[1], padding[2], padding[3]) return gt } diff --git a/message_input.go b/message_input.go index 656e3f5..20cdf34 100644 --- a/message_input.go +++ b/message_input.go @@ -14,7 +14,9 @@ func newMessageInput() *MessageInput { } mi.SetBorder(cfg.Theme.MessageInput.Border) - mi.SetBorderPadding(cfg.BorderPadding()) + + padding := cfg.Theme.MessageInput.BorderPadding + mi.SetBorderPadding(padding[0], padding[1], padding[2], padding[3]) return mi } diff --git a/messages_text.go b/messages_text.go index e4af360..f448db1 100644 --- a/messages_text.go +++ b/messages_text.go @@ -24,7 +24,9 @@ func newMessagesText() *MessagesText { mt.SetWordWrap(true) mt.SetBorder(cfg.Theme.MessagesText.Border) - mt.SetBorderPadding(cfg.BorderPadding()) + + padding := cfg.Theme.MessagesText.BorderPadding + mt.SetBorderPadding(padding[0], padding[1], padding[2], padding[3]) return mt } From ed769c531a1599dec2c29a59228b50b403a7bb7a Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 1 Jan 2023 15:49:46 +0530 Subject: [PATCH 08/70] Upgrade deps to latest --- go.mod | 4 ++-- go.sum | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 1fc2a0e..7b4a39e 100644 --- a/go.mod +++ b/go.mod @@ -4,12 +4,13 @@ go 1.19 require ( github.com/diamondburned/arikawa/v3 v3.1.0 - github.com/gdamore/tcell/v2 v2.5.3 github.com/rivo/tview v0.0.0-20221229180733-b86a50a5126c + gopkg.in/yaml.v3 v3.0.1 ) require ( github.com/gdamore/encoding v1.0.0 // indirect + github.com/gdamore/tcell/v2 v2.5.4 // indirect github.com/gorilla/schema v1.2.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect @@ -20,5 +21,4 @@ require ( golang.org/x/term v0.3.0 // indirect golang.org/x/text v0.5.0 // indirect golang.org/x/time v0.3.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 096b877..9982fc8 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdk github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= github.com/gdamore/tcell/v2 v2.5.3 h1:b9XQrT6QGbgI7JvZOJXFNczOQeIYbo8BfeSMzt2sAV0= github.com/gdamore/tcell/v2 v2.5.3/go.mod h1:wSkrPaXoiIWZqW/g7Px4xc79di6FTcpB8tvaKJ6uGBo= +github.com/gdamore/tcell/v2 v2.5.4 h1:TGU4tSjD3sCL788vFNeJnTdzpNKIw1H5dgLnJRQVv/k= +github.com/gdamore/tcell/v2 v2.5.4/go.mod h1:dZgRy5v4iMobMEcWNYBtREnDZAT9DYmfqIkrgEMxLyw= github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc= github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -21,16 +23,27 @@ github.com/rivo/tview v0.0.0-20221229180733-b86a50a5126c/go.mod h1:lBUy/T5kyMudF github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw= github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211001092434-39dca1131b70/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220318055525-2edf467146b5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -42,6 +55,10 @@ golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From 23b5e721565b69e3b6ef592e11e93f2fa1ec4324 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 1 Jan 2023 15:54:33 +0530 Subject: [PATCH 09/70] Set flow style for BorderPadding --- config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.go b/config.go index f229133..9ca7453 100644 --- a/config.go +++ b/config.go @@ -11,7 +11,7 @@ const name = "discordo" type CommonThemeConfig struct { Border bool `yaml:"border"` - BorderPadding [4]int `yaml:"border_padding"` + BorderPadding [4]int `yaml:"border_padding,flow"` } type GuildsTreeThemeConfig struct { From 29d975b2d9225a53427789ba71b3314d31314865 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 1 Jan 2023 18:56:56 +0530 Subject: [PATCH 10/70] Change default BorderPadding --- config.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.go b/config.go index 9ca7453..b455a1c 100644 --- a/config.go +++ b/config.go @@ -53,7 +53,7 @@ func newConfig() (*Config, error) { common := CommonThemeConfig{ Border: true, - BorderPadding: [...]int{1, 1, 1, 1}, + BorderPadding: [...]int{0, 0, 1, 1}, } c := Config{ @@ -73,7 +73,7 @@ func newConfig() (*Config, error) { }, }, } - path = filepath.Join(path, "config.yaml") + path = filepath.Join(path, "config.yml") if _, err = os.Stat(path); os.IsNotExist(err) { f, err := os.Create(path) if err != nil { From e3467354546ac85b67e76a073672d1486b70b584 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 1 Jan 2023 19:30:30 +0530 Subject: [PATCH 11/70] Escape message content --- messages_text.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/messages_text.go b/messages_text.go index f448db1..5ea5436 100644 --- a/messages_text.go +++ b/messages_text.go @@ -83,5 +83,5 @@ func (mt *MessagesText) newTimestamp(m *discord.Message) { } func (mt *MessagesText) newContent(m *discord.Message) { - mt.buffer.WriteString(m.Content) + mt.buffer.WriteString(tview.Escape(m.Content)) } From 232fb35a70e7ea680e6abf782c63f5b087c6d89d Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 1 Jan 2023 23:28:31 +0530 Subject: [PATCH 12/70] Upgrade tview to latest --- go.mod | 2 +- go.sum | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 7b4a39e..03d1edd 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.19 require ( github.com/diamondburned/arikawa/v3 v3.1.0 - github.com/rivo/tview v0.0.0-20221229180733-b86a50a5126c + github.com/rivo/tview v0.0.0-20230101141202-1dc4a83affeb gopkg.in/yaml.v3 v3.0.1 ) diff --git a/go.sum b/go.sum index 9982fc8..00a0d47 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,6 @@ github.com/diamondburned/arikawa/v3 v3.1.0 h1:M7ZyjoCM4o1+rzai2NMXjOSukSrPdP6OxV github.com/diamondburned/arikawa/v3 v3.1.0/go.mod h1:5jBSNnp82Z/EhsKa6Wk9FsOqSxfVkNZDTDBPOj47LpY= 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.5.3 h1:b9XQrT6QGbgI7JvZOJXFNczOQeIYbo8BfeSMzt2sAV0= -github.com/gdamore/tcell/v2 v2.5.3/go.mod h1:wSkrPaXoiIWZqW/g7Px4xc79di6FTcpB8tvaKJ6uGBo= github.com/gdamore/tcell/v2 v2.5.4 h1:TGU4tSjD3sCL788vFNeJnTdzpNKIw1H5dgLnJRQVv/k= github.com/gdamore/tcell/v2 v2.5.4/go.mod h1:dZgRy5v4iMobMEcWNYBtREnDZAT9DYmfqIkrgEMxLyw= github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc= @@ -13,13 +11,12 @@ github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWm github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 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/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/rivo/tview v0.0.0-20221229180733-b86a50a5126c h1:Xa0IDAwI/b4D3AQwFOhvOeYB/H0N8Bhhe3XJWSa2vjg= -github.com/rivo/tview v0.0.0-20221229180733-b86a50a5126c/go.mod h1:lBUy/T5kyMudFzWUH/C2moN+NlU5qF505vzOyINXuUQ= +github.com/rivo/tview v0.0.0-20230101141202-1dc4a83affeb h1:4/YJJr2yN6sGk9XiIedoU7FH4bCJEhoQjfIJLDhZAg0= +github.com/rivo/tview v0.0.0-20230101141202-1dc4a83affeb/go.mod h1:lBUy/T5kyMudFzWUH/C2moN+NlU5qF505vzOyINXuUQ= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw= github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= @@ -36,13 +33,11 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211001092434-39dca1131b70/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220318055525-2edf467146b5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= From 9f32821220a98578e7ebbcf435bac4174f5dfe36 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 1 Jan 2023 23:31:56 +0530 Subject: [PATCH 13/70] Initialize app & flex in global scope --- main.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/main.go b/main.go index ea85325..6e132a1 100644 --- a/main.go +++ b/main.go @@ -14,8 +14,9 @@ var ( cfg *Config discordState *State - app *tview.Application - flex *tview.Flex + app = tview.NewApplication() + flex = tview.NewFlex() + guildsTree *GuildsTree messagesText *MessagesText messageInput *MessageInput @@ -35,8 +36,6 @@ func main() { } // Initialize UI - app = tview.NewApplication() - guildsTree = newGuildsTree() messagesText = newMessagesText() messageInput = newMessageInput() @@ -51,7 +50,6 @@ func main() { right.AddItem(messagesText, 0, 1, false) right.AddItem(messageInput, 3, 1, false) - flex = tview.NewFlex() flex.AddItem(guildsTree, 0, 1, false) flex.AddItem(right, 0, 4, false) From 63243cc97e1f6cf536d4b1b23d3db2ca1d203682 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 1 Jan 2023 23:49:16 +0530 Subject: [PATCH 14/70] Rewrite --- guilds_tree.go | 10 ++++++---- messages_text.go | 34 ++++++++++++---------------------- state.go | 10 ++++++++++ 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/guilds_tree.go b/guilds_tree.go index a955865..55845ca 100644 --- a/guilds_tree.go +++ b/guilds_tree.go @@ -1,7 +1,6 @@ package main import ( - "fmt" "log" "sort" @@ -12,7 +11,8 @@ import ( type GuildsTree struct { *tview.TreeView - root *tview.TreeNode + root *tview.TreeNode + selectedChannel *discord.Channel } func newGuildsTree() *GuildsTree { @@ -135,6 +135,9 @@ func (gt *GuildsTree) onSelected(n *tview.TreeNode) { return } + gt.selectedChannel = c + messagesText.SetTitle(gt.channelToString(*c)) + ms, err := discordState.Messages(ref, cfg.MessagesLimit) if err != nil { log.Println(err) @@ -143,12 +146,11 @@ func (gt *GuildsTree) onSelected(n *tview.TreeNode) { for i := len(ms) - 1; i >= 0; i-- { if messagesText.newMessage(&ms[i]); err != nil { - fmt.Println(err) + log.Println(err) continue } } - messagesText.SetTitle(gt.channelToString(*c)) app.SetFocus(messagesText) } } diff --git a/messages_text.go b/messages_text.go index 5ea5436..92b151e 100644 --- a/messages_text.go +++ b/messages_text.go @@ -1,7 +1,7 @@ package main import ( - "bytes" + "fmt" "time" "github.com/diamondburned/arikawa/v3/discord" @@ -10,8 +10,6 @@ import ( type MessagesText struct { *tview.TextView - - buffer bytes.Buffer } func newMessagesText() *MessagesText { @@ -36,20 +34,18 @@ func (mt *MessagesText) newMessage(m *discord.Message) error { case discord.DefaultMessage, discord.InlinedReplyMessage: // Region tags are square brackets that contain a region ID in double quotes // https://pkg.go.dev/github.com/rivo/tview#hdr-Regions_and_Highlights - mt.buffer.WriteString(`["`) - mt.buffer.WriteString(m.ID.String()) - mt.buffer.WriteString(`"]`) + fmt.Fprintf(mt, `["%s"]`, m.ID) if m.ReferencedMessage != nil { - mt.buffer.WriteString("> [::d]") + fmt.Fprint(mt, "> [::d]") // Author mt.newAuthor(m.ReferencedMessage) // Content mt.newContent(m.ReferencedMessage) - mt.buffer.WriteString("[::-]") - mt.buffer.WriteByte('\n') + fmt.Fprint(mt, "[::-]") + fmt.Fprintln(mt) } // Author @@ -57,31 +53,25 @@ func (mt *MessagesText) newMessage(m *discord.Message) error { // Timestamps mt.newTimestamp(m) // Content - mt.buffer.WriteByte('\n') + fmt.Fprintln(mt) mt.newContent(m) // Tags with no region ID ([""]) don't start new regions. They can therefore be used to mark the end of a region. - mt.buffer.WriteString(`[""]`) + fmt.Fprint(mt, `[""]`) } - mt.buffer.WriteString("\n\n") - - _, err := mt.buffer.WriteTo(mt) - return err + fmt.Fprint(mt, "\n\n") + return nil } func (mt *MessagesText) newAuthor(m *discord.Message) { - mt.buffer.WriteString("[blue]") - mt.buffer.WriteString(m.Author.Username) - mt.buffer.WriteString("[-] ") + fmt.Fprintf(mt, "[blue]%s[-] ", m.Author.Username) } func (mt *MessagesText) newTimestamp(m *discord.Message) { - mt.buffer.WriteString("[::d]") - mt.buffer.WriteString(m.Timestamp.Format(time.Kitchen)) - mt.buffer.WriteString("[-:-:-] ") + fmt.Fprintf(mt, "[::d]%s[::-]", m.Timestamp.Format(time.Kitchen)) } func (mt *MessagesText) newContent(m *discord.Message) { - mt.buffer.WriteString(tview.Escape(m.Content)) + fmt.Fprint(mt, tview.Escape(m.Content)) } diff --git a/state.go b/state.go index bc9fe73..3d54e42 100644 --- a/state.go +++ b/state.go @@ -18,6 +18,7 @@ func newState(token string) *State { } s.AddHandler(s.onReady) + s.AddHandler(s.onMessageCreate) return s } @@ -49,3 +50,12 @@ func (s *State) onReady(r *gateway.ReadyEvent) { guildsTree.SetCurrentNode(guildsTree.root) app.SetFocus(guildsTree) } + +func (s *State) onMessageCreate(m *gateway.MessageCreateEvent) { + if guildsTree.selectedChannel != nil { + if err := messagesText.newMessage(&m.Message); err != nil { + log.Println(err) + return + } + } +} From 1231386964b5322d98ec21d3d8a68bf80fd7dfc5 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Mon, 2 Jan 2023 00:26:29 +0530 Subject: [PATCH 15/70] Move timestamps before author --- messages_text.go | 9 ++++----- state.go | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/messages_text.go b/messages_text.go index 92b151e..d67a1a1 100644 --- a/messages_text.go +++ b/messages_text.go @@ -48,19 +48,18 @@ func (mt *MessagesText) newMessage(m *discord.Message) error { fmt.Fprintln(mt) } - // Author - mt.newAuthor(m) // Timestamps mt.newTimestamp(m) + // Author + mt.newAuthor(m) // Content - fmt.Fprintln(mt) mt.newContent(m) // Tags with no region ID ([""]) don't start new regions. They can therefore be used to mark the end of a region. fmt.Fprint(mt, `[""]`) } - fmt.Fprint(mt, "\n\n") + fmt.Fprintln(mt) return nil } @@ -69,7 +68,7 @@ func (mt *MessagesText) newAuthor(m *discord.Message) { } func (mt *MessagesText) newTimestamp(m *discord.Message) { - fmt.Fprintf(mt, "[::d]%s[::-]", m.Timestamp.Format(time.Kitchen)) + fmt.Fprintf(mt, "[::d]%s[::-] ", m.Timestamp.Format(time.Kitchen)) } func (mt *MessagesText) newContent(m *discord.Message) { diff --git a/state.go b/state.go index 3d54e42..4fee36b 100644 --- a/state.go +++ b/state.go @@ -52,7 +52,7 @@ func (s *State) onReady(r *gateway.ReadyEvent) { } func (s *State) onMessageCreate(m *gateway.MessageCreateEvent) { - if guildsTree.selectedChannel != nil { + if guildsTree.selectedChannel != nil && guildsTree.selectedChannel.ID == m.ChannelID { if err := messagesText.newMessage(&m.Message); err != nil { log.Println(err) return From 9a410708d12e781c1d2f30a9e4f166ebc727565e Mon Sep 17 00:00:00 2001 From: ayn2op Date: Mon, 2 Jan 2023 00:37:22 +0530 Subject: [PATCH 16/70] Clarity --- message_input.go | 2 ++ messages_text.go | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/message_input.go b/message_input.go index 20cdf34..e5eb904 100644 --- a/message_input.go +++ b/message_input.go @@ -13,6 +13,8 @@ func newMessageInput() *MessageInput { InputField: tview.NewInputField(), } + mi.SetFieldBackgroundColor(tview.Styles.PrimitiveBackgroundColor) + mi.SetBorder(cfg.Theme.MessageInput.Border) padding := cfg.Theme.MessageInput.BorderPadding diff --git a/messages_text.go b/messages_text.go index d67a1a1..0f0ea3f 100644 --- a/messages_text.go +++ b/messages_text.go @@ -37,7 +37,7 @@ func (mt *MessagesText) newMessage(m *discord.Message) error { fmt.Fprintf(mt, `["%s"]`, m.ID) if m.ReferencedMessage != nil { - fmt.Fprint(mt, "> [::d]") + fmt.Fprint(mt, " ╭ [::d]") // Author mt.newAuthor(m.ReferencedMessage) From e00cb1c8eb7491cff931e3d2af870a86c766c10c Mon Sep 17 00:00:00 2001 From: ayn2op Date: Mon, 2 Jan 2023 00:43:44 +0530 Subject: [PATCH 17/70] Dim inline reply symbol --- messages_text.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/messages_text.go b/messages_text.go index 0f0ea3f..7e3e125 100644 --- a/messages_text.go +++ b/messages_text.go @@ -37,7 +37,7 @@ func (mt *MessagesText) newMessage(m *discord.Message) error { fmt.Fprintf(mt, `["%s"]`, m.ID) if m.ReferencedMessage != nil { - fmt.Fprint(mt, " ╭ [::d]") + fmt.Fprint(mt, "[::d] ╭ ") // Author mt.newAuthor(m.ReferencedMessage) From 227444f24e72d4e1889913283a77f4a92416775b Mon Sep 17 00:00:00 2001 From: ayn2op Date: Mon, 2 Jan 2023 01:15:13 +0530 Subject: [PATCH 18/70] Support for private channels (DM channels) --- guilds_tree.go | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/guilds_tree.go b/guilds_tree.go index 55845ca..895d451 100644 --- a/guilds_tree.go +++ b/guilds_tree.go @@ -3,6 +3,7 @@ package main import ( "log" "sort" + "strings" "github.com/diamondburned/arikawa/v3/discord" "github.com/rivo/tview" @@ -54,18 +55,35 @@ func (gt *GuildsTree) newChannel(n *tview.TreeNode, c discord.Channel) { } func (gt *GuildsTree) channelToString(c discord.Channel) string { + var s string switch c.Type { case discord.GuildText: - return "#" + c.Name + s = "#" + c.Name + case discord.DirectMessage: + r := c.DMRecipients[0] + s = r.Tag() case discord.GuildVoice: - return "v-" + c.Name + s = "v-" + c.Name + case discord.GroupDM: + s = c.Name + // If the name of the channel is empty, use the recipients tags + if s == "" { + rs := make([]string, len(c.DMRecipients)) + for _, r := range c.DMRecipients { + rs = append(rs, r.Tag()) + } + + s = strings.Join(rs, ", ") + } case discord.GuildNews: - return "n-" + c.Name + s = "n-" + c.Name case discord.GuildStore: - return "s-" + c.Name + s = "s-" + c.Name default: - return c.Name + s = c.Name } + + return s } func (gt *GuildsTree) onSelected(n *tview.TreeNode) { @@ -152,5 +170,19 @@ func (gt *GuildsTree) onSelected(n *tview.TreeNode) { } app.SetFocus(messagesText) + case nil: // Direct messages + cs, err := discordState.Cabinet.PrivateChannels() + if err != nil { + log.Println(err) + return + } + + sort.Slice(cs, func(i, j int) bool { + return cs[i].LastMessageID < cs[j].LastMessageID + }) + + for _, c := range cs { + gt.newChannel(n, c) + } } } From 4b186d15f8787e34a5c5b374d4c9bc012b184d2c Mon Sep 17 00:00:00 2001 From: ayn2op Date: Mon, 2 Jan 2023 01:20:07 +0530 Subject: [PATCH 19/70] Always focus guilds tree at start-up --- main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.go b/main.go index 6e132a1..e15f23b 100644 --- a/main.go +++ b/main.go @@ -49,8 +49,8 @@ func main() { right.SetDirection(tview.FlexRow) right.AddItem(messagesText, 0, 1, false) right.AddItem(messageInput, 3, 1, false) - - flex.AddItem(guildsTree, 0, 1, false) + // The guilds tree is always focused first at start-up. + flex.AddItem(guildsTree, 0, 1, true) flex.AddItem(right, 0, 4, false) app.EnableMouse(cfg.Mouse) From 1e1c0c0d2db3eaa70dd870dd039dd2d524af920a Mon Sep 17 00:00:00 2001 From: ayn2op Date: Mon, 2 Jan 2023 12:07:39 +0530 Subject: [PATCH 20/70] Add default useragent and identify properties --- state.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/state.go b/state.go index 4fee36b..708c01d 100644 --- a/state.go +++ b/state.go @@ -1,13 +1,25 @@ package main import ( + "fmt" "log" + "runtime" + "github.com/diamondburned/arikawa/v3/api" "github.com/diamondburned/arikawa/v3/gateway" "github.com/diamondburned/arikawa/v3/state" "github.com/rivo/tview" ) +func init() { + api.UserAgent = fmt.Sprintf("%s/%s %s/%s", name, "0.1", "arikawa", "v3") + gateway.DefaultIdentity = gateway.IdentifyProperties{ + OS: runtime.GOOS, + Browser: name, + Device: "", + } +} + type State struct { *state.State } @@ -27,6 +39,12 @@ func (s *State) onReady(r *gateway.ReadyEvent) { dmNode := tview.NewTreeNode("Direct Messages") guildsTree.root.AddChild(dmNode) + for _, g := range r.Guilds { + log.Println(g.Name) + } + + log.Printf("%#v\n", r.UserSettings.GuildFolders) + for _, gf := range r.UserSettings.GuildFolders { /// If the ID of the guild folder is zero, the guild folder only contains single guild. if gf.ID == 0 { From ca337433888bdc2269924a4ca9daf97765c89349 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Mon, 2 Jan 2023 12:32:36 +0530 Subject: [PATCH 21/70] rewrite --- state.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/state.go b/state.go index 708c01d..ec35799 100644 --- a/state.go +++ b/state.go @@ -39,12 +39,6 @@ func (s *State) onReady(r *gateway.ReadyEvent) { dmNode := tview.NewTreeNode("Direct Messages") guildsTree.root.AddChild(dmNode) - for _, g := range r.Guilds { - log.Println(g.Name) - } - - log.Printf("%#v\n", r.UserSettings.GuildFolders) - for _, gf := range r.UserSettings.GuildFolders { /// If the ID of the guild folder is zero, the guild folder only contains single guild. if gf.ID == 0 { From 7dff2b2433379e81f9c4b2910f11aa28d8c2f40a Mon Sep 17 00:00:00 2001 From: ayn2op Date: Mon, 2 Jan 2023 14:04:36 +0530 Subject: [PATCH 22/70] Support for sending message --- message_input.go | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/message_input.go b/message_input.go index e5eb904..a25d4e8 100644 --- a/message_input.go +++ b/message_input.go @@ -1,6 +1,7 @@ package main import ( + "github.com/gdamore/tcell/v2" "github.com/rivo/tview" ) @@ -13,12 +14,34 @@ func newMessageInput() *MessageInput { InputField: tview.NewInputField(), } + mi.SetDoneFunc(mi.onDone) + mi.SetFieldBackgroundColor(tview.Styles.PrimitiveBackgroundColor) - mi.SetBorder(cfg.Theme.MessageInput.Border) - padding := cfg.Theme.MessageInput.BorderPadding mi.SetBorderPadding(padding[0], padding[1], padding[2], padding[3]) return mi } + +func (mi *MessageInput) onDone(key tcell.Key) { + switch key { + case tcell.KeyEnter: + go mi.sendMessage() + case tcell.KeyEscape: + // Reset the message input. + mi.SetText("") + } +} + +func (mi *MessageInput) sendMessage() error { + text := mi.GetText() + _, err := discordState.SendMessage(guildsTree.selectedChannel.ID, text) + if err != nil { + return err + } + + // Reset the message input. + mi.SetText("") + return nil +} From ad9b1cade3612496f4b14474bd2dfbc60e4417a7 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Mon, 2 Jan 2023 14:06:46 +0530 Subject: [PATCH 23/70] Convert tcell to direct dep --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 03d1edd..b556807 100644 --- a/go.mod +++ b/go.mod @@ -4,13 +4,13 @@ go 1.19 require ( github.com/diamondburned/arikawa/v3 v3.1.0 + github.com/gdamore/tcell/v2 v2.5.4 github.com/rivo/tview v0.0.0-20230101141202-1dc4a83affeb gopkg.in/yaml.v3 v3.0.1 ) require ( github.com/gdamore/encoding v1.0.0 // indirect - github.com/gdamore/tcell/v2 v2.5.4 // indirect github.com/gorilla/schema v1.2.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect From eac2a2cd769168bc1a89fd615128e31058605797 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Mon, 2 Jan 2023 21:46:41 +0530 Subject: [PATCH 24/70] Add timestamps field to configuration --- config.go | 1 + messages_text.go | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/config.go b/config.go index b455a1c..709c117 100644 --- a/config.go +++ b/config.go @@ -36,6 +36,7 @@ type ThemeConfig struct { type Config struct { Mouse bool `yaml:"mouse"` MessagesLimit uint `yaml:"messages_limit"` + Timestamps bool `yaml:"timestamps"` Theme ThemeConfig `yaml:"theme"` } diff --git a/messages_text.go b/messages_text.go index 7e3e125..3ff8a49 100644 --- a/messages_text.go +++ b/messages_text.go @@ -20,6 +20,7 @@ func newMessagesText() *MessagesText { mt.SetDynamicColors(true) mt.SetRegions(true) mt.SetWordWrap(true) + mt.ScrollToEnd() mt.SetBorder(cfg.Theme.MessagesText.Border) @@ -41,6 +42,7 @@ func (mt *MessagesText) newMessage(m *discord.Message) error { // Author mt.newAuthor(m.ReferencedMessage) + // Content mt.newContent(m.ReferencedMessage) @@ -48,10 +50,14 @@ func (mt *MessagesText) newMessage(m *discord.Message) error { fmt.Fprintln(mt) } - // Timestamps - mt.newTimestamp(m) + if cfg.Timestamps { + // Timestamps + mt.newTimestamp(m) + } + // Author mt.newAuthor(m) + // Content mt.newContent(m) From 8fa861d59e434b216953914d5eb6d6732c40e3d9 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Wed, 4 Jan 2023 14:26:05 +0530 Subject: [PATCH 25/70] Update arikawa to latest --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b556807..d109351 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/ayn2op/discordo go 1.19 require ( - github.com/diamondburned/arikawa/v3 v3.1.0 + github.com/diamondburned/arikawa/v3 v3.2.0 github.com/gdamore/tcell/v2 v2.5.4 github.com/rivo/tview v0.0.0-20230101141202-1dc4a83affeb gopkg.in/yaml.v3 v3.0.1 diff --git a/go.sum b/go.sum index 00a0d47..1e3624c 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/diamondburned/arikawa/v3 v3.1.0 h1:M7ZyjoCM4o1+rzai2NMXjOSukSrPdP6OxV68WKvKZ6E= -github.com/diamondburned/arikawa/v3 v3.1.0/go.mod h1:5jBSNnp82Z/EhsKa6Wk9FsOqSxfVkNZDTDBPOj47LpY= +github.com/diamondburned/arikawa/v3 v3.2.0 h1:aBUhg94pxblT6ks4EV7qxEk44tnl0ico67ydqjVnv9g= +github.com/diamondburned/arikawa/v3 v3.2.0/go.mod h1:5jBSNnp82Z/EhsKa6Wk9FsOqSxfVkNZDTDBPOj47LpY= 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.5.4 h1:TGU4tSjD3sCL788vFNeJnTdzpNKIw1H5dgLnJRQVv/k= From 4b97caf3298272b31bdadaf6253f1ac74926ec45 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Wed, 4 Jan 2023 20:55:02 +0530 Subject: [PATCH 26/70] Assign GuildsTree#selectedMessage when a message is highlighted --- main.go | 10 +++++----- messages_text.go | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/main.go b/main.go index e15f23b..3bae4b4 100644 --- a/main.go +++ b/main.go @@ -35,16 +35,16 @@ func main() { log.Fatal(err) } - // Initialize UI - guildsTree = newGuildsTree() - messagesText = newMessagesText() - messageInput = newMessageInput() - discordState = newState(token) if err = discordState.Open(context.Background()); err != nil { log.Fatal(err) } + // Initialize UI + guildsTree = newGuildsTree() + messagesText = newMessagesText() + messageInput = newMessageInput() + right := tview.NewFlex() right.SetDirection(tview.FlexRow) right.AddItem(messagesText, 0, 1, false) diff --git a/messages_text.go b/messages_text.go index 3ff8a49..3e4c033 100644 --- a/messages_text.go +++ b/messages_text.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "log" "time" "github.com/diamondburned/arikawa/v3/discord" @@ -10,6 +11,8 @@ import ( type MessagesText struct { *tview.TextView + + selectedMessage *discord.Message } func newMessagesText() *MessagesText { @@ -21,6 +24,7 @@ func newMessagesText() *MessagesText { mt.SetRegions(true) mt.SetWordWrap(true) mt.ScrollToEnd() + mt.SetHighlightedFunc(mt.onHighlighted) mt.SetBorder(cfg.Theme.MessagesText.Border) @@ -80,3 +84,23 @@ func (mt *MessagesText) newTimestamp(m *discord.Message) { func (mt *MessagesText) newContent(m *discord.Message) { fmt.Fprint(mt, tview.Escape(m.Content)) } + +func (mt *MessagesText) onHighlighted(added, removed, remaining []string) { + if len(added) == 0 { + return + } + + sf, err := discord.ParseSnowflake(added[0]) + if err != nil { + log.Println(err) + return + } + + m, err := discordState.Cabinet.Message(guildsTree.selectedChannel.ID, discord.MessageID(sf)) + if err != nil { + log.Println(err) + return + } + + mt.selectedMessage = m +} From 1cbfe871c594af3e129d6deb68b058e1ba5d67fc Mon Sep 17 00:00:00 2001 From: ayn2op Date: Wed, 4 Jan 2023 23:40:00 +0530 Subject: [PATCH 27/70] Upgrade deps to latest --- go.mod | 8 ++++---- go.sum | 15 ++++++++------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index d109351..aeb1d2c 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( github.com/diamondburned/arikawa/v3 v3.2.0 github.com/gdamore/tcell/v2 v2.5.4 - github.com/rivo/tview v0.0.0-20230101141202-1dc4a83affeb + github.com/rivo/tview v0.0.0-20230104153304-892d1a2eb0da gopkg.in/yaml.v3 v3.0.1 ) @@ -17,8 +17,8 @@ require ( github.com/mattn/go-runewidth v0.0.14 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/rivo/uniseg v0.4.3 // indirect - golang.org/x/sys v0.3.0 // indirect - golang.org/x/term v0.3.0 // indirect - golang.org/x/text v0.5.0 // indirect + golang.org/x/sys v0.4.0 // indirect + golang.org/x/term v0.4.0 // indirect + golang.org/x/text v0.6.0 // indirect golang.org/x/time v0.3.0 // indirect ) diff --git a/go.sum b/go.sum index 1e3624c..5453662 100644 --- a/go.sum +++ b/go.sum @@ -15,8 +15,8 @@ github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWV github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/rivo/tview v0.0.0-20230101141202-1dc4a83affeb h1:4/YJJr2yN6sGk9XiIedoU7FH4bCJEhoQjfIJLDhZAg0= -github.com/rivo/tview v0.0.0-20230101141202-1dc4a83affeb/go.mod h1:lBUy/T5kyMudFzWUH/C2moN+NlU5qF505vzOyINXuUQ= +github.com/rivo/tview v0.0.0-20230104153304-892d1a2eb0da h1:3Mh+tcC2KqetuHpWMurDeF+yOgyt4w4qtLIpwSQ3uqo= +github.com/rivo/tview v0.0.0-20230104153304-892d1a2eb0da/go.mod h1:lBUy/T5kyMudFzWUH/C2moN+NlU5qF505vzOyINXuUQ= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw= github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= @@ -35,17 +35,18 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211001092434-39dca1131b70/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI= -golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/term v0.4.0 h1:O7UWfv5+A2qiuulQk30kVinPoMtoIPeVaKLEgLpVkvg= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= 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.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= From 726e7a4f01a045d406ac0e6b6caac8a569ef0af7 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Fri, 6 Jan 2023 21:35:01 +0530 Subject: [PATCH 28/70] Add customizable keybindings --- config.go | 78 ++++++++++++++++++++++++++++++++++-------------- message_input.go | 1 + messages_text.go | 38 +++++++++++++++++++++++ 3 files changed, 94 insertions(+), 23 deletions(-) diff --git a/config.go b/config.go index 709c117..89466d0 100644 --- a/config.go +++ b/config.go @@ -9,35 +9,54 @@ import ( const name = "discordo" -type CommonThemeConfig struct { - Border bool `yaml:"border"` - BorderPadding [4]int `yaml:"border_padding,flow"` -} +type ( + CommonKeysConfig struct { + Cancel string `yaml:"cancel"` + } -type GuildsTreeThemeConfig struct { - CommonThemeConfig `yaml:",inline"` - Graphics bool `yaml:"graphics"` -} + MessagesTextKeysConfig struct { + CommonKeysConfig `yaml:",inline"` + Reply string `yaml:"reply"` + ReplyMention string `yaml:"reply_mention"` + } -type MessagesTextThemeConfig struct { - CommonThemeConfig `yaml:",inline"` -} + KeysConfig struct { + MessagesText MessagesTextKeysConfig `yaml:"messages_text"` + } +) -type MessageInputThemeConfig struct { - CommonThemeConfig `yaml:",inline"` -} +type ( + CommonThemeConfig struct { + Border bool `yaml:"border"` + BorderPadding [4]int `yaml:"border_padding,flow"` + } -type ThemeConfig struct { - GuildsTree GuildsTreeThemeConfig `yaml:"guilds_tree"` - MessagesText MessagesTextThemeConfig `yaml:"messages_text"` - MessageInput MessageInputThemeConfig `yaml:"message_input"` -} + GuildsTreeThemeConfig struct { + CommonThemeConfig `yaml:",inline"` + Graphics bool `yaml:"graphics"` + } + + MessagesTextThemeConfig struct { + CommonThemeConfig `yaml:",inline"` + } + + MessageInputThemeConfig struct { + CommonThemeConfig `yaml:",inline"` + } + + ThemeConfig struct { + GuildsTree GuildsTreeThemeConfig `yaml:"guilds_tree"` + MessagesText MessagesTextThemeConfig `yaml:"messages_text"` + MessageInput MessageInputThemeConfig `yaml:"message_input"` + } +) type Config struct { Mouse bool `yaml:"mouse"` MessagesLimit uint `yaml:"messages_limit"` Timestamps bool `yaml:"timestamps"` + Keys KeysConfig `yaml:"keys"` Theme ThemeConfig `yaml:"theme"` } @@ -52,25 +71,38 @@ func newConfig() (*Config, error) { return nil, err } - common := CommonThemeConfig{ + commonTheme := CommonThemeConfig{ Border: true, BorderPadding: [...]int{0, 0, 1, 1}, } + commonKeys := CommonKeysConfig{ + Cancel: "Esc", + } + c := Config{ Mouse: true, + Timestamps: false, MessagesLimit: 50, + Keys: KeysConfig{ + MessagesText: MessagesTextKeysConfig{ + CommonKeysConfig: commonKeys, + Reply: "Rune[r]", + ReplyMention: "Rune[R]", + }, + }, + Theme: ThemeConfig{ GuildsTree: GuildsTreeThemeConfig{ - CommonThemeConfig: common, + CommonThemeConfig: commonTheme, Graphics: true, }, MessagesText: MessagesTextThemeConfig{ - CommonThemeConfig: common, + CommonThemeConfig: commonTheme, }, MessageInput: MessageInputThemeConfig{ - CommonThemeConfig: common, + CommonThemeConfig: commonTheme, }, }, } diff --git a/message_input.go b/message_input.go index a25d4e8..0e5530f 100644 --- a/message_input.go +++ b/message_input.go @@ -16,6 +16,7 @@ func newMessageInput() *MessageInput { mi.SetDoneFunc(mi.onDone) + mi.SetTitleAlign(tview.AlignLeft) mi.SetFieldBackgroundColor(tview.Styles.PrimitiveBackgroundColor) mi.SetBorder(cfg.Theme.MessageInput.Border) padding := cfg.Theme.MessageInput.BorderPadding diff --git a/messages_text.go b/messages_text.go index 3e4c033..68208cd 100644 --- a/messages_text.go +++ b/messages_text.go @@ -6,6 +6,7 @@ import ( "time" "github.com/diamondburned/arikawa/v3/discord" + "github.com/gdamore/tcell/v2" "github.com/rivo/tview" ) @@ -22,10 +23,13 @@ func newMessagesText() *MessagesText { mt.SetDynamicColors(true) mt.SetRegions(true) + mt.SetToggleHighlights(true) mt.SetWordWrap(true) mt.ScrollToEnd() mt.SetHighlightedFunc(mt.onHighlighted) + mt.SetInputCapture(mt.onInputCapture) + mt.SetTitleAlign(tview.AlignLeft) mt.SetBorder(cfg.Theme.MessagesText.Border) padding := cfg.Theme.MessagesText.BorderPadding @@ -104,3 +108,37 @@ func (mt *MessagesText) onHighlighted(added, removed, remaining []string) { mt.selectedMessage = m } + +func (mt *MessagesText) onInputCapture(event *tcell.EventKey) *tcell.EventKey { + switch event.Name() { + case cfg.Keys.MessagesText.Reply: + mt.replyAction(false) + return nil + case cfg.Keys.MessagesText.ReplyMention: + mt.replyAction(true) + return nil + case cfg.Keys.MessagesText.Cancel: + // TODO + return nil + } + + return event +} + +func (mt *MessagesText) replyAction(mention bool) { + if mt.selectedMessage == nil { + return + } + + var title string + if mention { + title += "[@] Replying to " + } else { + title += "Replying to " + } + + title += mt.selectedMessage.Author.Tag() + messageInput.SetTitle(title) + + app.SetFocus(messageInput) +} From af07f91f0e36e21289b500d0adc9c77be2f7d1f2 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Fri, 6 Jan 2023 21:41:07 +0530 Subject: [PATCH 29/70] keys for inputfield --- config.go | 10 ++++++++++ guilds_tree.go | 4 +++- message_input.go | 29 ++++++++++++++++------------- messages_text.go | 3 ++- 4 files changed, 31 insertions(+), 15 deletions(-) diff --git a/config.go b/config.go index 89466d0..f00a440 100644 --- a/config.go +++ b/config.go @@ -20,8 +20,14 @@ type ( ReplyMention string `yaml:"reply_mention"` } + MessageInputKeysConfig struct { + CommonKeysConfig `yaml:",inline"` + Send string `yaml:"send"` + } + KeysConfig struct { MessagesText MessagesTextKeysConfig `yaml:"messages_text"` + MessageInput MessageInputKeysConfig `yaml:"message_input"` } ) @@ -91,6 +97,10 @@ func newConfig() (*Config, error) { Reply: "Rune[r]", ReplyMention: "Rune[R]", }, + MessageInput: MessageInputKeysConfig{ + CommonKeysConfig: commonKeys, + Send: "Enter", + }, }, Theme: ThemeConfig{ diff --git a/guilds_tree.go b/guilds_tree.go index 895d451..ed06006 100644 --- a/guilds_tree.go +++ b/guilds_tree.go @@ -28,9 +28,11 @@ func newGuildsTree() *GuildsTree { gt.SetTopLevel(1) gt.SetSelectedFunc(gt.onSelected) - gt.SetBorder(cfg.Theme.GuildsTree.Border) + gt.SetTitle("Guilds") + gt.SetTitleAlign(tview.AlignLeft) padding := cfg.Theme.GuildsTree.BorderPadding + gt.SetBorder(cfg.Theme.GuildsTree.Border) gt.SetBorderPadding(padding[0], padding[1], padding[2], padding[3]) return gt diff --git a/message_input.go b/message_input.go index 0e5530f..a3266e0 100644 --- a/message_input.go +++ b/message_input.go @@ -1,6 +1,8 @@ package main import ( + "log" + "github.com/gdamore/tcell/v2" "github.com/rivo/tview" ) @@ -14,35 +16,36 @@ func newMessageInput() *MessageInput { InputField: tview.NewInputField(), } - mi.SetDoneFunc(mi.onDone) + mi.SetFieldBackgroundColor(tview.Styles.PrimitiveBackgroundColor) + mi.SetInputCapture(mi.onInputCapture) mi.SetTitleAlign(tview.AlignLeft) - mi.SetFieldBackgroundColor(tview.Styles.PrimitiveBackgroundColor) - mi.SetBorder(cfg.Theme.MessageInput.Border) + padding := cfg.Theme.MessageInput.BorderPadding + mi.SetBorder(cfg.Theme.MessageInput.Border) mi.SetBorderPadding(padding[0], padding[1], padding[2], padding[3]) return mi } -func (mi *MessageInput) onDone(key tcell.Key) { - switch key { - case tcell.KeyEnter: - go mi.sendMessage() - case tcell.KeyEscape: - // Reset the message input. - mi.SetText("") +func (mi *MessageInput) onInputCapture(event *tcell.EventKey) *tcell.EventKey { + switch event.Name() { + case cfg.Keys.MessageInput.Send: + mi.sendAction() + return nil } + + return event } -func (mi *MessageInput) sendMessage() error { +func (mi *MessageInput) sendAction() { text := mi.GetText() _, err := discordState.SendMessage(guildsTree.selectedChannel.ID, text) if err != nil { - return err + log.Println(err) + return } // Reset the message input. mi.SetText("") - return nil } diff --git a/messages_text.go b/messages_text.go index 68208cd..8b28983 100644 --- a/messages_text.go +++ b/messages_text.go @@ -29,10 +29,11 @@ func newMessagesText() *MessagesText { mt.SetHighlightedFunc(mt.onHighlighted) mt.SetInputCapture(mt.onInputCapture) + mt.SetTitle("Messages") mt.SetTitleAlign(tview.AlignLeft) - mt.SetBorder(cfg.Theme.MessagesText.Border) padding := cfg.Theme.MessagesText.BorderPadding + mt.SetBorder(cfg.Theme.MessagesText.Border) mt.SetBorderPadding(padding[0], padding[1], padding[2], padding[3]) return mt From 3c428470a2571b28eaab39800bc668b6fc258ec9 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Fri, 6 Jan 2023 21:42:03 +0530 Subject: [PATCH 30/70] Disable toggle highlights --- messages_text.go | 1 - 1 file changed, 1 deletion(-) diff --git a/messages_text.go b/messages_text.go index 8b28983..1b9d9a0 100644 --- a/messages_text.go +++ b/messages_text.go @@ -23,7 +23,6 @@ func newMessagesText() *MessagesText { mt.SetDynamicColors(true) mt.SetRegions(true) - mt.SetToggleHighlights(true) mt.SetWordWrap(true) mt.ScrollToEnd() mt.SetHighlightedFunc(mt.onHighlighted) From 6bc5b6296415e27ae9b6bb496b1cb154f48c9f32 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Fri, 6 Jan 2023 22:14:53 +0530 Subject: [PATCH 31/70] Support for sending message --- message_input.go | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/message_input.go b/message_input.go index a3266e0..aaf2e18 100644 --- a/message_input.go +++ b/message_input.go @@ -2,7 +2,11 @@ package main import ( "log" + "strings" + "github.com/diamondburned/arikawa/v3/api" + "github.com/diamondburned/arikawa/v3/discord" + "github.com/diamondburned/arikawa/v3/utils/json/option" "github.com/gdamore/tcell/v2" "github.com/rivo/tview" ) @@ -39,13 +43,44 @@ func (mi *MessageInput) onInputCapture(event *tcell.EventKey) *tcell.EventKey { } func (mi *MessageInput) sendAction() { - text := mi.GetText() - _, err := discordState.SendMessage(guildsTree.selectedChannel.ID, text) + if guildsTree.selectedChannel == nil { + return + } + + text := strings.TrimSpace(mi.GetText()) + if text == "" { + return + } + + var err error + + if messagesText.selectedMessage != nil { + title := mi.GetTitle() + if title == "" { + return + } + + data := api.SendMessageData{ + Content: text, + Reference: &discord.MessageReference{MessageID: messagesText.selectedMessage.ID}, + AllowedMentions: &api.AllowedMentions{RepliedUser: option.False}, + } + + if strings.HasPrefix(title, "[@]") { + data.AllowedMentions.RepliedUser = option.True + } + + _, err = discordState.SendMessageComplex(guildsTree.selectedChannel.ID, data) + } else { + _, err = discordState.SendMessage(guildsTree.selectedChannel.ID, text) + } + if err != nil { log.Println(err) return } // Reset the message input. + mi.SetTitle("") mi.SetText("") } From d0b9a6dd291a94ecf258cad76547c8ef1794bed9 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sat, 7 Jan 2023 12:39:54 +0530 Subject: [PATCH 32/70] Render attachments --- guilds_tree.go | 8 ++++++++ main.go | 10 +++++----- message_input.go | 1 - messages_text.go | 9 +++++++++ 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/guilds_tree.go b/guilds_tree.go index ed06006..5ef6113 100644 --- a/guilds_tree.go +++ b/guilds_tree.go @@ -89,6 +89,14 @@ func (gt *GuildsTree) channelToString(c discord.Channel) string { } func (gt *GuildsTree) onSelected(n *tview.TreeNode) { + gt.selectedChannel = nil + + messagesText.selectedMessage = nil + messagesText.Highlight() + + messageInput.SetTitle("") + messageInput.SetText("") + if len(n.GetChildren()) != 0 { n.SetExpanded(!n.IsExpanded()) return diff --git a/main.go b/main.go index 3bae4b4..e15f23b 100644 --- a/main.go +++ b/main.go @@ -35,16 +35,16 @@ func main() { log.Fatal(err) } - discordState = newState(token) - if err = discordState.Open(context.Background()); err != nil { - log.Fatal(err) - } - // Initialize UI guildsTree = newGuildsTree() messagesText = newMessagesText() messageInput = newMessageInput() + discordState = newState(token) + if err = discordState.Open(context.Background()); err != nil { + log.Fatal(err) + } + right := tview.NewFlex() right.SetDirection(tview.FlexRow) right.AddItem(messagesText, 0, 1, false) diff --git a/message_input.go b/message_input.go index aaf2e18..29d23fe 100644 --- a/message_input.go +++ b/message_input.go @@ -22,7 +22,6 @@ func newMessageInput() *MessageInput { mi.SetFieldBackgroundColor(tview.Styles.PrimitiveBackgroundColor) mi.SetInputCapture(mi.onInputCapture) - mi.SetTitleAlign(tview.AlignLeft) padding := cfg.Theme.MessageInput.BorderPadding diff --git a/messages_text.go b/messages_text.go index 1b9d9a0..efd94af 100644 --- a/messages_text.go +++ b/messages_text.go @@ -69,6 +69,9 @@ func (mt *MessagesText) newMessage(m *discord.Message) error { // Content mt.newContent(m) + // Attachments + mt.newAttachments(m) + // Tags with no region ID ([""]) don't start new regions. They can therefore be used to mark the end of a region. fmt.Fprint(mt, `[""]`) } @@ -89,6 +92,12 @@ func (mt *MessagesText) newContent(m *discord.Message) { fmt.Fprint(mt, tview.Escape(m.Content)) } +func (mt *MessagesText) newAttachments(m *discord.Message) { + for _, a := range m.Attachments { + fmt.Fprintf(mt, "\n[%s]: %s", a.Filename, a.URL) + } +} + func (mt *MessagesText) onHighlighted(added, removed, remaining []string) { if len(added) == 0 { return From b03b880efcff756b36333c83f0ae0dbca665a8d9 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sat, 7 Jan 2023 13:36:01 +0530 Subject: [PATCH 33/70] Title color --- config.go | 4 ++++ go.mod | 4 ++++ go.sum | 18 ++++++++++++++++++ guilds_tree.go | 2 ++ main.go | 5 +++++ message_input.go | 2 ++ messages_text.go | 1 + 7 files changed, 36 insertions(+) diff --git a/config.go b/config.go index f00a440..20a2792 100644 --- a/config.go +++ b/config.go @@ -35,6 +35,8 @@ type ( CommonThemeConfig struct { Border bool `yaml:"border"` BorderPadding [4]int `yaml:"border_padding,flow"` + + TitleColor string `yaml:"title_color"` } GuildsTreeThemeConfig struct { @@ -80,6 +82,8 @@ func newConfig() (*Config, error) { commonTheme := CommonThemeConfig{ Border: true, BorderPadding: [...]int{0, 0, 1, 1}, + + TitleColor: "gold", } commonKeys := CommonKeysConfig{ diff --git a/go.mod b/go.mod index aeb1d2c..a69ae51 100644 --- a/go.mod +++ b/go.mod @@ -6,11 +6,15 @@ require ( github.com/diamondburned/arikawa/v3 v3.2.0 github.com/gdamore/tcell/v2 v2.5.4 github.com/rivo/tview v0.0.0-20230104153304-892d1a2eb0da + github.com/zalando/go-keyring v0.2.2 gopkg.in/yaml.v3 v3.0.1 ) require ( + github.com/alessio/shellescape v1.4.1 // indirect + github.com/danieljoos/wincred v1.1.2 // indirect github.com/gdamore/encoding v1.0.0 // indirect + github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gorilla/schema v1.2.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect diff --git a/go.sum b/go.sum index 5453662..a08e014 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,17 @@ +github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= +github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= +github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= +github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/diamondburned/arikawa/v3 v3.2.0 h1:aBUhg94pxblT6ks4EV7qxEk44tnl0ico67ydqjVnv9g= github.com/diamondburned/arikawa/v3 v3.2.0/go.mod h1:5jBSNnp82Z/EhsKa6Wk9FsOqSxfVkNZDTDBPOj47LpY= 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.5.4 h1:TGU4tSjD3sCL788vFNeJnTdzpNKIw1H5dgLnJRQVv/k= github.com/gdamore/tcell/v2 v2.5.4/go.mod h1:dZgRy5v4iMobMEcWNYBtREnDZAT9DYmfqIkrgEMxLyw= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc= github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -15,12 +23,20 @@ github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWV github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/tview v0.0.0-20230104153304-892d1a2eb0da h1:3Mh+tcC2KqetuHpWMurDeF+yOgyt4w4qtLIpwSQ3uqo= github.com/rivo/tview v0.0.0-20230104153304-892d1a2eb0da/go.mod h1:lBUy/T5kyMudFzWUH/C2moN+NlU5qF505vzOyINXuUQ= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw= github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zalando/go-keyring v0.2.2 h1:f0xmpYiSrHtSNAVgwip93Cg8tuF45HJM6rHq/A5RI/4= +github.com/zalando/go-keyring v0.2.2/go.mod h1:sI3evg9Wvpw3+n4SqplGSJUMwtDeROfD4nsFz4z9PG0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -32,6 +48,7 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211001092434-39dca1131b70/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -56,5 +73,6 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/guilds_tree.go b/guilds_tree.go index 5ef6113..97e1d7e 100644 --- a/guilds_tree.go +++ b/guilds_tree.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/diamondburned/arikawa/v3/discord" + "github.com/gdamore/tcell/v2" "github.com/rivo/tview" ) @@ -29,6 +30,7 @@ func newGuildsTree() *GuildsTree { gt.SetSelectedFunc(gt.onSelected) gt.SetTitle("Guilds") + gt.SetTitleColor(tcell.GetColor(cfg.Theme.MessagesText.TitleColor)) gt.SetTitleAlign(tview.AlignLeft) padding := cfg.Theme.GuildsTree.BorderPadding diff --git a/main.go b/main.go index e15f23b..d249aa7 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,7 @@ import ( "log" "github.com/rivo/tview" + "github.com/zalando/go-keyring" ) var ( @@ -29,6 +30,10 @@ func init() { func main() { flag.Parse() + if token != "" { + go keyring.Set(name, "token", token) + } + var err error cfg, err = newConfig() if err != nil { diff --git a/message_input.go b/message_input.go index 29d23fe..5d3adb8 100644 --- a/message_input.go +++ b/message_input.go @@ -22,6 +22,8 @@ func newMessageInput() *MessageInput { mi.SetFieldBackgroundColor(tview.Styles.PrimitiveBackgroundColor) mi.SetInputCapture(mi.onInputCapture) + + mi.SetTitleColor(tcell.GetColor(cfg.Theme.MessagesText.TitleColor)) mi.SetTitleAlign(tview.AlignLeft) padding := cfg.Theme.MessageInput.BorderPadding diff --git a/messages_text.go b/messages_text.go index efd94af..79297bb 100644 --- a/messages_text.go +++ b/messages_text.go @@ -29,6 +29,7 @@ func newMessagesText() *MessagesText { mt.SetInputCapture(mt.onInputCapture) mt.SetTitle("Messages") + mt.SetTitleColor(tcell.GetColor(cfg.Theme.MessagesText.TitleColor)) mt.SetTitleAlign(tview.AlignLeft) padding := cfg.Theme.MessagesText.BorderPadding From 47c19078f1dcc57674e1b0a1de0aa1f4fd4c1290 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sat, 7 Jan 2023 13:37:17 +0530 Subject: [PATCH 34/70] Change default title color to terminal default --- config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.go b/config.go index 20a2792..7e50d8c 100644 --- a/config.go +++ b/config.go @@ -83,7 +83,7 @@ func newConfig() (*Config, error) { Border: true, BorderPadding: [...]int{0, 0, 1, 1}, - TitleColor: "gold", + TitleColor: "default", } commonKeys := CommonKeysConfig{ From 95df8371e9d3991eb706c0dd4dababc83b3f157e Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sat, 7 Jan 2023 13:48:01 +0530 Subject: [PATCH 35/70] Remove go-keyring --- go.mod | 4 ---- go.sum | 18 ------------------ main.go | 5 ----- 3 files changed, 27 deletions(-) diff --git a/go.mod b/go.mod index a69ae51..aeb1d2c 100644 --- a/go.mod +++ b/go.mod @@ -6,15 +6,11 @@ require ( github.com/diamondburned/arikawa/v3 v3.2.0 github.com/gdamore/tcell/v2 v2.5.4 github.com/rivo/tview v0.0.0-20230104153304-892d1a2eb0da - github.com/zalando/go-keyring v0.2.2 gopkg.in/yaml.v3 v3.0.1 ) require ( - github.com/alessio/shellescape v1.4.1 // indirect - github.com/danieljoos/wincred v1.1.2 // indirect github.com/gdamore/encoding v1.0.0 // indirect - github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gorilla/schema v1.2.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect diff --git a/go.sum b/go.sum index a08e014..5453662 100644 --- a/go.sum +++ b/go.sum @@ -1,17 +1,9 @@ -github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= -github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= -github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= -github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/diamondburned/arikawa/v3 v3.2.0 h1:aBUhg94pxblT6ks4EV7qxEk44tnl0ico67ydqjVnv9g= github.com/diamondburned/arikawa/v3 v3.2.0/go.mod h1:5jBSNnp82Z/EhsKa6Wk9FsOqSxfVkNZDTDBPOj47LpY= 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.5.4 h1:TGU4tSjD3sCL788vFNeJnTdzpNKIw1H5dgLnJRQVv/k= github.com/gdamore/tcell/v2 v2.5.4/go.mod h1:dZgRy5v4iMobMEcWNYBtREnDZAT9DYmfqIkrgEMxLyw= -github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= -github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc= github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -23,20 +15,12 @@ github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWV github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/tview v0.0.0-20230104153304-892d1a2eb0da h1:3Mh+tcC2KqetuHpWMurDeF+yOgyt4w4qtLIpwSQ3uqo= github.com/rivo/tview v0.0.0-20230104153304-892d1a2eb0da/go.mod h1:lBUy/T5kyMudFzWUH/C2moN+NlU5qF505vzOyINXuUQ= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw= github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zalando/go-keyring v0.2.2 h1:f0xmpYiSrHtSNAVgwip93Cg8tuF45HJM6rHq/A5RI/4= -github.com/zalando/go-keyring v0.2.2/go.mod h1:sI3evg9Wvpw3+n4SqplGSJUMwtDeROfD4nsFz4z9PG0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -48,7 +32,6 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211001092434-39dca1131b70/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -73,6 +56,5 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go index d249aa7..e15f23b 100644 --- a/main.go +++ b/main.go @@ -6,7 +6,6 @@ import ( "log" "github.com/rivo/tview" - "github.com/zalando/go-keyring" ) var ( @@ -30,10 +29,6 @@ func init() { func main() { flag.Parse() - if token != "" { - go keyring.Set(name, "token", token) - } - var err error cfg, err = newConfig() if err != nil { From 087e4391ed626cd3c5c3dd522311cd90f73ef043 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sat, 7 Jan 2023 14:20:20 +0530 Subject: [PATCH 36/70] Add background color to ThemeConfig --- config.go | 6 ++++-- guilds_tree.go | 4 +++- message_input.go | 4 +++- messages_text.go | 2 ++ 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/config.go b/config.go index 7e50d8c..202fb21 100644 --- a/config.go +++ b/config.go @@ -36,7 +36,8 @@ type ( Border bool `yaml:"border"` BorderPadding [4]int `yaml:"border_padding,flow"` - TitleColor string `yaml:"title_color"` + TitleColor string `yaml:"title_color"` + BackgroundColor string `yaml:"background_color"` } GuildsTreeThemeConfig struct { @@ -83,7 +84,8 @@ func newConfig() (*Config, error) { Border: true, BorderPadding: [...]int{0, 0, 1, 1}, - TitleColor: "default", + TitleColor: "default", + BackgroundColor: "default", } commonKeys := CommonKeysConfig{ diff --git a/guilds_tree.go b/guilds_tree.go index 97e1d7e..06a8db3 100644 --- a/guilds_tree.go +++ b/guilds_tree.go @@ -29,8 +29,10 @@ func newGuildsTree() *GuildsTree { gt.SetTopLevel(1) gt.SetSelectedFunc(gt.onSelected) + gt.SetBackgroundColor(tcell.GetColor(cfg.Theme.GuildsTree.BackgroundColor)) + gt.SetTitle("Guilds") - gt.SetTitleColor(tcell.GetColor(cfg.Theme.MessagesText.TitleColor)) + gt.SetTitleColor(tcell.GetColor(cfg.Theme.GuildsTree.TitleColor)) gt.SetTitleAlign(tview.AlignLeft) padding := cfg.Theme.GuildsTree.BorderPadding diff --git a/message_input.go b/message_input.go index 5d3adb8..52e4844 100644 --- a/message_input.go +++ b/message_input.go @@ -23,7 +23,9 @@ func newMessageInput() *MessageInput { mi.SetFieldBackgroundColor(tview.Styles.PrimitiveBackgroundColor) mi.SetInputCapture(mi.onInputCapture) - mi.SetTitleColor(tcell.GetColor(cfg.Theme.MessagesText.TitleColor)) + mi.SetBackgroundColor(tcell.GetColor(cfg.Theme.MessageInput.BackgroundColor)) + + mi.SetTitleColor(tcell.GetColor(cfg.Theme.MessageInput.TitleColor)) mi.SetTitleAlign(tview.AlignLeft) padding := cfg.Theme.MessageInput.BorderPadding diff --git a/messages_text.go b/messages_text.go index 79297bb..16c6eff 100644 --- a/messages_text.go +++ b/messages_text.go @@ -28,6 +28,8 @@ func newMessagesText() *MessagesText { mt.SetHighlightedFunc(mt.onHighlighted) mt.SetInputCapture(mt.onInputCapture) + mt.SetBackgroundColor(tcell.GetColor(cfg.Theme.MessagesText.BackgroundColor)) + mt.SetTitle("Messages") mt.SetTitleColor(tcell.GetColor(cfg.Theme.MessagesText.TitleColor)) mt.SetTitleAlign(tview.AlignLeft) From a8ecb1336748da71b5267ecb1c370f0bddd186d5 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sat, 7 Jan 2023 14:22:01 +0530 Subject: [PATCH 37/70] Set message input field background color as background color --- message_input.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/message_input.go b/message_input.go index 52e4844..7216ff6 100644 --- a/message_input.go +++ b/message_input.go @@ -20,9 +20,8 @@ func newMessageInput() *MessageInput { InputField: tview.NewInputField(), } - mi.SetFieldBackgroundColor(tview.Styles.PrimitiveBackgroundColor) mi.SetInputCapture(mi.onInputCapture) - + mi.SetFieldBackgroundColor(tcell.GetColor(cfg.Theme.MessageInput.BackgroundColor)) mi.SetBackgroundColor(tcell.GetColor(cfg.Theme.MessageInput.BackgroundColor)) mi.SetTitleColor(tcell.GetColor(cfg.Theme.MessageInput.TitleColor)) From fc0b9a03eba065f50a3e9ecee765beea7838f29b Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sat, 7 Jan 2023 23:04:21 +0530 Subject: [PATCH 38/70] Markdown parser --- discordmd/discordmd.go | 20 ++++++++++++++++++++ discordmd/discordmd_test.go | 14 ++++++++++++++ guilds_tree.go | 14 +++++++------- messages_text.go | 3 ++- state.go | 4 ++-- 5 files changed, 45 insertions(+), 10 deletions(-) create mode 100644 discordmd/discordmd.go create mode 100644 discordmd/discordmd_test.go diff --git a/discordmd/discordmd.go b/discordmd/discordmd.go new file mode 100644 index 0000000..37cf095 --- /dev/null +++ b/discordmd/discordmd.go @@ -0,0 +1,20 @@ +package discordmd + +import ( + "regexp" +) + +var ( + boldRegex = regexp.MustCompile(`(?ms)\*\*(.*?)\*\*`) + italicRegex = regexp.MustCompile(`(?ms)\*(.*?)\*`) + underlineRegex = regexp.MustCompile(`(?ms)__(.*?)__`) + strikeThroughRegex = regexp.MustCompile(`(?ms)~~(.*?)~~`) +) + +func Parse(input string) string { + input = boldRegex.ReplaceAllString(input, "[::b]$1[::-]") + input = italicRegex.ReplaceAllString(input, "[::i]$1[::-]") + input = underlineRegex.ReplaceAllString(input, "[::u]$1[::-]") + input = strikeThroughRegex.ReplaceAllString(input, "[::s]$1[::-]") + return input +} diff --git a/discordmd/discordmd_test.go b/discordmd/discordmd_test.go new file mode 100644 index 0000000..5f7a42b --- /dev/null +++ b/discordmd/discordmd_test.go @@ -0,0 +1,14 @@ +package discordmd + +import ( + "testing" +) + +func TestParse(t *testing.T) { + const input = `**Lorem** ipsum dolor sit amet, consectetur adipiscing __elit.__ Nullam ante magna, luctus in ~~molestie non, elementum sit~~ amet tortor. Nunc euismod urna ac massa dictum ultrices. Donec tempor __dignissim__ ullamcorper. Mauris ultricies, risus non malesuada consectetur, *purus leo interdum purus*, nec vestibulum lacus neque non nulla.` + const want = `[::b]Lorem[::-] ipsum dolor sit amet, consectetur adipiscing [::u]elit.[::-] Nullam ante magna, luctus in [::s]molestie non, elementum sit[::-] amet tortor. Nunc euismod urna ac massa dictum ultrices. Donec tempor [::u]dignissim[::-] ullamcorper. Mauris ultricies, risus non malesuada consectetur, [::i]purus leo interdum purus[::-], nec vestibulum lacus neque non nulla.` + + if got := Parse(input); got != want { + t.Errorf("got %s; want %s", got, want) + } +} diff --git a/guilds_tree.go b/guilds_tree.go index 06a8db3..6d74013 100644 --- a/guilds_tree.go +++ b/guilds_tree.go @@ -42,7 +42,7 @@ func newGuildsTree() *GuildsTree { return gt } -func (gt *GuildsTree) newGuildFromID(n *tview.TreeNode, gid discord.GuildID) error { +func (gt *GuildsTree) createGuildNodeFromID(n *tview.TreeNode, gid discord.GuildID) error { g, err := discordState.Cabinet.Guild(gid) if err != nil { return err @@ -54,7 +54,7 @@ func (gt *GuildsTree) newGuildFromID(n *tview.TreeNode, gid discord.GuildID) err return nil } -func (gt *GuildsTree) newChannel(n *tview.TreeNode, c discord.Channel) { +func (gt *GuildsTree) createChannelNode(n *tview.TreeNode, c discord.Channel) { cn := tview.NewTreeNode(gt.channelToString(c)) cn.SetReference(c.ID) n.AddChild(cn) @@ -121,7 +121,7 @@ func (gt *GuildsTree) onSelected(n *tview.TreeNode) { // Orphan (top-level) channels for _, c := range cs { if c.Type != discord.GuildCategory && !c.ParentID.IsValid() { - gt.newChannel(n, c) + gt.createChannelNode(n, c) } } @@ -131,12 +131,12 @@ func (gt *GuildsTree) onSelected(n *tview.TreeNode) { if c.Type == discord.GuildCategory { for _, nestedChannel := range cs { if nestedChannel.ParentID == c.ID { - gt.newChannel(n, c) + gt.createChannelNode(n, c) continue CATEGORY } } - gt.newChannel(n, c) + gt.createChannelNode(n, c) } } @@ -154,7 +154,7 @@ func (gt *GuildsTree) onSelected(n *tview.TreeNode) { }) if parent != nil { - gt.newChannel(parent, c) + gt.createChannelNode(parent, c) } } } @@ -196,7 +196,7 @@ func (gt *GuildsTree) onSelected(n *tview.TreeNode) { }) for _, c := range cs { - gt.newChannel(n, c) + gt.createChannelNode(n, c) } } } diff --git a/messages_text.go b/messages_text.go index 16c6eff..55e740d 100644 --- a/messages_text.go +++ b/messages_text.go @@ -5,6 +5,7 @@ import ( "log" "time" + "github.com/ayn2op/discordo/discordmd" "github.com/diamondburned/arikawa/v3/discord" "github.com/gdamore/tcell/v2" "github.com/rivo/tview" @@ -92,7 +93,7 @@ func (mt *MessagesText) newTimestamp(m *discord.Message) { } func (mt *MessagesText) newContent(m *discord.Message) { - fmt.Fprint(mt, tview.Escape(m.Content)) + fmt.Fprint(mt, discordmd.Parse(tview.Escape(m.Content))) } func (mt *MessagesText) newAttachments(m *discord.Message) { diff --git a/state.go b/state.go index ec35799..69f6321 100644 --- a/state.go +++ b/state.go @@ -42,7 +42,7 @@ func (s *State) onReady(r *gateway.ReadyEvent) { for _, gf := range r.UserSettings.GuildFolders { /// If the ID of the guild folder is zero, the guild folder only contains single guild. if gf.ID == 0 { - if err := guildsTree.newGuildFromID(guildsTree.root, gf.GuildIDs[0]); err != nil { + if err := guildsTree.createGuildNodeFromID(guildsTree.root, gf.GuildIDs[0]); err != nil { log.Println(err) continue } @@ -51,7 +51,7 @@ func (s *State) onReady(r *gateway.ReadyEvent) { guildsTree.root.AddChild(gfNode) for _, gid := range gf.GuildIDs { - if err := guildsTree.newGuildFromID(gfNode, gid); err != nil { + if err := guildsTree.createGuildNodeFromID(gfNode, gid); err != nil { log.Println(err) continue } From f51ae4a5d3a6eee3a418860c9106f1cb661f6e68 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sat, 7 Jan 2023 23:23:17 +0530 Subject: [PATCH 39/70] modular --- guilds_tree.go | 87 +++++++++++++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 40 deletions(-) diff --git a/guilds_tree.go b/guilds_tree.go index 6d74013..3dabdde 100644 --- a/guilds_tree.go +++ b/guilds_tree.go @@ -92,6 +92,50 @@ func (gt *GuildsTree) channelToString(c discord.Channel) string { return s } +func (gt *GuildsTree) createOrphanChannelNodes(n *tview.TreeNode, cs []discord.Channel) { + for _, c := range cs { + if c.Type != discord.GuildCategory && !c.ParentID.IsValid() { + gt.createChannelNode(n, c) + } + } +} + +func (gt *GuildsTree) createParentChannelNodes(n *tview.TreeNode, cs []discord.Channel) { +CATEGORY: + for _, c := range cs { + if c.Type == discord.GuildCategory { + for _, nestedChannel := range cs { + if nestedChannel.ParentID == c.ID { + gt.createChannelNode(n, c) + continue CATEGORY + } + } + + gt.createChannelNode(n, c) + } + } +} + +func (gt *GuildsTree) createChildrenChannelNodes(n *tview.TreeNode, cs []discord.Channel) { + for _, c := range cs { + if c.Type != discord.GuildCategory && c.ParentID.IsValid() { + var parent *tview.TreeNode + n.Walk(func(node, _ *tview.TreeNode) bool { + if node.GetReference() == c.ParentID { + parent = node + return false + } + + return true + }) + + if parent != nil { + gt.createChannelNode(parent, c) + } + } + } +} + func (gt *GuildsTree) onSelected(n *tview.TreeNode) { gt.selectedChannel = nil @@ -118,46 +162,9 @@ func (gt *GuildsTree) onSelected(n *tview.TreeNode) { return cs[i].Position < cs[j].Position }) - // Orphan (top-level) channels - for _, c := range cs { - if c.Type != discord.GuildCategory && !c.ParentID.IsValid() { - gt.createChannelNode(n, c) - } - } - - // Category channels - CATEGORY: - for _, c := range cs { - if c.Type == discord.GuildCategory { - for _, nestedChannel := range cs { - if nestedChannel.ParentID == c.ID { - gt.createChannelNode(n, c) - continue CATEGORY - } - } - - gt.createChannelNode(n, c) - } - } - - // Children (category-bound) channels - for _, c := range cs { - if c.Type != discord.GuildCategory && c.ParentID.IsValid() { - var parent *tview.TreeNode - n.Walk(func(node, _ *tview.TreeNode) bool { - if node.GetReference() == c.ParentID { - parent = node - return false - } - - return true - }) - - if parent != nil { - gt.createChannelNode(parent, c) - } - } - } + gt.createOrphanChannelNodes(n, cs) + gt.createParentChannelNodes(n, cs) + gt.createChildrenChannelNodes(n, cs) case discord.ChannelID: messagesText.Clear() From 02538a08a71c9d40a87f32624241038fc2893eda Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 8 Jan 2023 00:00:58 +0530 Subject: [PATCH 40/70] Add benchmark --- discordmd/discordmd_test.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/discordmd/discordmd_test.go b/discordmd/discordmd_test.go index 5f7a42b..a6ff2f4 100644 --- a/discordmd/discordmd_test.go +++ b/discordmd/discordmd_test.go @@ -4,11 +4,18 @@ import ( "testing" ) +const input = `**Lorem** ipsum dolor sit amet, consectetur adipiscing __elit.__ Nullam ante magna, luctus in ~~molestie non, elementum sit~~ amet tortor. Nunc euismod urna ac massa dictum ultrices. Donec tempor __dignissim__ ullamcorper. Mauris ultricies, risus non malesuada consectetur, *purus leo interdum purus*, nec vestibulum lacus neque non nulla.` + func TestParse(t *testing.T) { - const input = `**Lorem** ipsum dolor sit amet, consectetur adipiscing __elit.__ Nullam ante magna, luctus in ~~molestie non, elementum sit~~ amet tortor. Nunc euismod urna ac massa dictum ultrices. Donec tempor __dignissim__ ullamcorper. Mauris ultricies, risus non malesuada consectetur, *purus leo interdum purus*, nec vestibulum lacus neque non nulla.` const want = `[::b]Lorem[::-] ipsum dolor sit amet, consectetur adipiscing [::u]elit.[::-] Nullam ante magna, luctus in [::s]molestie non, elementum sit[::-] amet tortor. Nunc euismod urna ac massa dictum ultrices. Donec tempor [::u]dignissim[::-] ullamcorper. Mauris ultricies, risus non malesuada consectetur, [::i]purus leo interdum purus[::-], nec vestibulum lacus neque non nulla.` if got := Parse(input); got != want { t.Errorf("got %s; want %s", got, want) } } + +func BenchmarkParse(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = Parse(input) + } +} From 0cbd72807ba6ef4750dbbe72e95745aa173316ae Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 8 Jan 2023 00:29:51 +0530 Subject: [PATCH 41/70] Focus input on channel selected --- guilds_tree.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guilds_tree.go b/guilds_tree.go index 3dabdde..a9b40cd 100644 --- a/guilds_tree.go +++ b/guilds_tree.go @@ -190,7 +190,7 @@ func (gt *GuildsTree) onSelected(n *tview.TreeNode) { } } - app.SetFocus(messagesText) + app.SetFocus(messageInput) case nil: // Direct messages cs, err := discordState.Cabinet.PrivateChannels() if err != nil { From 1972f0aa15ac327becf9104ba1a6bbc6a271a198 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 8 Jan 2023 00:33:35 +0530 Subject: [PATCH 42/70] title = '' & clear --- guilds_tree.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/guilds_tree.go b/guilds_tree.go index a9b40cd..73fdfb4 100644 --- a/guilds_tree.go +++ b/guilds_tree.go @@ -140,6 +140,8 @@ func (gt *GuildsTree) onSelected(n *tview.TreeNode) { gt.selectedChannel = nil messagesText.selectedMessage = nil + messagesText.Clear() + messagesText.SetTitle("") messagesText.Highlight() messageInput.SetTitle("") @@ -166,8 +168,6 @@ func (gt *GuildsTree) onSelected(n *tview.TreeNode) { gt.createParentChannelNodes(n, cs) gt.createChildrenChannelNodes(n, cs) case discord.ChannelID: - messagesText.Clear() - c, err := discordState.Cabinet.Channel(ref) if err != nil { log.Println(err) From eca4ab3999a86054725448f446cea0537df58939 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 8 Jan 2023 13:27:51 +0530 Subject: [PATCH 43/70] Unload channel on messages text cancel --- messages_text.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/messages_text.go b/messages_text.go index 55e740d..1cbaa0e 100644 --- a/messages_text.go +++ b/messages_text.go @@ -132,6 +132,15 @@ func (mt *MessagesText) onInputCapture(event *tcell.EventKey) *tcell.EventKey { return nil case cfg.Keys.MessagesText.Cancel: // TODO + guildsTree.selectedChannel = nil + + mt.selectedMessage = nil + mt.Clear() + mt.SetTitle("") + mt.Highlight() + + messageInput.SetText("") + messageInput.SetTitle("") return nil } From 57cd2824d4d517e1c91f10215844621b10575057 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 8 Jan 2023 14:16:31 +0530 Subject: [PATCH 44/70] rewrite --- config.go | 15 ++++++++----- discordmd/discordmd_test.go | 3 ++- guilds_tree.go | 4 +++- main.go | 7 ++++-- messages_text.go | 44 +++++++++++++++++++++++++++---------- state.go | 9 +++++--- 6 files changed, 58 insertions(+), 24 deletions(-) diff --git a/config.go b/config.go index 202fb21..093485d 100644 --- a/config.go +++ b/config.go @@ -47,6 +47,7 @@ type ( MessagesTextThemeConfig struct { CommonThemeConfig `yaml:",inline"` + AuthorColor string `yaml:"author_color"` } MessageInputThemeConfig struct { @@ -76,7 +77,8 @@ func newConfig() (*Config, error) { } path = filepath.Join(path, name) - if err = os.MkdirAll(path, os.ModePerm); err != nil { + err = os.MkdirAll(path, os.ModePerm) + if err != nil { return nil, err } @@ -116,6 +118,7 @@ func newConfig() (*Config, error) { }, MessagesText: MessagesTextThemeConfig{ CommonThemeConfig: commonTheme, + AuthorColor: "aqua", }, MessageInput: MessageInputThemeConfig{ CommonThemeConfig: commonTheme, @@ -123,15 +126,16 @@ func newConfig() (*Config, error) { }, } path = filepath.Join(path, "config.yml") - if _, err = os.Stat(path); os.IsNotExist(err) { + _, err = os.Stat(path) + if os.IsNotExist(err) { f, err := os.Create(path) if err != nil { return nil, err } defer f.Close() - e := yaml.NewEncoder(f) - if err = e.Encode(c); err != nil { + err = yaml.NewEncoder(f).Encode(c) + if err != nil { return nil, err } } else { @@ -141,7 +145,8 @@ func newConfig() (*Config, error) { } defer f.Close() - if err = yaml.NewDecoder(f).Decode(&c); err != nil { + err = yaml.NewDecoder(f).Decode(&c) + if err != nil { return nil, err } } diff --git a/discordmd/discordmd_test.go b/discordmd/discordmd_test.go index a6ff2f4..cd2eadc 100644 --- a/discordmd/discordmd_test.go +++ b/discordmd/discordmd_test.go @@ -9,7 +9,8 @@ const input = `**Lorem** ipsum dolor sit amet, consectetur adipiscing __elit.__ func TestParse(t *testing.T) { const want = `[::b]Lorem[::-] ipsum dolor sit amet, consectetur adipiscing [::u]elit.[::-] Nullam ante magna, luctus in [::s]molestie non, elementum sit[::-] amet tortor. Nunc euismod urna ac massa dictum ultrices. Donec tempor [::u]dignissim[::-] ullamcorper. Mauris ultricies, risus non malesuada consectetur, [::i]purus leo interdum purus[::-], nec vestibulum lacus neque non nulla.` - if got := Parse(input); got != want { + got := Parse(input) + if got != want { t.Errorf("got %s; want %s", got, want) } } diff --git a/guilds_tree.go b/guilds_tree.go index 73fdfb4..ab2de7a 100644 --- a/guilds_tree.go +++ b/guilds_tree.go @@ -184,12 +184,14 @@ func (gt *GuildsTree) onSelected(n *tview.TreeNode) { } for i := len(ms) - 1; i >= 0; i-- { - if messagesText.newMessage(&ms[i]); err != nil { + err = messagesText.newMessage(&ms[i]) + if err != nil { log.Println(err) continue } } + messagesText.ScrollToEnd() app.SetFocus(messageInput) case nil: // Direct messages cs, err := discordState.Cabinet.PrivateChannels() diff --git a/main.go b/main.go index e15f23b..e8d85b3 100644 --- a/main.go +++ b/main.go @@ -41,7 +41,8 @@ func main() { messageInput = newMessageInput() discordState = newState(token) - if err = discordState.Open(context.Background()); err != nil { + err = discordState.Open(context.Background()) + if err != nil { log.Fatal(err) } @@ -55,7 +56,9 @@ func main() { app.EnableMouse(cfg.Mouse) app.SetRoot(flex, true) - if err = app.Run(); err != nil { + + err = app.Run() + if err != nil { log.Fatal(err) } } diff --git a/messages_text.go b/messages_text.go index 1cbaa0e..c6f6512 100644 --- a/messages_text.go +++ b/messages_text.go @@ -1,7 +1,7 @@ package main import ( - "fmt" + "bytes" "log" "time" @@ -11,9 +11,12 @@ import ( "github.com/rivo/tview" ) +const replyIndicator = '╭' + type MessagesText struct { *tview.TextView + buffer bytes.Buffer selectedMessage *discord.Message } @@ -43,14 +46,20 @@ func newMessagesText() *MessagesText { } func (mt *MessagesText) newMessage(m *discord.Message) error { + mt.buffer.Reset() + switch m.Type { case discord.DefaultMessage, discord.InlinedReplyMessage: // Region tags are square brackets that contain a region ID in double quotes // https://pkg.go.dev/github.com/rivo/tview#hdr-Regions_and_Highlights - fmt.Fprintf(mt, `["%s"]`, m.ID) + mt.buffer.WriteString(`["`) + mt.buffer.WriteString(m.ID.String()) + mt.buffer.WriteString(`"]`) if m.ReferencedMessage != nil { - fmt.Fprint(mt, "[::d] ╭ ") + mt.buffer.WriteString("[::d] ") + mt.buffer.WriteRune(replyIndicator) + mt.buffer.WriteByte(' ') // Author mt.newAuthor(m.ReferencedMessage) @@ -58,8 +67,7 @@ func (mt *MessagesText) newMessage(m *discord.Message) error { // Content mt.newContent(m.ReferencedMessage) - fmt.Fprint(mt, "[::-]") - fmt.Fprintln(mt) + mt.buffer.WriteString("[::-]\n") } if cfg.Timestamps { @@ -77,28 +85,40 @@ func (mt *MessagesText) newMessage(m *discord.Message) error { mt.newAttachments(m) // Tags with no region ID ([""]) don't start new regions. They can therefore be used to mark the end of a region. - fmt.Fprint(mt, `[""]`) + mt.buffer.WriteString(`[""]`) + mt.buffer.WriteByte('\n') } - fmt.Fprintln(mt) - return nil + _, err := mt.buffer.WriteTo(mt) + return err } func (mt *MessagesText) newAuthor(m *discord.Message) { - fmt.Fprintf(mt, "[blue]%s[-] ", m.Author.Username) + mt.buffer.WriteByte('[') + mt.buffer.WriteString(cfg.Theme.MessagesText.AuthorColor) + mt.buffer.WriteByte(']') + mt.buffer.WriteString(m.Author.Username) + mt.buffer.WriteString("[-] ") } func (mt *MessagesText) newTimestamp(m *discord.Message) { - fmt.Fprintf(mt, "[::d]%s[::-] ", m.Timestamp.Format(time.Kitchen)) + mt.buffer.WriteString("[::d]") + mt.buffer.WriteString(m.Timestamp.Format(time.Kitchen)) + mt.buffer.WriteString("[::-] ") } func (mt *MessagesText) newContent(m *discord.Message) { - fmt.Fprint(mt, discordmd.Parse(tview.Escape(m.Content))) + mt.buffer.WriteString(discordmd.Parse(tview.Escape(m.Content))) } func (mt *MessagesText) newAttachments(m *discord.Message) { for _, a := range m.Attachments { - fmt.Fprintf(mt, "\n[%s]: %s", a.Filename, a.URL) + mt.buffer.WriteByte('\n') + + mt.buffer.WriteByte('[') + mt.buffer.WriteString(a.Filename) + mt.buffer.WriteString("]: ") + mt.buffer.WriteString(a.URL) } } diff --git a/state.go b/state.go index 69f6321..f4bf7e3 100644 --- a/state.go +++ b/state.go @@ -42,7 +42,8 @@ func (s *State) onReady(r *gateway.ReadyEvent) { for _, gf := range r.UserSettings.GuildFolders { /// If the ID of the guild folder is zero, the guild folder only contains single guild. if gf.ID == 0 { - if err := guildsTree.createGuildNodeFromID(guildsTree.root, gf.GuildIDs[0]); err != nil { + err := guildsTree.createGuildNodeFromID(guildsTree.root, gf.GuildIDs[0]) + if err != nil { log.Println(err) continue } @@ -51,7 +52,8 @@ func (s *State) onReady(r *gateway.ReadyEvent) { guildsTree.root.AddChild(gfNode) for _, gid := range gf.GuildIDs { - if err := guildsTree.createGuildNodeFromID(gfNode, gid); err != nil { + err := guildsTree.createGuildNodeFromID(gfNode, gid) + if err != nil { log.Println(err) continue } @@ -65,7 +67,8 @@ func (s *State) onReady(r *gateway.ReadyEvent) { func (s *State) onMessageCreate(m *gateway.MessageCreateEvent) { if guildsTree.selectedChannel != nil && guildsTree.selectedChannel.ID == m.ChannelID { - if err := messagesText.newMessage(&m.Message); err != nil { + err := messagesText.newMessage(&m.Message) + if err != nil { log.Println(err) return } From ab3f26c394f15c2af440183a9bc6c2598efa205e Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 8 Jan 2023 14:23:03 +0530 Subject: [PATCH 45/70] reset method --- guilds_tree.go | 9 ++------- message_input.go | 12 +++++++++--- messages_text.go | 17 ++++++++++------- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/guilds_tree.go b/guilds_tree.go index ab2de7a..e09adbe 100644 --- a/guilds_tree.go +++ b/guilds_tree.go @@ -139,13 +139,8 @@ func (gt *GuildsTree) createChildrenChannelNodes(n *tview.TreeNode, cs []discord func (gt *GuildsTree) onSelected(n *tview.TreeNode) { gt.selectedChannel = nil - messagesText.selectedMessage = nil - messagesText.Clear() - messagesText.SetTitle("") - messagesText.Highlight() - - messageInput.SetTitle("") - messageInput.SetText("") + messagesText.reset() + messageInput.reset() if len(n.GetChildren()) != 0 { n.SetExpanded(!n.IsExpanded()) diff --git a/message_input.go b/message_input.go index 7216ff6..ad6b100 100644 --- a/message_input.go +++ b/message_input.go @@ -34,11 +34,19 @@ func newMessageInput() *MessageInput { return mi } +func (mi *MessageInput) reset() { + mi.SetTitle("") + mi.SetText("") +} + func (mi *MessageInput) onInputCapture(event *tcell.EventKey) *tcell.EventKey { switch event.Name() { case cfg.Keys.MessageInput.Send: mi.sendAction() return nil + case cfg.Keys.MessageInput.Cancel: + mi.reset() + return nil } return event @@ -82,7 +90,5 @@ func (mi *MessageInput) sendAction() { return } - // Reset the message input. - mi.SetTitle("") - mi.SetText("") + messageInput.reset() } diff --git a/messages_text.go b/messages_text.go index c6f6512..db42aac 100644 --- a/messages_text.go +++ b/messages_text.go @@ -45,6 +45,14 @@ func newMessagesText() *MessagesText { return mt } +func (mt *MessagesText) reset() { + messagesText.selectedMessage = nil + + mt.SetTitle("") + mt.Clear() + mt.Highlight() +} + func (mt *MessagesText) newMessage(m *discord.Message) error { mt.buffer.Reset() @@ -154,13 +162,8 @@ func (mt *MessagesText) onInputCapture(event *tcell.EventKey) *tcell.EventKey { // TODO guildsTree.selectedChannel = nil - mt.selectedMessage = nil - mt.Clear() - mt.SetTitle("") - mt.Highlight() - - messageInput.SetText("") - messageInput.SetTitle("") + messagesText.reset() + messageInput.reset() return nil } From 0889c93e40f3cea0981998dda78120db2331bdad Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 8 Jan 2023 14:31:42 +0530 Subject: [PATCH 46/70] use strings.Builder instead of bytes.Buffer --- messages_text.go | 55 ++++++++++++++++++++++++------------------------ out.log | 1 + 2 files changed, 29 insertions(+), 27 deletions(-) create mode 100644 out.log diff --git a/messages_text.go b/messages_text.go index db42aac..60c8ec6 100644 --- a/messages_text.go +++ b/messages_text.go @@ -1,8 +1,9 @@ package main import ( - "bytes" + "fmt" "log" + "strings" "time" "github.com/ayn2op/discordo/discordmd" @@ -16,7 +17,7 @@ const replyIndicator = '╭' type MessagesText struct { *tview.TextView - buffer bytes.Buffer + builder strings.Builder selectedMessage *discord.Message } @@ -54,20 +55,20 @@ func (mt *MessagesText) reset() { } func (mt *MessagesText) newMessage(m *discord.Message) error { - mt.buffer.Reset() + mt.builder.Reset() switch m.Type { case discord.DefaultMessage, discord.InlinedReplyMessage: // Region tags are square brackets that contain a region ID in double quotes // https://pkg.go.dev/github.com/rivo/tview#hdr-Regions_and_Highlights - mt.buffer.WriteString(`["`) - mt.buffer.WriteString(m.ID.String()) - mt.buffer.WriteString(`"]`) + mt.builder.WriteString(`["`) + mt.builder.WriteString(m.ID.String()) + mt.builder.WriteString(`"]`) if m.ReferencedMessage != nil { - mt.buffer.WriteString("[::d] ") - mt.buffer.WriteRune(replyIndicator) - mt.buffer.WriteByte(' ') + mt.builder.WriteString("[::d] ") + mt.builder.WriteRune(replyIndicator) + mt.builder.WriteByte(' ') // Author mt.newAuthor(m.ReferencedMessage) @@ -75,7 +76,7 @@ func (mt *MessagesText) newMessage(m *discord.Message) error { // Content mt.newContent(m.ReferencedMessage) - mt.buffer.WriteString("[::-]\n") + mt.builder.WriteString("[::-]\n") } if cfg.Timestamps { @@ -93,40 +94,40 @@ func (mt *MessagesText) newMessage(m *discord.Message) error { mt.newAttachments(m) // Tags with no region ID ([""]) don't start new regions. They can therefore be used to mark the end of a region. - mt.buffer.WriteString(`[""]`) - mt.buffer.WriteByte('\n') + mt.builder.WriteString(`[""]`) + mt.builder.WriteByte('\n') } - _, err := mt.buffer.WriteTo(mt) + _, err := fmt.Fprint(mt, mt.builder.String()) return err } func (mt *MessagesText) newAuthor(m *discord.Message) { - mt.buffer.WriteByte('[') - mt.buffer.WriteString(cfg.Theme.MessagesText.AuthorColor) - mt.buffer.WriteByte(']') - mt.buffer.WriteString(m.Author.Username) - mt.buffer.WriteString("[-] ") + mt.builder.WriteByte('[') + mt.builder.WriteString(cfg.Theme.MessagesText.AuthorColor) + mt.builder.WriteByte(']') + mt.builder.WriteString(m.Author.Username) + mt.builder.WriteString("[-] ") } func (mt *MessagesText) newTimestamp(m *discord.Message) { - mt.buffer.WriteString("[::d]") - mt.buffer.WriteString(m.Timestamp.Format(time.Kitchen)) - mt.buffer.WriteString("[::-] ") + mt.builder.WriteString("[::d]") + mt.builder.WriteString(m.Timestamp.Format(time.Kitchen)) + mt.builder.WriteString("[::-] ") } func (mt *MessagesText) newContent(m *discord.Message) { - mt.buffer.WriteString(discordmd.Parse(tview.Escape(m.Content))) + mt.builder.WriteString(discordmd.Parse(tview.Escape(m.Content))) } func (mt *MessagesText) newAttachments(m *discord.Message) { for _, a := range m.Attachments { - mt.buffer.WriteByte('\n') + mt.builder.WriteByte('\n') - mt.buffer.WriteByte('[') - mt.buffer.WriteString(a.Filename) - mt.buffer.WriteString("]: ") - mt.buffer.WriteString(a.URL) + mt.builder.WriteByte('[') + mt.builder.WriteString(a.Filename) + mt.builder.WriteString("]: ") + mt.builder.WriteString(a.URL) } } diff --git a/out.log b/out.log new file mode 100644 index 0000000..1c6d578 --- /dev/null +++ b/out.log @@ -0,0 +1 @@ +2023/01/08 14:31:13 Discord 403 error: Missing Access From c49ee937c9d19c882dcaa81c1d03d50ea564ef13 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 8 Jan 2023 14:31:57 +0530 Subject: [PATCH 47/70] remove out.log --- out.log | 1 - 1 file changed, 1 deletion(-) delete mode 100644 out.log diff --git a/out.log b/out.log deleted file mode 100644 index 1c6d578..0000000 --- a/out.log +++ /dev/null @@ -1 +0,0 @@ -2023/01/08 14:31:13 Discord 403 error: Missing Access From 38f21125dbca3c8b39a6a440128f3b56e7f312a0 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 8 Jan 2023 15:55:02 +0530 Subject: [PATCH 48/70] Inline codeblocks --- discordmd/discordmd.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/discordmd/discordmd.go b/discordmd/discordmd.go index 37cf095..4297ba1 100644 --- a/discordmd/discordmd.go +++ b/discordmd/discordmd.go @@ -5,10 +5,11 @@ import ( ) var ( - boldRegex = regexp.MustCompile(`(?ms)\*\*(.*?)\*\*`) - italicRegex = regexp.MustCompile(`(?ms)\*(.*?)\*`) - underlineRegex = regexp.MustCompile(`(?ms)__(.*?)__`) - strikeThroughRegex = regexp.MustCompile(`(?ms)~~(.*?)~~`) + boldRegex = regexp.MustCompile(`(?ms)\*\*(.*?)\*\*`) + italicRegex = regexp.MustCompile(`(?ms)\*(.*?)\*`) + underlineRegex = regexp.MustCompile(`(?ms)__(.*?)__`) + strikeThroughRegex = regexp.MustCompile(`(?ms)~~(.*?)~~`) + inlineCodeBlockRegex = regexp.MustCompile("(?ms)`" + `([^` + "`" + `\n]+)` + "`") ) func Parse(input string) string { @@ -16,5 +17,6 @@ func Parse(input string) string { input = italicRegex.ReplaceAllString(input, "[::i]$1[::-]") input = underlineRegex.ReplaceAllString(input, "[::u]$1[::-]") input = strikeThroughRegex.ReplaceAllString(input, "[::s]$1[::-]") + input = inlineCodeBlockRegex.ReplaceAllString(input, "[::r]$1[::-]") return input } From 1165513e85e9b34b48aecd6d9796e9971fa68c58 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 8 Jan 2023 18:21:21 +0530 Subject: [PATCH 49/70] bye bye mess --- guilds_tree.go | 35 ++++++----------------------------- 1 file changed, 6 insertions(+), 29 deletions(-) diff --git a/guilds_tree.go b/guilds_tree.go index e09adbe..32751da 100644 --- a/guilds_tree.go +++ b/guilds_tree.go @@ -72,7 +72,7 @@ func (gt *GuildsTree) channelToString(c discord.Channel) string { s = "v-" + c.Name case discord.GroupDM: s = c.Name - // If the name of the channel is empty, use the recipients tags + // If the name of the channel is empty, use the recipients' tags if s == "" { rs := make([]string, len(c.DMRecipients)) for _, r := range c.DMRecipients { @@ -92,33 +92,12 @@ func (gt *GuildsTree) channelToString(c discord.Channel) string { return s } -func (gt *GuildsTree) createOrphanChannelNodes(n *tview.TreeNode, cs []discord.Channel) { +func (gt *GuildsTree) createChannelNodes(n *tview.TreeNode, cs []discord.Channel) { for _, c := range cs { - if c.Type != discord.GuildCategory && !c.ParentID.IsValid() { + // If the type of the channel is guild category or if the channel is an orphan channel. + if c.Type == discord.GuildCategory || !c.ParentID.IsValid() { gt.createChannelNode(n, c) - } - } -} - -func (gt *GuildsTree) createParentChannelNodes(n *tview.TreeNode, cs []discord.Channel) { -CATEGORY: - for _, c := range cs { - if c.Type == discord.GuildCategory { - for _, nestedChannel := range cs { - if nestedChannel.ParentID == c.ID { - gt.createChannelNode(n, c) - continue CATEGORY - } - } - - gt.createChannelNode(n, c) - } - } -} - -func (gt *GuildsTree) createChildrenChannelNodes(n *tview.TreeNode, cs []discord.Channel) { - for _, c := range cs { - if c.Type != discord.GuildCategory && c.ParentID.IsValid() { + } else { var parent *tview.TreeNode n.Walk(func(node, _ *tview.TreeNode) bool { if node.GetReference() == c.ParentID { @@ -159,9 +138,7 @@ func (gt *GuildsTree) onSelected(n *tview.TreeNode) { return cs[i].Position < cs[j].Position }) - gt.createOrphanChannelNodes(n, cs) - gt.createParentChannelNodes(n, cs) - gt.createChildrenChannelNodes(n, cs) + gt.createChannelNodes(n, cs) case discord.ChannelID: c, err := discordState.Cabinet.Channel(ref) if err != nil { From a39264f0484496a135e911805b98a9c8b6375584 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 8 Jan 2023 20:07:20 +0530 Subject: [PATCH 50/70] autoscroll --- guilds_tree.go | 3 +- messages_text.go | 101 +++++++++++++++++++++-------------------------- state.go | 2 +- 3 files changed, 48 insertions(+), 58 deletions(-) diff --git a/guilds_tree.go b/guilds_tree.go index 32751da..188e638 100644 --- a/guilds_tree.go +++ b/guilds_tree.go @@ -156,14 +156,13 @@ func (gt *GuildsTree) onSelected(n *tview.TreeNode) { } for i := len(ms) - 1; i >= 0; i-- { - err = messagesText.newMessage(&ms[i]) + err = messagesText.createMessage(&ms[i]) if err != nil { log.Println(err) continue } } - messagesText.ScrollToEnd() app.SetFocus(messageInput) case nil: // Direct messages cs, err := discordState.Cabinet.PrivateChannels() diff --git a/messages_text.go b/messages_text.go index 60c8ec6..ffc27bc 100644 --- a/messages_text.go +++ b/messages_text.go @@ -1,9 +1,8 @@ package main import ( - "fmt" + "bytes" "log" - "strings" "time" "github.com/ayn2op/discordo/discordmd" @@ -17,8 +16,8 @@ const replyIndicator = '╭' type MessagesText struct { *tview.TextView - builder strings.Builder selectedMessage *discord.Message + buf bytes.Buffer } func newMessagesText() *MessagesText { @@ -29,9 +28,12 @@ func newMessagesText() *MessagesText { mt.SetDynamicColors(true) mt.SetRegions(true) mt.SetWordWrap(true) - mt.ScrollToEnd() mt.SetHighlightedFunc(mt.onHighlighted) mt.SetInputCapture(mt.onInputCapture) + mt.ScrollToEnd() + mt.SetChangedFunc(func() { + app.Draw() + }) mt.SetBackgroundColor(tcell.GetColor(cfg.Theme.MessagesText.BackgroundColor)) @@ -54,80 +56,69 @@ func (mt *MessagesText) reset() { mt.Highlight() } -func (mt *MessagesText) newMessage(m *discord.Message) error { - mt.builder.Reset() - +func (mt *MessagesText) createMessage(m *discord.Message) error { switch m.Type { case discord.DefaultMessage, discord.InlinedReplyMessage: // Region tags are square brackets that contain a region ID in double quotes // https://pkg.go.dev/github.com/rivo/tview#hdr-Regions_and_Highlights - mt.builder.WriteString(`["`) - mt.builder.WriteString(m.ID.String()) - mt.builder.WriteString(`"]`) + mt.buf.WriteString(`["`) + mt.buf.WriteString(m.ID.String()) + mt.buf.WriteString(`"]`) if m.ReferencedMessage != nil { - mt.builder.WriteString("[::d] ") - mt.builder.WriteRune(replyIndicator) - mt.builder.WriteByte(' ') + mt.buf.WriteString("[::d] ") + mt.buf.WriteRune(replyIndicator) + mt.buf.WriteByte(' ') - // Author - mt.newAuthor(m.ReferencedMessage) + mt.buf.WriteByte('[') + mt.buf.WriteString(cfg.Theme.MessagesText.AuthorColor) + mt.buf.WriteByte(']') + mt.buf.WriteString(m.Author.Username) + mt.buf.WriteString("[-] ") - // Content - mt.newContent(m.ReferencedMessage) - - mt.builder.WriteString("[::-]\n") + mt.buf.WriteString(discordmd.Parse(tview.Escape(m.Content))) + mt.buf.WriteString("[::-]\n") } - if cfg.Timestamps { - // Timestamps - mt.newTimestamp(m) - } - - // Author - mt.newAuthor(m) - - // Content - mt.newContent(m) - - // Attachments - mt.newAttachments(m) + mt.createHeader(m) + mt.createBody(m) + mt.createFooter(m) // Tags with no region ID ([""]) don't start new regions. They can therefore be used to mark the end of a region. - mt.builder.WriteString(`[""]`) - mt.builder.WriteByte('\n') + mt.buf.WriteString(`[""]`) + mt.buf.WriteByte('\n') } - _, err := fmt.Fprint(mt, mt.builder.String()) + _, err := mt.buf.WriteTo(mt) return err } -func (mt *MessagesText) newAuthor(m *discord.Message) { - mt.builder.WriteByte('[') - mt.builder.WriteString(cfg.Theme.MessagesText.AuthorColor) - mt.builder.WriteByte(']') - mt.builder.WriteString(m.Author.Username) - mt.builder.WriteString("[-] ") +func (mt *MessagesText) createHeader(m *discord.Message) { + mt.buf.WriteByte('[') + mt.buf.WriteString(cfg.Theme.MessagesText.AuthorColor) + mt.buf.WriteByte(']') + mt.buf.WriteString(m.Author.Username) + mt.buf.WriteString("[-] ") + + if cfg.Timestamps { + mt.buf.WriteString("[::d]") + mt.buf.WriteString(m.Timestamp.Format(time.Kitchen)) + mt.buf.WriteString("[::-] ") + } } -func (mt *MessagesText) newTimestamp(m *discord.Message) { - mt.builder.WriteString("[::d]") - mt.builder.WriteString(m.Timestamp.Format(time.Kitchen)) - mt.builder.WriteString("[::-] ") +func (mt *MessagesText) createBody(m *discord.Message) { + mt.buf.WriteString(discordmd.Parse(tview.Escape(m.Content))) } -func (mt *MessagesText) newContent(m *discord.Message) { - mt.builder.WriteString(discordmd.Parse(tview.Escape(m.Content))) -} - -func (mt *MessagesText) newAttachments(m *discord.Message) { +func (mt *MessagesText) createFooter(m *discord.Message) { for _, a := range m.Attachments { - mt.builder.WriteByte('\n') + mt.buf.WriteByte('\n') - mt.builder.WriteByte('[') - mt.builder.WriteString(a.Filename) - mt.builder.WriteString("]: ") - mt.builder.WriteString(a.URL) + mt.buf.WriteByte('[') + mt.buf.WriteString(a.Filename) + mt.buf.WriteString("]: ") + mt.buf.WriteString(a.URL) } } diff --git a/state.go b/state.go index f4bf7e3..509a39c 100644 --- a/state.go +++ b/state.go @@ -67,7 +67,7 @@ func (s *State) onReady(r *gateway.ReadyEvent) { func (s *State) onMessageCreate(m *gateway.MessageCreateEvent) { if guildsTree.selectedChannel != nil && guildsTree.selectedChannel.ID == m.ChannelID { - err := messagesText.newMessage(&m.Message) + err := messagesText.createMessage(&m.Message) if err != nil { log.Println(err) return From 5fa71c26627ed9187ec141dce7188207671f26b8 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 8 Jan 2023 20:56:43 +0530 Subject: [PATCH 51/70] Editor --- config.go | 10 +++++++--- message_input.go | 22 ++++++++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/config.go b/config.go index 093485d..cfb19d3 100644 --- a/config.go +++ b/config.go @@ -23,6 +23,7 @@ type ( MessageInputKeysConfig struct { CommonKeysConfig `yaml:",inline"` Send string `yaml:"send"` + LaunchEditor string `yaml:"launch_editor"` } KeysConfig struct { @@ -62,9 +63,10 @@ type ( ) type Config struct { - Mouse bool `yaml:"mouse"` - MessagesLimit uint `yaml:"messages_limit"` - Timestamps bool `yaml:"timestamps"` + Mouse bool `yaml:"mouse"` + MessagesLimit uint `yaml:"messages_limit"` + Timestamps bool `yaml:"timestamps"` + Editor string `yaml:"editor"` Keys KeysConfig `yaml:"keys"` Theme ThemeConfig `yaml:"theme"` @@ -98,6 +100,7 @@ func newConfig() (*Config, error) { Mouse: true, Timestamps: false, MessagesLimit: 50, + Editor: "default", Keys: KeysConfig{ MessagesText: MessagesTextKeysConfig{ @@ -108,6 +111,7 @@ func newConfig() (*Config, error) { MessageInput: MessageInputKeysConfig{ CommonKeysConfig: commonKeys, Send: "Enter", + LaunchEditor: "Ctrl+E", }, }, diff --git a/message_input.go b/message_input.go index ad6b100..00d846b 100644 --- a/message_input.go +++ b/message_input.go @@ -2,6 +2,8 @@ package main import ( "log" + "os" + "os/exec" "strings" "github.com/diamondburned/arikawa/v3/api" @@ -44,6 +46,26 @@ func (mi *MessageInput) onInputCapture(event *tcell.EventKey) *tcell.EventKey { case cfg.Keys.MessageInput.Send: mi.sendAction() return nil + case cfg.Keys.MessageInput.LaunchEditor: + e := cfg.Editor + if e == "default" { + e = os.Getenv("EDITOR") + } + + cmd := exec.Command(e) + var b strings.Builder + cmd.Stdout = &b + + app.Suspend(func() { + err := cmd.Run() + if err != nil { + log.Println(err) + return + } + }) + + mi.SetText(b.String()) + return nil case cfg.Keys.MessageInput.Cancel: mi.reset() return nil From f25c59a67c399a9e81016420ff2f4ea9ba6630e2 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 8 Jan 2023 20:58:22 +0530 Subject: [PATCH 52/70] seg. into sep. func. --- message_input.go | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/message_input.go b/message_input.go index 00d846b..2fc8e85 100644 --- a/message_input.go +++ b/message_input.go @@ -47,24 +47,7 @@ func (mi *MessageInput) onInputCapture(event *tcell.EventKey) *tcell.EventKey { mi.sendAction() return nil case cfg.Keys.MessageInput.LaunchEditor: - e := cfg.Editor - if e == "default" { - e = os.Getenv("EDITOR") - } - - cmd := exec.Command(e) - var b strings.Builder - cmd.Stdout = &b - - app.Suspend(func() { - err := cmd.Run() - if err != nil { - log.Println(err) - return - } - }) - - mi.SetText(b.String()) + messageInput.launchEditorAction() return nil case cfg.Keys.MessageInput.Cancel: mi.reset() @@ -114,3 +97,24 @@ func (mi *MessageInput) sendAction() { messageInput.reset() } + +func (mi *MessageInput) launchEditorAction() { + e := cfg.Editor + if e == "default" { + e = os.Getenv("EDITOR") + } + + cmd := exec.Command(e) + var b strings.Builder + cmd.Stdout = &b + + app.Suspend(func() { + err := cmd.Run() + if err != nil { + log.Println(err) + return + } + }) + + mi.SetText(b.String()) +} From 8c236c636c5f509d5d5059085716b5df35bc5f5d Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 8 Jan 2023 21:01:51 +0530 Subject: [PATCH 53/70] Goroutinize SendMessage* calls --- message_input.go | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/message_input.go b/message_input.go index 2fc8e85..684c439 100644 --- a/message_input.go +++ b/message_input.go @@ -68,26 +68,20 @@ func (mi *MessageInput) sendAction() { } var err error - if messagesText.selectedMessage != nil { - title := mi.GetTitle() - if title == "" { - return - } - data := api.SendMessageData{ Content: text, Reference: &discord.MessageReference{MessageID: messagesText.selectedMessage.ID}, AllowedMentions: &api.AllowedMentions{RepliedUser: option.False}, } - if strings.HasPrefix(title, "[@]") { + if strings.HasPrefix(mi.GetTitle(), "[@]") { data.AllowedMentions.RepliedUser = option.True } - _, err = discordState.SendMessageComplex(guildsTree.selectedChannel.ID, data) + go discordState.SendMessageComplex(guildsTree.selectedChannel.ID, data) } else { - _, err = discordState.SendMessage(guildsTree.selectedChannel.ID, text) + go discordState.SendMessage(guildsTree.selectedChannel.ID, text) } if err != nil { From 71158b12c9689a1b8b5e35fa93da94902bf85d83 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 8 Jan 2023 21:48:15 +0530 Subject: [PATCH 54/70] Basic plugin system --- main.go | 11 ++++++++++ plugin.go | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 plugin.go diff --git a/main.go b/main.go index e8d85b3..6096f7c 100644 --- a/main.go +++ b/main.go @@ -3,6 +3,7 @@ package main import ( "context" "flag" + "fmt" "log" "github.com/rivo/tview" @@ -11,6 +12,7 @@ import ( var ( token string + plugins []*Plugin cfg *Config discordState *State @@ -30,6 +32,15 @@ func main() { flag.Parse() var err error + err = loadPlugins() + if err != nil { + log.Fatal(err) + } + + for _, p := range plugins { + fmt.Println(p.Name()) + } + cfg, err = newConfig() if err != nil { log.Fatal(err) diff --git a/plugin.go b/plugin.go new file mode 100644 index 0000000..67b33f4 --- /dev/null +++ b/plugin.go @@ -0,0 +1,61 @@ +package main + +import ( + "log" + "os" + "path/filepath" + "plugin" +) + +type Plugin struct { + *plugin.Plugin +} + +func newPlugin(path string) (*Plugin, error) { + p, err := plugin.Open(path) + if err != nil { + return nil, err + } + + return &Plugin{Plugin: p}, nil +} + +func (p *Plugin) Name() string { + s, _ := p.Lookup("Name") + return *(s).(*string) +} + +func loadPlugins() error { + path, err := os.UserConfigDir() + if err != nil { + log.Fatal(err) + } + + path = filepath.Join(path, name, "plugins") + err = os.MkdirAll(path, os.ModePerm) + if err != nil { + return err + } + + entries, err := os.ReadDir(path) + if err != nil { + return err + } + + for _, entry := range entries { + if entry.IsDir() { + continue + } + + if filepath.Ext(entry.Name()) == ".so" { + p, err := newPlugin(filepath.Join(path, entry.Name())) + if err != nil { + return err + } + + plugins = append(plugins, p) + } + } + + return nil +} From 1b082bb352606094f10e1eda06735c9f8677189e Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 8 Jan 2023 22:20:58 +0530 Subject: [PATCH 55/70] Add config for selecting messages --- config.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/config.go b/config.go index cfb19d3..4e2d33d 100644 --- a/config.go +++ b/config.go @@ -18,6 +18,8 @@ type ( CommonKeysConfig `yaml:",inline"` Reply string `yaml:"reply"` ReplyMention string `yaml:"reply_mention"` + SelectPrevious string `yaml:"select_previous"` + SelectNext string `yaml:"select_next"` } MessageInputKeysConfig struct { @@ -107,6 +109,9 @@ func newConfig() (*Config, error) { CommonKeysConfig: commonKeys, Reply: "Rune[r]", ReplyMention: "Rune[R]", + + SelectPrevious: "Up", + SelectNext: "Down", }, MessageInput: MessageInputKeysConfig{ CommonKeysConfig: commonKeys, From 6a2171bbc6f0de11494a83954b2d03908ec96f9d Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 8 Jan 2023 23:09:16 +0530 Subject: [PATCH 56/70] Remove TODO comment --- messages_text.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/messages_text.go b/messages_text.go index ffc27bc..1653dc7 100644 --- a/messages_text.go +++ b/messages_text.go @@ -150,8 +150,13 @@ func (mt *MessagesText) onInputCapture(event *tcell.EventKey) *tcell.EventKey { case cfg.Keys.MessagesText.ReplyMention: mt.replyAction(true) return nil + case cfg.Keys.MessagesText.SelectPrevious: + mt.selectPreviousAction() + return nil + case cfg.Keys.MessagesText.SelectNext: + mt.selectNextAction() + return nil case cfg.Keys.MessagesText.Cancel: - // TODO guildsTree.selectedChannel = nil messagesText.reset() @@ -179,3 +184,7 @@ func (mt *MessagesText) replyAction(mention bool) { app.SetFocus(messageInput) } + +func (mt *MessagesText) selectPreviousAction() {} + +func (mt *MessagesText) selectNextAction() {} From cfaaa2e84bd7594378d998a7b371376b978fdda4 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 8 Jan 2023 23:17:35 +0530 Subject: [PATCH 57/70] plugins --- guilds_tree.go | 12 ++++++------ main.go | 8 ++++---- message_input.go | 18 +++++++++--------- messages_text.go | 24 ++++++++++++------------ plugin.go | 2 +- 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/guilds_tree.go b/guilds_tree.go index 188e638..c7c0b5b 100644 --- a/guilds_tree.go +++ b/guilds_tree.go @@ -24,19 +24,19 @@ func newGuildsTree() *GuildsTree { root: tview.NewTreeNode(""), } - gt.SetGraphics(cfg.Theme.GuildsTree.Graphics) + gt.SetGraphics(config.Theme.GuildsTree.Graphics) gt.SetRoot(gt.root) gt.SetTopLevel(1) gt.SetSelectedFunc(gt.onSelected) - gt.SetBackgroundColor(tcell.GetColor(cfg.Theme.GuildsTree.BackgroundColor)) + gt.SetBackgroundColor(tcell.GetColor(config.Theme.GuildsTree.BackgroundColor)) gt.SetTitle("Guilds") - gt.SetTitleColor(tcell.GetColor(cfg.Theme.GuildsTree.TitleColor)) + gt.SetTitleColor(tcell.GetColor(config.Theme.GuildsTree.TitleColor)) gt.SetTitleAlign(tview.AlignLeft) - padding := cfg.Theme.GuildsTree.BorderPadding - gt.SetBorder(cfg.Theme.GuildsTree.Border) + padding := config.Theme.GuildsTree.BorderPadding + gt.SetBorder(config.Theme.GuildsTree.Border) gt.SetBorderPadding(padding[0], padding[1], padding[2], padding[3]) return gt @@ -149,7 +149,7 @@ func (gt *GuildsTree) onSelected(n *tview.TreeNode) { gt.selectedChannel = c messagesText.SetTitle(gt.channelToString(*c)) - ms, err := discordState.Messages(ref, cfg.MessagesLimit) + ms, err := discordState.Messages(ref, config.MessagesLimit) if err != nil { log.Println(err) return diff --git a/main.go b/main.go index 6096f7c..f038c49 100644 --- a/main.go +++ b/main.go @@ -12,9 +12,9 @@ import ( var ( token string - plugins []*Plugin - cfg *Config + config *Config discordState *State + plugins = make(map[string]*Plugin) app = tview.NewApplication() flex = tview.NewFlex() @@ -41,7 +41,7 @@ func main() { fmt.Println(p.Name()) } - cfg, err = newConfig() + config, err = newConfig() if err != nil { log.Fatal(err) } @@ -65,7 +65,7 @@ func main() { flex.AddItem(guildsTree, 0, 1, true) flex.AddItem(right, 0, 4, false) - app.EnableMouse(cfg.Mouse) + app.EnableMouse(config.Mouse) app.SetRoot(flex, true) err = app.Run() diff --git a/message_input.go b/message_input.go index 684c439..f6eb5a0 100644 --- a/message_input.go +++ b/message_input.go @@ -23,14 +23,14 @@ func newMessageInput() *MessageInput { } mi.SetInputCapture(mi.onInputCapture) - mi.SetFieldBackgroundColor(tcell.GetColor(cfg.Theme.MessageInput.BackgroundColor)) - mi.SetBackgroundColor(tcell.GetColor(cfg.Theme.MessageInput.BackgroundColor)) + mi.SetFieldBackgroundColor(tcell.GetColor(config.Theme.MessageInput.BackgroundColor)) + mi.SetBackgroundColor(tcell.GetColor(config.Theme.MessageInput.BackgroundColor)) - mi.SetTitleColor(tcell.GetColor(cfg.Theme.MessageInput.TitleColor)) + mi.SetTitleColor(tcell.GetColor(config.Theme.MessageInput.TitleColor)) mi.SetTitleAlign(tview.AlignLeft) - padding := cfg.Theme.MessageInput.BorderPadding - mi.SetBorder(cfg.Theme.MessageInput.Border) + padding := config.Theme.MessageInput.BorderPadding + mi.SetBorder(config.Theme.MessageInput.Border) mi.SetBorderPadding(padding[0], padding[1], padding[2], padding[3]) return mi @@ -43,13 +43,13 @@ func (mi *MessageInput) reset() { func (mi *MessageInput) onInputCapture(event *tcell.EventKey) *tcell.EventKey { switch event.Name() { - case cfg.Keys.MessageInput.Send: + case config.Keys.MessageInput.Send: mi.sendAction() return nil - case cfg.Keys.MessageInput.LaunchEditor: + case config.Keys.MessageInput.LaunchEditor: messageInput.launchEditorAction() return nil - case cfg.Keys.MessageInput.Cancel: + case config.Keys.MessageInput.Cancel: mi.reset() return nil } @@ -93,7 +93,7 @@ func (mi *MessageInput) sendAction() { } func (mi *MessageInput) launchEditorAction() { - e := cfg.Editor + e := config.Editor if e == "default" { e = os.Getenv("EDITOR") } diff --git a/messages_text.go b/messages_text.go index 1653dc7..8b9c0ea 100644 --- a/messages_text.go +++ b/messages_text.go @@ -35,14 +35,14 @@ func newMessagesText() *MessagesText { app.Draw() }) - mt.SetBackgroundColor(tcell.GetColor(cfg.Theme.MessagesText.BackgroundColor)) + mt.SetBackgroundColor(tcell.GetColor(config.Theme.MessagesText.BackgroundColor)) mt.SetTitle("Messages") - mt.SetTitleColor(tcell.GetColor(cfg.Theme.MessagesText.TitleColor)) + mt.SetTitleColor(tcell.GetColor(config.Theme.MessagesText.TitleColor)) mt.SetTitleAlign(tview.AlignLeft) - padding := cfg.Theme.MessagesText.BorderPadding - mt.SetBorder(cfg.Theme.MessagesText.Border) + padding := config.Theme.MessagesText.BorderPadding + mt.SetBorder(config.Theme.MessagesText.Border) mt.SetBorderPadding(padding[0], padding[1], padding[2], padding[3]) return mt @@ -71,7 +71,7 @@ func (mt *MessagesText) createMessage(m *discord.Message) error { mt.buf.WriteByte(' ') mt.buf.WriteByte('[') - mt.buf.WriteString(cfg.Theme.MessagesText.AuthorColor) + mt.buf.WriteString(config.Theme.MessagesText.AuthorColor) mt.buf.WriteByte(']') mt.buf.WriteString(m.Author.Username) mt.buf.WriteString("[-] ") @@ -95,12 +95,12 @@ func (mt *MessagesText) createMessage(m *discord.Message) error { func (mt *MessagesText) createHeader(m *discord.Message) { mt.buf.WriteByte('[') - mt.buf.WriteString(cfg.Theme.MessagesText.AuthorColor) + mt.buf.WriteString(config.Theme.MessagesText.AuthorColor) mt.buf.WriteByte(']') mt.buf.WriteString(m.Author.Username) mt.buf.WriteString("[-] ") - if cfg.Timestamps { + if config.Timestamps { mt.buf.WriteString("[::d]") mt.buf.WriteString(m.Timestamp.Format(time.Kitchen)) mt.buf.WriteString("[::-] ") @@ -144,19 +144,19 @@ func (mt *MessagesText) onHighlighted(added, removed, remaining []string) { func (mt *MessagesText) onInputCapture(event *tcell.EventKey) *tcell.EventKey { switch event.Name() { - case cfg.Keys.MessagesText.Reply: + case config.Keys.MessagesText.Reply: mt.replyAction(false) return nil - case cfg.Keys.MessagesText.ReplyMention: + case config.Keys.MessagesText.ReplyMention: mt.replyAction(true) return nil - case cfg.Keys.MessagesText.SelectPrevious: + case config.Keys.MessagesText.SelectPrevious: mt.selectPreviousAction() return nil - case cfg.Keys.MessagesText.SelectNext: + case config.Keys.MessagesText.SelectNext: mt.selectNextAction() return nil - case cfg.Keys.MessagesText.Cancel: + case config.Keys.MessagesText.Cancel: guildsTree.selectedChannel = nil messagesText.reset() diff --git a/plugin.go b/plugin.go index 67b33f4..c73995f 100644 --- a/plugin.go +++ b/plugin.go @@ -53,7 +53,7 @@ func loadPlugins() error { return err } - plugins = append(plugins, p) + plugins[p.Name()] = p } } From 6ae88a6dcfe287e6739d6fc33b3f07120bb2b289 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 8 Jan 2023 23:18:32 +0530 Subject: [PATCH 58/70] Remove useless loop --- main.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/main.go b/main.go index f038c49..2e4351a 100644 --- a/main.go +++ b/main.go @@ -3,7 +3,6 @@ package main import ( "context" "flag" - "fmt" "log" "github.com/rivo/tview" @@ -37,10 +36,6 @@ func main() { log.Fatal(err) } - for _, p := range plugins { - fmt.Println(p.Name()) - } - config, err = newConfig() if err != nil { log.Fatal(err) From fb2a6dc0f0a26d9ee6026f7b837bcfe7ef0f3b06 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sun, 8 Jan 2023 23:27:18 +0530 Subject: [PATCH 59/70] Remove Go plugins --- main.go | 6 ------ plugin.go | 61 ------------------------------------------------------- 2 files changed, 67 deletions(-) delete mode 100644 plugin.go diff --git a/main.go b/main.go index 2e4351a..956bb94 100644 --- a/main.go +++ b/main.go @@ -13,7 +13,6 @@ var ( config *Config discordState *State - plugins = make(map[string]*Plugin) app = tview.NewApplication() flex = tview.NewFlex() @@ -31,11 +30,6 @@ func main() { flag.Parse() var err error - err = loadPlugins() - if err != nil { - log.Fatal(err) - } - config, err = newConfig() if err != nil { log.Fatal(err) diff --git a/plugin.go b/plugin.go deleted file mode 100644 index c73995f..0000000 --- a/plugin.go +++ /dev/null @@ -1,61 +0,0 @@ -package main - -import ( - "log" - "os" - "path/filepath" - "plugin" -) - -type Plugin struct { - *plugin.Plugin -} - -func newPlugin(path string) (*Plugin, error) { - p, err := plugin.Open(path) - if err != nil { - return nil, err - } - - return &Plugin{Plugin: p}, nil -} - -func (p *Plugin) Name() string { - s, _ := p.Lookup("Name") - return *(s).(*string) -} - -func loadPlugins() error { - path, err := os.UserConfigDir() - if err != nil { - log.Fatal(err) - } - - path = filepath.Join(path, name, "plugins") - err = os.MkdirAll(path, os.ModePerm) - if err != nil { - return err - } - - entries, err := os.ReadDir(path) - if err != nil { - return err - } - - for _, entry := range entries { - if entry.IsDir() { - continue - } - - if filepath.Ext(entry.Name()) == ".so" { - p, err := newPlugin(filepath.Join(path, entry.Name())) - if err != nil { - return err - } - - plugins[p.Name()] = p - } - } - - return nil -} From 433f9feb58aca90aa4532350df0cd5faa49a2523 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Mon, 9 Jan 2023 13:49:43 +0530 Subject: [PATCH 60/70] select bindings --- config.go | 25 +++++++---- message_input.go | 14 +++++-- messages_text.go | 107 +++++++++++++++++++++++++++++++++++------------ 3 files changed, 108 insertions(+), 38 deletions(-) diff --git a/config.go b/config.go index 4e2d33d..1b3e41d 100644 --- a/config.go +++ b/config.go @@ -16,16 +16,21 @@ type ( MessagesTextKeysConfig struct { CommonKeysConfig `yaml:",inline"` - Reply string `yaml:"reply"` - ReplyMention string `yaml:"reply_mention"` - SelectPrevious string `yaml:"select_previous"` - SelectNext string `yaml:"select_next"` + + Reply string `yaml:"reply"` + ReplyMention string `yaml:"reply_mention"` + + SelectPrevious string `yaml:"select_previous"` + SelectNext string `yaml:"select_next"` + SelectFirst string `yaml:"select_first"` + SelectLast string `yaml:"select_last"` } MessageInputKeysConfig struct { CommonKeysConfig `yaml:",inline"` - Send string `yaml:"send"` - LaunchEditor string `yaml:"launch_editor"` + + Send string `yaml:"send"` + LaunchEditor string `yaml:"launch_editor"` } KeysConfig struct { @@ -45,12 +50,14 @@ type ( GuildsTreeThemeConfig struct { CommonThemeConfig `yaml:",inline"` - Graphics bool `yaml:"graphics"` + + Graphics bool `yaml:"graphics"` } MessagesTextThemeConfig struct { CommonThemeConfig `yaml:",inline"` - AuthorColor string `yaml:"author_color"` + + AuthorColor string `yaml:"author_color"` } MessageInputThemeConfig struct { @@ -112,6 +119,8 @@ func newConfig() (*Config, error) { SelectPrevious: "Up", SelectNext: "Down", + SelectFirst: "Home", + SelectLast: "End", }, MessageInput: MessageInputKeysConfig{ CommonKeysConfig: commonKeys, diff --git a/message_input.go b/message_input.go index f6eb5a0..5e75795 100644 --- a/message_input.go +++ b/message_input.go @@ -68,10 +68,16 @@ func (mi *MessageInput) sendAction() { } var err error - if messagesText.selectedMessage != nil { + if messagesText.selectedMessage != -1 { + ms, err := discordState.Cabinet.Messages(guildsTree.selectedChannel.ID) + if err != nil { + log.Println(err) + return + } + data := api.SendMessageData{ Content: text, - Reference: &discord.MessageReference{MessageID: messagesText.selectedMessage.ID}, + Reference: &discord.MessageReference{MessageID: ms[messagesText.selectedMessage].ID}, AllowedMentions: &api.AllowedMentions{RepliedUser: option.False}, } @@ -89,7 +95,9 @@ func (mi *MessageInput) sendAction() { return } - messageInput.reset() + messagesText.selectedMessage = -1 + messagesText.Highlight() + mi.reset() } func (mi *MessageInput) launchEditorAction() { diff --git a/messages_text.go b/messages_text.go index 8b9c0ea..b1b2536 100644 --- a/messages_text.go +++ b/messages_text.go @@ -16,19 +16,20 @@ const replyIndicator = '╭' type MessagesText struct { *tview.TextView - selectedMessage *discord.Message + selectedMessage int buf bytes.Buffer } func newMessagesText() *MessagesText { mt := &MessagesText{ TextView: tview.NewTextView(), + + selectedMessage: -1, } mt.SetDynamicColors(true) mt.SetRegions(true) mt.SetWordWrap(true) - mt.SetHighlightedFunc(mt.onHighlighted) mt.SetInputCapture(mt.onInputCapture) mt.ScrollToEnd() mt.SetChangedFunc(func() { @@ -49,7 +50,7 @@ func newMessagesText() *MessagesText { } func (mt *MessagesText) reset() { - messagesText.selectedMessage = nil + messagesText.selectedMessage = -1 mt.SetTitle("") mt.Clear() @@ -122,26 +123,6 @@ func (mt *MessagesText) createFooter(m *discord.Message) { } } -func (mt *MessagesText) onHighlighted(added, removed, remaining []string) { - if len(added) == 0 { - return - } - - sf, err := discord.ParseSnowflake(added[0]) - if err != nil { - log.Println(err) - return - } - - m, err := discordState.Cabinet.Message(guildsTree.selectedChannel.ID, discord.MessageID(sf)) - if err != nil { - log.Println(err) - return - } - - mt.selectedMessage = m -} - func (mt *MessagesText) onInputCapture(event *tcell.EventKey) *tcell.EventKey { switch event.Name() { case config.Keys.MessagesText.Reply: @@ -156,6 +137,12 @@ func (mt *MessagesText) onInputCapture(event *tcell.EventKey) *tcell.EventKey { case config.Keys.MessagesText.SelectNext: mt.selectNextAction() return nil + case config.Keys.MessagesText.SelectFirst: + mt.selectFirstAction() + return nil + case config.Keys.MessagesText.SelectLast: + mt.selectLastAction() + return nil case config.Keys.MessagesText.Cancel: guildsTree.selectedChannel = nil @@ -168,7 +155,7 @@ func (mt *MessagesText) onInputCapture(event *tcell.EventKey) *tcell.EventKey { } func (mt *MessagesText) replyAction(mention bool) { - if mt.selectedMessage == nil { + if mt.selectedMessage == -1 { return } @@ -179,12 +166,78 @@ func (mt *MessagesText) replyAction(mention bool) { title += "Replying to " } - title += mt.selectedMessage.Author.Tag() + ms, err := discordState.Cabinet.Messages(guildsTree.selectedChannel.ID) + if err != nil { + log.Println(err) + return + } + + title += ms[mt.selectedMessage].Author.Tag() messageInput.SetTitle(title) app.SetFocus(messageInput) } -func (mt *MessagesText) selectPreviousAction() {} +func (mt *MessagesText) selectPreviousAction() { + ms, err := discordState.Cabinet.Messages(guildsTree.selectedChannel.ID) + if err != nil { + log.Println(err) + return + } -func (mt *MessagesText) selectNextAction() {} + // If no message is currently selected, select the latest message. + if len(mt.GetHighlights()) == 0 { + mt.selectedMessage = 0 + } else { + if mt.selectedMessage < len(ms)-1 { + mt.selectedMessage++ + } + } + + mt.Highlight(ms[mt.selectedMessage].ID.String()) + mt.ScrollToHighlight() +} + +func (mt *MessagesText) selectNextAction() { + ms, err := discordState.Cabinet.Messages(guildsTree.selectedChannel.ID) + if err != nil { + log.Println(err) + return + } + + // If no message is currently selected, select the latest message. + if len(mt.GetHighlights()) == 0 { + mt.selectedMessage = 0 + } else { + if mt.selectedMessage > 0 { + mt.selectedMessage-- + } + } + + mt.Highlight(ms[mt.selectedMessage].ID.String()) + mt.ScrollToHighlight() +} + +func (mt *MessagesText) selectFirstAction() { + ms, err := discordState.Cabinet.Messages(guildsTree.selectedChannel.ID) + if err != nil { + log.Println(err) + return + } + + mt.selectedMessage = len(ms) - 1 + mt.Highlight(ms[mt.selectedMessage].ID.String()) + mt.ScrollToHighlight() +} + +func (mt *MessagesText) selectLastAction() { + ms, err := discordState.Cabinet.Messages(guildsTree.selectedChannel.ID) + if err != nil { + log.Println(err) + return + } + + mt.selectedMessage = 0 + mt.Highlight(ms[mt.selectedMessage].ID.String()) + mt.ScrollToHighlight() +} From 8caad25ba560e7629eea4edcd43d844a6380ef6f Mon Sep 17 00:00:00 2001 From: ayn2op Date: Mon, 9 Jan 2023 14:14:11 +0530 Subject: [PATCH 61/70] keybindings --- config.go | 82 ++++++++++++++++++------------------------------ guilds_tree.go | 10 +++--- message_input.go | 14 ++++----- messages_text.go | 43 ++++++++++++++++++++----- 4 files changed, 77 insertions(+), 72 deletions(-) diff --git a/config.go b/config.go index 1b3e41d..4791ed8 100644 --- a/config.go +++ b/config.go @@ -10,15 +10,10 @@ import ( const name = "discordo" type ( - CommonKeysConfig struct { - Cancel string `yaml:"cancel"` - } - MessagesTextKeysConfig struct { - CommonKeysConfig `yaml:",inline"` - Reply string `yaml:"reply"` ReplyMention string `yaml:"reply_mention"` + SelectReply string `yaml:"select_reply"` SelectPrevious string `yaml:"select_previous"` SelectNext string `yaml:"select_next"` @@ -27,44 +22,36 @@ type ( } MessageInputKeysConfig struct { - CommonKeysConfig `yaml:",inline"` - Send string `yaml:"send"` LaunchEditor string `yaml:"launch_editor"` } KeysConfig struct { + Cancel string `yaml:"cancel"` + MessagesText MessagesTextKeysConfig `yaml:"messages_text"` MessageInput MessageInputKeysConfig `yaml:"message_input"` } ) type ( - CommonThemeConfig struct { + GuildsTreeThemeConfig struct { + Graphics bool `yaml:"graphics"` + } + + MessagesTextThemeConfig struct { + AuthorColor string `yaml:"author_color"` + } + + MessageInputThemeConfig struct{} + + ThemeConfig struct { Border bool `yaml:"border"` BorderPadding [4]int `yaml:"border_padding,flow"` TitleColor string `yaml:"title_color"` BackgroundColor string `yaml:"background_color"` - } - GuildsTreeThemeConfig struct { - CommonThemeConfig `yaml:",inline"` - - Graphics bool `yaml:"graphics"` - } - - MessagesTextThemeConfig struct { - CommonThemeConfig `yaml:",inline"` - - AuthorColor string `yaml:"author_color"` - } - - MessageInputThemeConfig struct { - CommonThemeConfig `yaml:",inline"` - } - - ThemeConfig struct { GuildsTree GuildsTreeThemeConfig `yaml:"guilds_tree"` MessagesText MessagesTextThemeConfig `yaml:"messages_text"` MessageInput MessageInputThemeConfig `yaml:"message_input"` @@ -93,18 +80,6 @@ func newConfig() (*Config, error) { return nil, err } - commonTheme := CommonThemeConfig{ - Border: true, - BorderPadding: [...]int{0, 0, 1, 1}, - - TitleColor: "default", - BackgroundColor: "default", - } - - commonKeys := CommonKeysConfig{ - Cancel: "Esc", - } - c := Config{ Mouse: true, Timestamps: false, @@ -112,10 +87,12 @@ func newConfig() (*Config, error) { Editor: "default", Keys: KeysConfig{ + Cancel: "Esc", + MessagesText: MessagesTextKeysConfig{ - CommonKeysConfig: commonKeys, - Reply: "Rune[r]", - ReplyMention: "Rune[R]", + Reply: "Rune[r]", + ReplyMention: "Rune[R]", + SelectReply: "Rune[s]", SelectPrevious: "Up", SelectNext: "Down", @@ -123,24 +100,25 @@ func newConfig() (*Config, error) { SelectLast: "End", }, MessageInput: MessageInputKeysConfig{ - CommonKeysConfig: commonKeys, - Send: "Enter", - LaunchEditor: "Ctrl+E", + Send: "Enter", + LaunchEditor: "Ctrl+E", }, }, Theme: ThemeConfig{ + Border: true, + BorderPadding: [...]int{0, 0, 1, 1}, + + TitleColor: "default", + BackgroundColor: "default", + GuildsTree: GuildsTreeThemeConfig{ - CommonThemeConfig: commonTheme, - Graphics: true, + Graphics: true, }, MessagesText: MessagesTextThemeConfig{ - CommonThemeConfig: commonTheme, - AuthorColor: "aqua", - }, - MessageInput: MessageInputThemeConfig{ - CommonThemeConfig: commonTheme, + AuthorColor: "aqua", }, + MessageInput: MessageInputThemeConfig{}, }, } path = filepath.Join(path, "config.yml") diff --git a/guilds_tree.go b/guilds_tree.go index c7c0b5b..f8f4cca 100644 --- a/guilds_tree.go +++ b/guilds_tree.go @@ -29,15 +29,15 @@ func newGuildsTree() *GuildsTree { gt.SetTopLevel(1) gt.SetSelectedFunc(gt.onSelected) - gt.SetBackgroundColor(tcell.GetColor(config.Theme.GuildsTree.BackgroundColor)) + gt.SetBackgroundColor(tcell.GetColor(config.Theme.BackgroundColor)) gt.SetTitle("Guilds") - gt.SetTitleColor(tcell.GetColor(config.Theme.GuildsTree.TitleColor)) + gt.SetTitleColor(tcell.GetColor(config.Theme.TitleColor)) gt.SetTitleAlign(tview.AlignLeft) - padding := config.Theme.GuildsTree.BorderPadding - gt.SetBorder(config.Theme.GuildsTree.Border) - gt.SetBorderPadding(padding[0], padding[1], padding[2], padding[3]) + p := config.Theme.BorderPadding + gt.SetBorder(config.Theme.Border) + gt.SetBorderPadding(p[0], p[1], p[2], p[3]) return gt } diff --git a/message_input.go b/message_input.go index 5e75795..913a9de 100644 --- a/message_input.go +++ b/message_input.go @@ -23,15 +23,15 @@ func newMessageInput() *MessageInput { } mi.SetInputCapture(mi.onInputCapture) - mi.SetFieldBackgroundColor(tcell.GetColor(config.Theme.MessageInput.BackgroundColor)) - mi.SetBackgroundColor(tcell.GetColor(config.Theme.MessageInput.BackgroundColor)) + mi.SetBackgroundColor(tcell.GetColor(config.Theme.BackgroundColor)) + mi.SetFieldBackgroundColor(tcell.GetColor(config.Theme.BackgroundColor)) - mi.SetTitleColor(tcell.GetColor(config.Theme.MessageInput.TitleColor)) + mi.SetTitleColor(tcell.GetColor(config.Theme.TitleColor)) mi.SetTitleAlign(tview.AlignLeft) - padding := config.Theme.MessageInput.BorderPadding - mi.SetBorder(config.Theme.MessageInput.Border) - mi.SetBorderPadding(padding[0], padding[1], padding[2], padding[3]) + p := config.Theme.BorderPadding + mi.SetBorder(config.Theme.Border) + mi.SetBorderPadding(p[0], p[1], p[2], p[3]) return mi } @@ -49,7 +49,7 @@ func (mi *MessageInput) onInputCapture(event *tcell.EventKey) *tcell.EventKey { case config.Keys.MessageInput.LaunchEditor: messageInput.launchEditorAction() return nil - case config.Keys.MessageInput.Cancel: + case config.Keys.Cancel: mi.reset() return nil } diff --git a/messages_text.go b/messages_text.go index b1b2536..323a64e 100644 --- a/messages_text.go +++ b/messages_text.go @@ -36,15 +36,15 @@ func newMessagesText() *MessagesText { app.Draw() }) - mt.SetBackgroundColor(tcell.GetColor(config.Theme.MessagesText.BackgroundColor)) + mt.SetBackgroundColor(tcell.GetColor(config.Theme.BackgroundColor)) mt.SetTitle("Messages") - mt.SetTitleColor(tcell.GetColor(config.Theme.MessagesText.TitleColor)) + mt.SetTitleColor(tcell.GetColor(config.Theme.TitleColor)) mt.SetTitleAlign(tview.AlignLeft) - padding := config.Theme.MessagesText.BorderPadding - mt.SetBorder(config.Theme.MessagesText.Border) - mt.SetBorderPadding(padding[0], padding[1], padding[2], padding[3]) + p := config.Theme.BorderPadding + mt.SetBorder(config.Theme.Border) + mt.SetBorderPadding(p[0], p[1], p[2], p[3]) return mt } @@ -74,10 +74,10 @@ func (mt *MessagesText) createMessage(m *discord.Message) error { mt.buf.WriteByte('[') mt.buf.WriteString(config.Theme.MessagesText.AuthorColor) mt.buf.WriteByte(']') - mt.buf.WriteString(m.Author.Username) + mt.buf.WriteString(m.ReferencedMessage.Author.Username) mt.buf.WriteString("[-] ") - mt.buf.WriteString(discordmd.Parse(tview.Escape(m.Content))) + mt.buf.WriteString(discordmd.Parse(tview.Escape(m.ReferencedMessage.Content))) mt.buf.WriteString("[::-]\n") } @@ -143,7 +143,10 @@ func (mt *MessagesText) onInputCapture(event *tcell.EventKey) *tcell.EventKey { case config.Keys.MessagesText.SelectLast: mt.selectLastAction() return nil - case config.Keys.MessagesText.Cancel: + case config.Keys.MessagesText.SelectReply: + mt.selectReplyAction() + return nil + case config.Keys.Cancel: guildsTree.selectedChannel = nil messagesText.reset() @@ -241,3 +244,27 @@ func (mt *MessagesText) selectLastAction() { mt.Highlight(ms[mt.selectedMessage].ID.String()) mt.ScrollToHighlight() } + +func (mt *MessagesText) selectReplyAction() { + if mt.selectedMessage == -1 { + return + } + + ms, err := discordState.Cabinet.Messages(guildsTree.selectedChannel.ID) + if err != nil { + log.Println(err) + return + } + + ref := ms[mt.selectedMessage].ReferencedMessage + if ref != nil { + for i, m := range ms { + if ref.ID == m.ID { + mt.selectedMessage = i + } + } + + mt.Highlight(ms[mt.selectedMessage].ID.String()) + mt.ScrollToHighlight() + } +} From cd8177f0c7ddf50a01fe739653177809c9c16134 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Mon, 9 Jan 2023 14:27:21 +0530 Subject: [PATCH 62/70] copy content action --- config.go | 4 ++++ go.mod | 1 + go.sum | 2 ++ main.go | 22 ++++++++++++++++++++++ messages_text.go | 18 ++++++++++++++++++ 5 files changed, 47 insertions(+) diff --git a/config.go b/config.go index 4791ed8..2fedd45 100644 --- a/config.go +++ b/config.go @@ -11,6 +11,8 @@ const name = "discordo" type ( MessagesTextKeysConfig struct { + CopyContent string `yaml:"copy_content"` + Reply string `yaml:"reply"` ReplyMention string `yaml:"reply_mention"` SelectReply string `yaml:"select_reply"` @@ -90,6 +92,8 @@ func newConfig() (*Config, error) { Cancel: "Esc", MessagesText: MessagesTextKeysConfig{ + CopyContent: "Rune[c]", + Reply: "Rune[r]", ReplyMention: "Rune[R]", SelectReply: "Rune[s]", diff --git a/go.mod b/go.mod index aeb1d2c..d1e0542 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/ayn2op/discordo go 1.19 require ( + github.com/atotto/clipboard v0.1.4 github.com/diamondburned/arikawa/v3 v3.2.0 github.com/gdamore/tcell/v2 v2.5.4 github.com/rivo/tview v0.0.0-20230104153304-892d1a2eb0da diff --git a/go.sum b/go.sum index 5453662..0bf69dd 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= +github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/diamondburned/arikawa/v3 v3.2.0 h1:aBUhg94pxblT6ks4EV7qxEk44tnl0ico67ydqjVnv9g= github.com/diamondburned/arikawa/v3 v3.2.0/go.mod h1:5jBSNnp82Z/EhsKa6Wk9FsOqSxfVkNZDTDBPOj47LpY= github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= diff --git a/main.go b/main.go index 956bb94..6aae793 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,8 @@ import ( "context" "flag" "log" + "os" + "path/filepath" "github.com/rivo/tview" ) @@ -24,6 +26,26 @@ var ( func init() { flag.StringVar(&token, "token", "", "The authentication token.") + + path, err := os.UserCacheDir() + if err != nil { + log.Fatal(err) + } + + path = filepath.Join(path, name) + err = os.MkdirAll(path, os.ModePerm) + if err != nil { + log.Fatal(err) + } + + path = filepath.Join(path, "logs.txt") + f, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND, os.ModePerm) + if err != nil { + log.Fatal(err) + } + + log.SetOutput(f) + log.SetFlags(log.LstdFlags | log.Llongfile) } func main() { diff --git a/messages_text.go b/messages_text.go index 323a64e..6bf2f0d 100644 --- a/messages_text.go +++ b/messages_text.go @@ -5,6 +5,7 @@ import ( "log" "time" + "github.com/atotto/clipboard" "github.com/ayn2op/discordo/discordmd" "github.com/diamondburned/arikawa/v3/discord" "github.com/gdamore/tcell/v2" @@ -125,6 +126,9 @@ func (mt *MessagesText) createFooter(m *discord.Message) { func (mt *MessagesText) onInputCapture(event *tcell.EventKey) *tcell.EventKey { switch event.Name() { + case config.Keys.MessagesText.CopyContent: + mt.copyContentAction() + return nil case config.Keys.MessagesText.Reply: mt.replyAction(false) return nil @@ -268,3 +272,17 @@ func (mt *MessagesText) selectReplyAction() { mt.ScrollToHighlight() } } + +func (mt *MessagesText) copyContentAction() { + ms, err := discordState.Cabinet.Messages(guildsTree.selectedChannel.ID) + if err != nil { + log.Println(err) + return + } + + err = clipboard.WriteAll(ms[mt.selectedMessage].Content) + if err != nil { + log.Println(err) + return + } +} From 7662127affddb0bb5a2122a674ac6b44ae64207c Mon Sep 17 00:00:00 2001 From: ayn2op Date: Mon, 9 Jan 2023 14:34:51 +0530 Subject: [PATCH 63/70] Log file --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index 6aae793..6061d6b 100644 --- a/main.go +++ b/main.go @@ -39,7 +39,7 @@ func init() { } path = filepath.Join(path, "logs.txt") - f, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND, os.ModePerm) + f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, os.ModePerm) if err != nil { log.Fatal(err) } From 19de9a1ba2cba8ec6b62fbd5fbe40f51effb6243 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Mon, 9 Jan 2023 15:44:12 +0530 Subject: [PATCH 64/70] paste --- config.go | 8 ++++++-- message_input.go | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/config.go b/config.go index 2fedd45..422083e 100644 --- a/config.go +++ b/config.go @@ -24,7 +24,9 @@ type ( } MessageInputKeysConfig struct { - Send string `yaml:"send"` + Send string `yaml:"send"` + Paste string `yaml:"paste"` + LaunchEditor string `yaml:"launch_editor"` } @@ -104,7 +106,9 @@ func newConfig() (*Config, error) { SelectLast: "End", }, MessageInput: MessageInputKeysConfig{ - Send: "Enter", + Send: "Enter", + + Paste: "Ctrl+V", LaunchEditor: "Ctrl+E", }, }, diff --git a/message_input.go b/message_input.go index 913a9de..5eadabb 100644 --- a/message_input.go +++ b/message_input.go @@ -6,6 +6,7 @@ import ( "os/exec" "strings" + "github.com/atotto/clipboard" "github.com/diamondburned/arikawa/v3/api" "github.com/diamondburned/arikawa/v3/discord" "github.com/diamondburned/arikawa/v3/utils/json/option" @@ -46,6 +47,9 @@ func (mi *MessageInput) onInputCapture(event *tcell.EventKey) *tcell.EventKey { case config.Keys.MessageInput.Send: mi.sendAction() return nil + case config.Keys.MessageInput.Paste: + mi.pasteAction() + return nil case config.Keys.MessageInput.LaunchEditor: messageInput.launchEditorAction() return nil @@ -100,6 +104,16 @@ func (mi *MessageInput) sendAction() { mi.reset() } +func (mi *MessageInput) pasteAction() { + text, err := clipboard.ReadAll() + if err != nil { + log.Fatal(err) + } + + // Append the text to the message input. + mi.SetText(mi.GetText() + text) +} + func (mi *MessageInput) launchEditorAction() { e := config.Editor if e == "default" { From 832d887d38b9a5fe8a12d8c81d441267c27c38e0 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Mon, 9 Jan 2023 15:47:22 +0530 Subject: [PATCH 65/70] border color --- config.go | 2 ++ guilds_tree.go | 1 + message_input.go | 1 + messages_text.go | 1 + 4 files changed, 5 insertions(+) diff --git a/config.go b/config.go index 422083e..57bb153 100644 --- a/config.go +++ b/config.go @@ -51,6 +51,7 @@ type ( ThemeConfig struct { Border bool `yaml:"border"` + BorderColor string `yaml:"border_color"` BorderPadding [4]int `yaml:"border_padding,flow"` TitleColor string `yaml:"title_color"` @@ -115,6 +116,7 @@ func newConfig() (*Config, error) { Theme: ThemeConfig{ Border: true, + BorderColor: "default", BorderPadding: [...]int{0, 0, 1, 1}, TitleColor: "default", diff --git a/guilds_tree.go b/guilds_tree.go index f8f4cca..8b926e9 100644 --- a/guilds_tree.go +++ b/guilds_tree.go @@ -37,6 +37,7 @@ func newGuildsTree() *GuildsTree { p := config.Theme.BorderPadding gt.SetBorder(config.Theme.Border) + gt.SetBorderColor(tcell.GetColor(config.Theme.BorderColor)) gt.SetBorderPadding(p[0], p[1], p[2], p[3]) return gt diff --git a/message_input.go b/message_input.go index 5eadabb..319d415 100644 --- a/message_input.go +++ b/message_input.go @@ -32,6 +32,7 @@ func newMessageInput() *MessageInput { p := config.Theme.BorderPadding mi.SetBorder(config.Theme.Border) + mi.SetBorderColor(tcell.GetColor(config.Theme.BorderColor)) mi.SetBorderPadding(p[0], p[1], p[2], p[3]) return mi diff --git a/messages_text.go b/messages_text.go index 6bf2f0d..37a2863 100644 --- a/messages_text.go +++ b/messages_text.go @@ -45,6 +45,7 @@ func newMessagesText() *MessagesText { p := config.Theme.BorderPadding mt.SetBorder(config.Theme.Border) + mt.SetBorderColor(tcell.GetColor(config.Theme.BorderColor)) mt.SetBorderPadding(p[0], p[1], p[2], p[3]) return mt From bc31828a96963907829a6dd1ea723a3ba8e610fb Mon Sep 17 00:00:00 2001 From: ayn2op Date: Mon, 9 Jan 2023 16:07:16 +0530 Subject: [PATCH 66/70] polish --- .github/workflows/ci.yml | 27 +++++++++++++++ .gitignore | 4 +++ LICENSE | 21 +++++++++++ README.md | 75 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 127 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..bdc55d6 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,27 @@ +name: ci +on: [push, pull_request] + +jobs: + build: + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-go@v3 + with: + go-version: '^1.19' + + - name: Build + run: go build . + + - uses: actions/upload-artifact@v3 + if: ${{ github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }} + with: + name: discordo_${{ runner.os }}_${{ runner.arch }} + path: | + discordo + discordo.exe diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ca87ce3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +discordo* + +# Visual Studio Code +.vscode/ \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ae882e2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 ayn2op + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..06b4a0b --- /dev/null +++ b/README.md @@ -0,0 +1,75 @@ +# Discordo · [![ci](https://github.com/ayn2op/discordo/actions/workflows/ci.yml/badge.svg)](https://github.com/ayn2op/discordo/actions/workflows/ci.yml) [![Go Report Card](https://goreportcard.com/badge/github.com/ayn2op/discordo)](https://goreportcard.com/report/github.com/ayn2op/discordo) [![license](https://img.shields.io/github/license/ayn2op/discordo?logo=github)](https://github.com/ayn2op/discordo/blob/master/LICENSE) + +Discordo is a lightweight, secure, and feature-rich Discord terminal client. Heavily work-in-progress, expect breaking changes. + +![Preview](.github/preview.png) + + +## Table of Contents + +- [Features](#features) +- [Installation](#installation) + - [Prebuilt binaries](#prebuilt-binaries) + - [Package managers](#package-managers) + - [Building from source](#building-from-source) +- [Usage](#usage) + - [Configuration](#configuration) +- [Disclaimer](#disclaimer) + +## Features + +- Lightweight +- Secure +- Configurable +- Cross-platform +- Minimalistic +- Feature-rich + - Mouse & clipboard support + - Partial [Discord-flavored markdown](https://support.discord.com/hc/en-us/articles/210298617-Markdown-Text-101-Chat-Formatting-Bold-Italic-Underline-) + +## Installation + +### Prebuilt binaries + +You can download and install a [prebuilt binary here](https://nightly.link/ayn2op/discordo/workflows/ci/main) for Windows, macOS, or Linux. + +### Package managers + +- [Arch Linux](https://aur.archlinux.org/packages/discordo-git/): `yay -S discordo-git` (thanks to [Alyxia Sother](https://github.com/lexisother) for maintaining the AUR package). +- [FreeBSD](https://www.freshports.org/net-im/discordo): `pkg install discordo` or via the ports system `make -C /usr/ports/net-im/discordo install clean`. + +### Building from source + +```bash +git clone https://github.com/ayn2op/discordo +cd discordo +make build + +# optional +sudo mv ./discordo /usr/local/bin +``` + +### Linux clipboard support + +- `xclip` or `xsel` for X11 (`apt install xclip`) +- `wl-clipboard` for Wayland (`apt install wl-clipboard`) + +## Usage + +1. Run the `discordo` executable with no arguments. + +- If you are logging in using an authentication token, provide the `token` command-line flag to the executable (eg: `--token "OTI2MDU5NTQxNDE2Nzc5ODA2.Yc2KKA.2iZ-5JxgxG-9Ub8GHzBSn-NJjNg"`). The token is stored securely in the default OS-specific keyring. + +2. Enter your email and password and click on the "Login" button to continue. + +- Most of the Discord third-party clients store the token in a configuration file unencrypted. Discordo securely stores the token in the default OS-specific keyring. + +### Configuration + +A default configuration file is created on first start-up at `$HOME/.config/discordo/config.yml` on Unix, `$HOME/Library/Application Support/discordo/config.yml` on Darwin, and `%AppData%/discordo/config.yml` on Windows. + +Similarly, a log file is created on first start-up at `$HOME/.cache/discordo/logs.txt` on Unix, `$HOME/Library/Caches/discordo/logs.txt` on Darwin, and `%LocalAppData%/discordo/logs.txt` on Windows. + +## Disclaimer + +Automated user accounts or "self-bots" are against Discord's Terms of Service. I am not responsible for any loss caused by using "self-bots" or Discordo. From 5a37d74d28d32069e368f5bc270bfbbdf9ceb96a Mon Sep 17 00:00:00 2001 From: ayn2op Date: Mon, 9 Jan 2023 16:36:19 +0530 Subject: [PATCH 67/70] Login form --- go.mod | 5 ++++ go.sum | 25 ++++++++++++++++ login_form.go | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++ main.go | 45 +++++++++++++++++++--------- 4 files changed, 142 insertions(+), 14 deletions(-) create mode 100644 login_form.go diff --git a/go.mod b/go.mod index d1e0542..a626f4d 100644 --- a/go.mod +++ b/go.mod @@ -4,14 +4,19 @@ go 1.19 require ( github.com/atotto/clipboard v0.1.4 + github.com/diamondburned/arikawa v1.3.14 github.com/diamondburned/arikawa/v3 v3.2.0 github.com/gdamore/tcell/v2 v2.5.4 github.com/rivo/tview v0.0.0-20230104153304-892d1a2eb0da + github.com/zalando/go-keyring v0.2.2 gopkg.in/yaml.v3 v3.0.1 ) require ( + github.com/alessio/shellescape v1.4.1 // indirect + github.com/danieljoos/wincred v1.1.2 // indirect github.com/gdamore/encoding v1.0.0 // indirect + github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gorilla/schema v1.2.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect diff --git a/go.sum b/go.sum index 0bf69dd..dc33baa 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,22 @@ +github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= +github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= +github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= +github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/diamondburned/arikawa v1.3.14 h1:9Y1r8nlvWA01hQIYVFGr83JTLd5ULPBzNOKvxbAsH1M= +github.com/diamondburned/arikawa v1.3.14/go.mod h1:nIhVIatzTQhPUa7NB8w4koG1RF9gYbpAr8Fj8sKq660= github.com/diamondburned/arikawa/v3 v3.2.0 h1:aBUhg94pxblT6ks4EV7qxEk44tnl0ico67ydqjVnv9g= github.com/diamondburned/arikawa/v3 v3.2.0/go.mod h1:5jBSNnp82Z/EhsKa6Wk9FsOqSxfVkNZDTDBPOj47LpY= 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.5.4 h1:TGU4tSjD3sCL788vFNeJnTdzpNKIw1H5dgLnJRQVv/k= github.com/gdamore/tcell/v2 v2.5.4/go.mod h1:dZgRy5v4iMobMEcWNYBtREnDZAT9DYmfqIkrgEMxLyw= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gorilla/schema v1.1.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc= github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -17,23 +28,35 @@ github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWV github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/tview v0.0.0-20230104153304-892d1a2eb0da h1:3Mh+tcC2KqetuHpWMurDeF+yOgyt4w4qtLIpwSQ3uqo= github.com/rivo/tview v0.0.0-20230104153304-892d1a2eb0da/go.mod h1:lBUy/T5kyMudFzWUH/C2moN+NlU5qF505vzOyINXuUQ= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw= github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zalando/go-keyring v0.2.2 h1:f0xmpYiSrHtSNAVgwip93Cg8tuF45HJM6rHq/A5RI/4= +github.com/zalando/go-keyring v0.2.2/go.mod h1:sI3evg9Wvpw3+n4SqplGSJUMwtDeROfD4nsFz4z9PG0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211001092434-39dca1131b70/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -49,6 +72,7 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -58,5 +82,6 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/login_form.go b/login_form.go new file mode 100644 index 0000000..847dadc --- /dev/null +++ b/login_form.go @@ -0,0 +1,81 @@ +package main + +import ( + "context" + "log" + + "github.com/diamondburned/arikawa/api" + "github.com/gdamore/tcell/v2" + "github.com/rivo/tview" +) + +type LoginForm struct { + *tview.Form +} + +func newLoginForm() *LoginForm { + lf := &LoginForm{ + Form: tview.NewForm(), + } + + lf.AddInputField("Email", "", 0, nil, nil) + lf.AddPasswordField("Password", "", 0, 0, nil) + lf.AddPasswordField("Code (optional)", "", 0, 0, nil) + lf.AddButton("Login", lf.onLoginButtonSelected) + + lf.SetTitle("Login") + lf.SetTitleColor(tcell.GetColor(config.Theme.TitleColor)) + + p := config.Theme.BorderPadding + lf.SetBorder(config.Theme.Border) + lf.SetBorderColor(tcell.GetColor(config.Theme.BorderColor)) + lf.SetBorderPadding(p[0], p[1], p[2], p[3]) + + return lf +} + +func (lf *LoginForm) onLoginButtonSelected() { + email := lf.GetFormItem(0).(*tview.InputField).GetText() + password := lf.GetFormItem(1).(*tview.InputField).GetText() + if email == "" || password == "" { + return + } + + // Make a scratch HTTP client without a token + client := api.NewClient("").WithContext(context.Background()) + // Try to login without TOTP + l, err := client.Login(email, password) + if err != nil { + log.Fatal(err) + } + + // Retry logging in with a 2FA token + if l.Token == "" && l.MFA { + code := lf.GetFormItem(2).(*tview.InputField).GetText() + if code == "" { + return + } + + l, err = client.TOTP(code, l.Ticket) + if err != nil { + log.Fatal(err) + } + } + + // We got the token, return with a new Session. + discordState = newState(l.Token) + err = discordState.Open(context.Background()) + if err != nil { + log.Fatal(err) + } + + right := tview.NewFlex() + right.SetDirection(tview.FlexRow) + right.AddItem(messagesText, 0, 1, false) + right.AddItem(messageInput, 3, 1, false) + // The guilds tree is always focused first at start-up. + flex.AddItem(guildsTree, 0, 1, true) + flex.AddItem(right, 0, 4, false) + + app.SetRoot(flex, true) +} diff --git a/main.go b/main.go index 6061d6b..41f8034 100644 --- a/main.go +++ b/main.go @@ -8,6 +8,7 @@ import ( "path/filepath" "github.com/rivo/tview" + "github.com/zalando/go-keyring" ) var ( @@ -52,6 +53,17 @@ func main() { flag.Parse() var err error + // If the token is passed via the flag, set it in the keyring. + if token != "" { + go keyring.Set(name, "token", token) + } else { + token, err = keyring.Get(name, "token") + if err != nil { + log.Println(err) + return + } + } + config, err = newConfig() if err != nil { log.Fatal(err) @@ -62,23 +74,28 @@ func main() { messagesText = newMessagesText() messageInput = newMessageInput() - discordState = newState(token) - err = discordState.Open(context.Background()) - if err != nil { - log.Fatal(err) + // mission failed, we'll get 'em next time + if token == "" { + app.SetRoot(newLoginForm(), true) + } else { + discordState = newState(token) + err = discordState.Open(context.Background()) + if err != nil { + log.Fatal(err) + } + + right := tview.NewFlex() + right.SetDirection(tview.FlexRow) + right.AddItem(messagesText, 0, 1, false) + right.AddItem(messageInput, 3, 1, false) + // The guilds tree is always focused first at start-up. + flex.AddItem(guildsTree, 0, 1, true) + flex.AddItem(right, 0, 4, false) + + app.SetRoot(flex, true) } - right := tview.NewFlex() - right.SetDirection(tview.FlexRow) - right.AddItem(messagesText, 0, 1, false) - right.AddItem(messageInput, 3, 1, false) - // The guilds tree is always focused first at start-up. - flex.AddItem(guildsTree, 0, 1, true) - flex.AddItem(right, 0, 4, false) - app.EnableMouse(config.Mouse) - app.SetRoot(flex, true) - err = app.Run() if err != nil { log.Fatal(err) From 6254f9afca0bcdb0c6669d08b49070294fa1e692 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Mon, 9 Jan 2023 17:01:09 +0530 Subject: [PATCH 68/70] merged --- go.mod | 8 ------ go.sum | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.go | 11 -------- 3 files changed, 87 insertions(+), 19 deletions(-) create mode 100644 go.sum diff --git a/go.mod b/go.mod index 7f21fa4..a626f4d 100644 --- a/go.mod +++ b/go.mod @@ -4,11 +4,6 @@ go 1.19 require ( github.com/atotto/clipboard v0.1.4 - github.com/diamondburned/arikawa/v3 v3.1.0 - github.com/gdamore/tcell/v2 v2.5.3 - github.com/rivo/tview v0.0.0-20221221172820-02e38ea9604c - github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 - github.com/zalando/go-keyring v0.2.1 github.com/diamondburned/arikawa v1.3.14 github.com/diamondburned/arikawa/v3 v3.2.0 github.com/gdamore/tcell/v2 v2.5.4 @@ -28,9 +23,6 @@ require ( github.com/mattn/go-runewidth v0.0.14 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/rivo/uniseg v0.4.3 // indirect - golang.org/x/sys v0.3.0 // indirect - golang.org/x/term v0.3.0 // indirect - golang.org/x/text v0.5.0 // indirect golang.org/x/sys v0.4.0 // indirect golang.org/x/term v0.4.0 // indirect golang.org/x/text v0.6.0 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..dc33baa --- /dev/null +++ b/go.sum @@ -0,0 +1,87 @@ +github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= +github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= +github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= +github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= +github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= +github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/diamondburned/arikawa v1.3.14 h1:9Y1r8nlvWA01hQIYVFGr83JTLd5ULPBzNOKvxbAsH1M= +github.com/diamondburned/arikawa v1.3.14/go.mod h1:nIhVIatzTQhPUa7NB8w4koG1RF9gYbpAr8Fj8sKq660= +github.com/diamondburned/arikawa/v3 v3.2.0 h1:aBUhg94pxblT6ks4EV7qxEk44tnl0ico67ydqjVnv9g= +github.com/diamondburned/arikawa/v3 v3.2.0/go.mod h1:5jBSNnp82Z/EhsKa6Wk9FsOqSxfVkNZDTDBPOj47LpY= +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.5.4 h1:TGU4tSjD3sCL788vFNeJnTdzpNKIw1H5dgLnJRQVv/k= +github.com/gdamore/tcell/v2 v2.5.4/go.mod h1:dZgRy5v4iMobMEcWNYBtREnDZAT9DYmfqIkrgEMxLyw= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gorilla/schema v1.1.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= +github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc= +github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +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/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= +github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rivo/tview v0.0.0-20230104153304-892d1a2eb0da h1:3Mh+tcC2KqetuHpWMurDeF+yOgyt4w4qtLIpwSQ3uqo= +github.com/rivo/tview v0.0.0-20230104153304-892d1a2eb0da/go.mod h1:lBUy/T5kyMudFzWUH/C2moN+NlU5qF505vzOyINXuUQ= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw= +github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zalando/go-keyring v0.2.2 h1:f0xmpYiSrHtSNAVgwip93Cg8tuF45HJM6rHq/A5RI/4= +github.com/zalando/go-keyring v0.2.2/go.mod h1:sI3evg9Wvpw3+n4SqplGSJUMwtDeROfD4nsFz4z9PG0= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211001092434-39dca1131b70/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.4.0 h1:O7UWfv5+A2qiuulQk30kVinPoMtoIPeVaKLEgLpVkvg= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= +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.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go index 71b5228..41f8034 100644 --- a/main.go +++ b/main.go @@ -7,17 +7,6 @@ import ( "os" "path/filepath" - "github.com/ayn2op/discordo/config" - "github.com/zalando/go-keyring" -) - -var tokenFlag string - -func init() { - flag.StringVar(&tokenFlag, "token", "", "The authentication token.") - - path := config.LogDirPath() - err := os.MkdirAll(path, os.ModePerm) "github.com/rivo/tview" "github.com/zalando/go-keyring" ) From 131d303f785070243f9c2bfb07614e1f79d18cca Mon Sep 17 00:00:00 2001 From: ayn2op Date: Mon, 9 Jan 2023 17:02:30 +0530 Subject: [PATCH 69/70] resolve --- .github/workflows/ci.yml | 4 ---- README.md | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 147c62b..bdc55d6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,11 +16,7 @@ jobs: go-version: '^1.19' - name: Build -<<<<<<< HEAD - run: make -======= run: go build . ->>>>>>> rewrite - uses: actions/upload-artifact@v3 if: ${{ github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }} diff --git a/README.md b/README.md index c05da5b..f8cec5b 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ You can download and install a [prebuilt binary here](https://nightly.link/ayn2o ```bash git clone https://github.com/ayn2op/discordo cd discordo -make build +go build . # optional sudo mv ./discordo /usr/local/bin From dec0a61bcc1992f24c0ae00c946cad2f758a8c2d Mon Sep 17 00:00:00 2001 From: ayn2op Date: Mon, 9 Jan 2023 17:03:04 +0530 Subject: [PATCH 70/70] Remove Makefile --- Makefile | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 Makefile diff --git a/Makefile b/Makefile deleted file mode 100644 index e57a522..0000000 --- a/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -FLAGS=-ldflags "-s -w" - -.PHONY: all -all: clean fmt build - -.PHONY: clean -clean: - go clean - -.PHONY: fmt -fmt: - gofmt -d -e -s . - -.PHONY: build -build: - go build $(FLAGS)