diff --git a/README.md b/README.md index c0a639a..e5b70d9 100644 --- a/README.md +++ b/README.md @@ -38,11 +38,9 @@ sudo mv ./discordo /usr/local/bin 1. Run the `discordo` executable with no arguments. -> On first startup, a default configuration file will be created at `$HOME/.config/discordo.toml` on Unix, `%AppData%/discordo.toml` on Windows, and `$HOME/Library/Application Support/discordo.toml` on Darwin. - 2. Log in using the account email and password (first-time login) and click on the "Login" button to continue. -> Note: by default, Discordo utilizes OS-specific keyring to store credentials such as client authentication token. However, if you prefer not to use a keyring (not recommended), you may set the `token` field in the configuration file and Discordo will prioritize the usage of the provided token to login instead of keyring. +> Note: by default, Discordo utilizes OS-specific keyring to store credentials such as client authentication token. However, if you prefer not to use a keyring (not recommended), you may set the `DISCORDO_TOKEN` environment variable and Discordo will prioritize the usage of the provided token to login instead of keyring. ### Clipboard support diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..5bbe4fe --- /dev/null +++ b/config/config.go @@ -0,0 +1,41 @@ +package config + +var General = struct { + UserAgent string + Mouse bool + Notifications bool + FetchMessagesLimit int +}{ + UserAgent: "Mozilla/5.0 (X11; Linux x86_64; rv:95.0) Gecko/20100101 Firefox/95.0", + Mouse: true, + Notifications: true, + FetchMessagesLimit: 50, +} + +var Keybindings = struct { + FocusChannelsTreeView []string + FocusMessagesView []string + FocusMessageInputField []string + + SelectPreviousMessage []string + SelectNextMessage []string + SelectFirstMessage []string + SelectLastMessage []string + SelectMessageReference []string + ReplySelectedMessage []string + MentionReplySelectedMessage []string + CopySelectedMessage []string +}{ + FocusChannelsTreeView: []string{"Alt+Left"}, + FocusMessagesView: []string{"Alt+Right"}, + FocusMessageInputField: []string{"Alt+Down"}, + + SelectPreviousMessage: []string{"Up"}, + SelectNextMessage: []string{"Down"}, + SelectFirstMessage: []string{"Home"}, + SelectLastMessage: []string{"End"}, + ReplySelectedMessage: []string{"Rune[r]"}, + MentionReplySelectedMessage: []string{"Rune[R]"}, + CopySelectedMessage: []string{"Rune[c]"}, + SelectMessageReference: []string{"Rune[m]"}, +} diff --git a/discord.go b/discord.go index 8f471c0..d915cce 100644 --- a/discord.go +++ b/discord.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/ayntgl/discordgo" + "github.com/ayntgl/discordo/config" "github.com/gen2brain/beeep" "github.com/rivo/tview" ) @@ -19,26 +20,6 @@ var ( strikeThroughRegex = regexp.MustCompile(`(?m)~~(.*?)~~`) ) -func newSession() *discordgo.Session { - s, err := discordgo.New() - if err != nil { - panic(err) - } - - s.UserAgent = conf.UserAgent - s.Identify.Compress = false - s.Identify.Intents = 0 - s.Identify.LargeThreshold = 0 - s.Identify.Properties.Device = "" - s.Identify.Properties.Browser = "Chrome" - s.Identify.Properties.OS = "Linux" - - s.AddHandlerOnce(onSessionReady) - s.AddHandler(onSessionMessageCreate) - - return s -} - func onSessionReady(_ *discordgo.Session, r *discordgo.Ready) { dmNode := tview.NewTreeNode("Direct Messages"). Collapse() @@ -74,15 +55,15 @@ func onSessionReady(_ *discordgo.Session, r *discordgo.Ready) { func onSessionMessageCreate(_ *discordgo.Session, m *discordgo.MessageCreate) { if selectedChannel == nil || selectedChannel.ID != m.ChannelID { - if conf.Notifications { + if config.General.Notifications { for _, u := range m.Mentions { - if u.ID == session.State.User.ID { - g, err := session.State.Guild(m.GuildID) + if u.ID == app.Session.State.User.ID { + g, err := app.Session.State.Guild(m.GuildID) if err != nil { return } - c, err := session.State.Channel(m.ChannelID) + c, err := app.Session.State.Channel(m.ChannelID) if err != nil { return } @@ -114,7 +95,7 @@ func login(email, password string) (*loginResponse, error) { Email string `json:"email"` Password string `json:"password"` }{email, password} - resp, err := session.RequestWithBucketID( + resp, err := app.Session.RequestWithBucketID( "POST", discordgo.EndpointLogin, data, @@ -139,7 +120,7 @@ func totp(code, ticket string) (*loginResponse, error) { Ticket string `json:"ticket"` }{code, ticket} e := discordgo.EndpointAuth + "mfa/totp" - resp, err := session.RequestWithBucketID("POST", e, data, e) + resp, err := app.Session.RequestWithBucketID("POST", e, data, e) if err != nil { return nil, err } @@ -314,7 +295,7 @@ func buildAttachments(b *strings.Builder, as []*discordgo.MessageAttachment) { func buildMentions(content string, mentions []*discordgo.User) string { for _, mUser := range mentions { var color string - if mUser.ID == session.State.User.ID { + if mUser.ID == app.Session.State.User.ID { color = "[:#5865F2]" } else { color = "[#EB459E]" @@ -334,7 +315,7 @@ func buildMentions(content string, mentions []*discordgo.User) string { } func buildAuthor(b *strings.Builder, u *discordgo.User) { - if u.ID == session.State.User.ID { + if u.ID == app.Session.State.User.ID { b.WriteString("[#57F287]") } else { b.WriteString("[#ED4245]") diff --git a/main.go b/main.go index ee30255..ea7415e 100644 --- a/main.go +++ b/main.go @@ -1,9 +1,11 @@ package main import ( + "os" + "github.com/ayntgl/discordgo" + "github.com/ayntgl/discordo/config" "github.com/ayntgl/discordo/ui" - "github.com/ayntgl/discordo/util" "github.com/gdamore/tcell/v2" "github.com/rivo/tview" "github.com/zalando/go-keyring" @@ -12,63 +14,49 @@ import ( const service = "discordo" var ( - app *tview.Application + app *ui.App loginForm *tview.Form channelsTreeView *tview.TreeView messagesTextView *tview.TextView messageInputField *tview.InputField mainFlex *tview.Flex - conf *util.Config - session *discordgo.Session - selectedChannel *discordgo.Channel selectedMessage int = -1 ) func main() { - conf = util.LoadConfig() - - tview.Borders.Horizontal = conf.Borders.Horizontal - tview.Borders.Vertical = conf.Borders.Vertical - tview.Borders.TopLeft = conf.Borders.TopLeft - tview.Borders.TopRight = conf.Borders.TopRight - tview.Borders.BottomLeft = conf.Borders.BottomLeft - tview.Borders.BottomRight = conf.Borders.BottomRight - tview.Borders.HorizontalFocus = conf.Borders.HorizontalFocus - tview.Borders.VerticalFocus = conf.Borders.VerticalFocus - tview.Borders.TopLeftFocus = conf.Borders.TopLeftFocus - tview.Borders.TopRightFocus = conf.Borders.TopRightFocus - tview.Borders.BottomLeftFocus = conf.Borders.BottomLeftFocus - tview.Borders.BottomRightFocus = conf.Borders.BottomRightFocus - - tview.Styles.PrimitiveBackgroundColor = tcell.GetColor(conf.Theme.Background) - tview.Styles.ContrastBackgroundColor = tcell.GetColor(conf.Theme.Background) - tview.Styles.MoreContrastBackgroundColor = tcell.GetColor(conf.Theme.Background) - tview.Styles.BorderColor = tcell.GetColor(conf.Theme.Border) - tview.Styles.TitleColor = tcell.GetColor(conf.Theme.Title) - tview.Styles.GraphicsColor = tcell.GetColor(conf.Theme.Graphics) - tview.Styles.PrimaryTextColor = tcell.GetColor(conf.Theme.Text) - tview.Styles.SecondaryTextColor = tcell.GetColor(conf.Theme.Text) - tview.Styles.TertiaryTextColor = tcell.GetColor(conf.Theme.Text) - tview.Styles.InverseTextColor = tcell.GetColor(conf.Theme.Text) - tview.Styles.ContrastSecondaryTextColor = tcell.GetColor(conf.Theme.Text) - - app = tview.NewApplication() + app = ui.NewApp() app. - EnableMouse(conf.Mouse). + EnableMouse(config.General.Mouse). SetInputCapture(onAppInputCapture) - channelsTreeView = ui.NewChannelsTreeView() - channelsTreeView.SetSelectedFunc(onChannelsTreeSelected) + app.ChannelsTreeView. + SetTopLevel(1). + SetRoot(tview.NewTreeNode("")). + SetSelectedFunc(onChannelsTreeSelected). + SetTitleAlign(tview.AlignLeft). + SetBorder(true). + SetBorderPadding(0, 0, 1, 0) - messagesTextView = ui.NewMessagesTextView() - messagesTextView. + app.MessagesTextView. + SetRegions(true). + SetDynamicColors(true). + SetWordWrap(true). SetChangedFunc(func() { app.Draw() }). - SetInputCapture(onMessagesViewInputCapture) + SetTitleAlign(tview.AlignLeft). + SetInputCapture(onMessagesViewInputCapture). + SetBorder(true). + SetBorderPadding(0, 0, 1, 0) - messageInputField = ui.NewMessageInputField() - messageInputField.SetInputCapture(onMessageInputFieldInputCapture) + app.MessageInputField. + SetPlaceholder("Message..."). + SetPlaceholderTextColor(tcell.ColorWhite). + SetFieldBackgroundColor(tview.Styles.PrimitiveBackgroundColor). + SetInputCapture(onMessageInputFieldInputCapture). + SetTitleAlign(tview.AlignLeft). + SetBorder(true). + SetBorderPadding(0, 0, 1, 0) rightFlex := tview.NewFlex(). SetDirection(tview.FlexRow). @@ -78,9 +66,9 @@ func main() { AddItem(channelsTreeView, 0, 1, false). AddItem(rightFlex, 0, 4, false) - token, err := keyring.Get(service, "token") - if err != nil { - token = conf.Token + token := os.Getenv("DISCORDO_TOKEN") + if token == "" { + token, _ = keyring.Get(service, "token") } if token != "" { @@ -88,10 +76,10 @@ func main() { SetRoot(mainFlex, true). SetFocus(channelsTreeView) - session = newSession() - session.Token = token - session.Identify.Token = token - if err := session.Open(); err != nil { + app.Session.AddHandlerOnce(onSessionReady) + app.Session.AddHandler(onSessionMessageCreate) + err := app.Connect(token) + if err != nil { panic(err) } } else { @@ -111,7 +99,6 @@ func onLoginFormLoginButtonSelected() { return } - session = newSession() // Login using the email and password lr, err := login(email, password) if err != nil { @@ -123,9 +110,10 @@ func onLoginFormLoginButtonSelected() { SetRoot(mainFlex, true). SetFocus(channelsTreeView) - session.Token = lr.Token - session.Identify.Token = lr.Token - if err = session.Open(); err != nil { + app.Session.AddHandlerOnce(onSessionReady) + app.Session.AddHandler(onSessionMessageCreate) + err = app.Connect(lr.Token) + if err != nil { panic(err) } @@ -147,9 +135,10 @@ func onLoginFormLoginButtonSelected() { SetRoot(mainFlex, true). SetFocus(channelsTreeView) - session.Token = lr.Token - session.Identify.Token = lr.Token - if err = session.Open(); err != nil { + app.Session.AddHandlerOnce(onSessionReady) + app.Session.AddHandler(onSessionMessageCreate) + err = app.Connect(lr.Token) + if err != nil { panic(err) } diff --git a/ui.go b/ui.go index eece24b..d93a86c 100644 --- a/ui.go +++ b/ui.go @@ -6,19 +6,20 @@ import ( "github.com/atotto/clipboard" "github.com/ayntgl/discordgo" + "github.com/ayntgl/discordo/config" "github.com/ayntgl/discordo/util" "github.com/gdamore/tcell/v2" "github.com/rivo/tview" ) func onAppInputCapture(e *tcell.EventKey) *tcell.EventKey { - if util.HasKeybinding(conf.Keybindings.FocusChannelsTree, e.Name()) { + if util.HasKeybinding(config.Keybindings.FocusChannelsTreeView, e.Name()) { app.SetFocus(channelsTreeView) return nil - } else if util.HasKeybinding(conf.Keybindings.FocusMessagesView, e.Name()) { + } else if util.HasKeybinding(config.Keybindings.FocusMessagesView, e.Name()) { app.SetFocus(messagesTextView) return nil - } else if util.HasKeybinding(conf.Keybindings.FocusMessageInputField, e.Name()) { + } else if util.HasKeybinding(config.Keybindings.FocusMessageInputField, e.Name()) { app.SetFocus(messageInputField) return nil } @@ -42,14 +43,14 @@ func onChannelsTreeSelected(n *tview.TreeNode) { if len(n.GetChildren()) == 0 { // If the reference of the selected `*TreeNode` is `nil`, it is the direct messages `*TreeNode`. if id == nil { - cs := session.State.PrivateChannels + cs := app.Session.State.PrivateChannels sort.Slice(cs, func(i, j int) bool { return cs[i].LastMessageID > cs[j].LastMessageID }) for _, c := range cs { tag := "[::d]" - if util.ChannelIsUnread(session.State, c) { + if util.ChannelIsUnread(app.Session.State, c) { tag = "[::b]" } @@ -59,7 +60,7 @@ func onChannelsTreeSelected(n *tview.TreeNode) { n.AddChild(cn) } } else { - g, err := session.State.Guild(id.(string)) + g, err := app.Session.State.Guild(id.(string)) if err != nil { return } @@ -69,17 +70,17 @@ func onChannelsTreeSelected(n *tview.TreeNode) { }) // Top-level channels - createTopLevelChannelsNodes(channelsTreeView, session.State, n, g.Channels) + createTopLevelChannelsNodes(channelsTreeView, app.Session.State, n, g.Channels) // Category channels - createCategoryChannelsNodes(channelsTreeView, session.State, n, g.Channels) + createCategoryChannelsNodes(channelsTreeView, app.Session.State, n, g.Channels) // Second-level channels - createSecondLevelChannelsNodes(channelsTreeView, session.State, g.Channels) + createSecondLevelChannelsNodes(channelsTreeView, app.Session.State, g.Channels) } } n.SetExpanded(!n.IsExpanded()) default: // Channels - c, err := session.State.Channel(id.(string)) + c, err := app.Session.State.Channel(id.(string)) if err != nil { return } @@ -104,7 +105,7 @@ func onChannelsTreeSelected(n *tview.TreeNode) { } go func() { - ms, err := session.ChannelMessages(c.ID, conf.GetMessagesLimit, "", "", "") + ms, err := app.Session.ChannelMessages(c.ID, config.General.FetchMessagesLimit, "", "", "") if err != nil { return } @@ -116,8 +117,8 @@ func onChannelsTreeSelected(n *tview.TreeNode) { // Scroll to the end of the text after the messages have been written to the TextView. messagesTextView.ScrollToEnd() - if len(ms) != 0 && util.ChannelIsUnread(session.State, c) { - session.ChannelMessageAck(c.ID, c.LastMessageID, "") + if len(ms) != 0 && util.ChannelIsUnread(app.Session.State, c) { + app.Session.ChannelMessageAck(c.ID, c.LastMessageID, "") } }() } @@ -186,7 +187,7 @@ func onMessagesViewInputCapture(e *tcell.EventKey) *tcell.EventKey { return nil } - if util.HasKeybinding(conf.Keybindings.SelectPreviousMessage, e.Name()) { + if util.HasKeybinding(config.Keybindings.SelectPreviousMessage, e.Name()) { if len(messagesTextView.GetHighlights()) == 0 { selectedMessage = len(ms) - 1 } else { @@ -200,7 +201,7 @@ func onMessagesViewInputCapture(e *tcell.EventKey) *tcell.EventKey { Highlight(ms[selectedMessage].ID). ScrollToHighlight() return nil - } else if util.HasKeybinding(conf.Keybindings.SelectNextMessage, e.Name()) { + } else if util.HasKeybinding(config.Keybindings.SelectNextMessage, e.Name()) { if len(messagesTextView.GetHighlights()) == 0 { selectedMessage = len(ms) - 1 } else { @@ -214,19 +215,19 @@ func onMessagesViewInputCapture(e *tcell.EventKey) *tcell.EventKey { Highlight(ms[selectedMessage].ID). ScrollToHighlight() return nil - } else if util.HasKeybinding(conf.Keybindings.SelectFirstMessage, e.Name()) { + } else if util.HasKeybinding(config.Keybindings.SelectFirstMessage, e.Name()) { selectedMessage = 0 messagesTextView. Highlight(ms[selectedMessage].ID). ScrollToHighlight() return nil - } else if util.HasKeybinding(conf.Keybindings.SelectLastMessage, e.Name()) { + } else if util.HasKeybinding(config.Keybindings.SelectLastMessage, e.Name()) { selectedMessage = len(ms) - 1 messagesTextView. Highlight(ms[selectedMessage].ID). ScrollToHighlight() return nil - } else if util.HasKeybinding(conf.Keybindings.SelectMessageReference, e.Name()) { + } else if util.HasKeybinding(config.Keybindings.SelectMessageReference, e.Name()) { hs := messagesTextView.GetHighlights() if len(hs) == 0 { return nil @@ -241,7 +242,7 @@ func onMessagesViewInputCapture(e *tcell.EventKey) *tcell.EventKey { } return nil - } else if util.HasKeybinding(conf.Keybindings.ReplySelectedMessage, e.Name()) { + } else if util.HasKeybinding(config.Keybindings.ReplySelectedMessage, e.Name()) { hs := messagesTextView.GetHighlights() if len(hs) == 0 { return nil @@ -251,7 +252,7 @@ func onMessagesViewInputCapture(e *tcell.EventKey) *tcell.EventKey { messageInputField.SetTitle("Replying to " + m.Author.String()) app.SetFocus(messageInputField) return nil - } else if util.HasKeybinding(conf.Keybindings.MentionReplySelectedMessage, e.Name()) { + } else if util.HasKeybinding(config.Keybindings.MentionReplySelectedMessage, e.Name()) { hs := messagesTextView.GetHighlights() if len(hs) == 0 { return nil @@ -261,7 +262,7 @@ func onMessagesViewInputCapture(e *tcell.EventKey) *tcell.EventKey { messageInputField.SetTitle("[@] Replying to " + m.Author.String()) app.SetFocus(messageInputField) return nil - } else if util.HasKeybinding(conf.Keybindings.CopySelectedMessage, e.Name()) { + } else if util.HasKeybinding(config.Keybindings.CopySelectedMessage, e.Name()) { hs := messagesTextView.GetHighlights() if len(hs) == 0 { return nil @@ -304,14 +305,14 @@ func onMessageInputFieldInputCapture(e *tcell.EventKey) *tcell.EventKey { d.AllowedMentions.RepliedUser = false } - go session.ChannelMessageSendComplex(m.ChannelID, d) + go app.Session.ChannelMessageSendComplex(m.ChannelID, d) selectedMessage = -1 messagesTextView.Highlight() messageInputField.SetTitle("") } else { - go session.ChannelMessageSend(selectedChannel.ID, t) + go app.Session.ChannelMessageSend(selectedChannel.ID, t) } messageInputField.SetText("") diff --git a/ui/app.go b/ui/app.go new file mode 100644 index 0000000..3741ba6 --- /dev/null +++ b/ui/app.go @@ -0,0 +1,48 @@ +package ui + +import ( + "github.com/ayntgl/discordgo" + "github.com/ayntgl/discordo/config" + "github.com/rivo/tview" +) + +type App struct { + *tview.Application + + ChannelsTreeView *tview.TreeView + MessagesTextView *tview.TextView + MessageInputField *tview.InputField + + Session *discordgo.Session +} + +func NewApp() *App { + s, _ := discordgo.New() + return &App{ + Application: tview.NewApplication(), + + ChannelsTreeView: tview.NewTreeView(), + MessagesTextView: tview.NewTextView(), + MessageInputField: tview.NewInputField(), + + Session: s, + } +} + +func (app *App) Connect(token string) error { + app.Session.Token = token + app.Session.UserAgent = config.General.UserAgent + + app.Session.Identify.Token = token + app.Session.Identify.Compress = false + app.Session.Identify.Intents = 0 + app.Session.Identify.LargeThreshold = 0 + app.Session.Identify.Properties.Device = "" + app.Session.Identify.Properties.Browser = "Firefox" + app.Session.Identify.Properties.OS = "Linux" + + // app.Session.AddHandlerOnce(onSessionReady) + // app.Session.AddHandler(onSessionMessageCreate) + + return app.Session.Open() +} diff --git a/ui/channels_treeview.go b/ui/channels_treeview.go deleted file mode 100644 index 86046b1..0000000 --- a/ui/channels_treeview.go +++ /dev/null @@ -1,15 +0,0 @@ -package ui - -import "github.com/rivo/tview" - -func NewChannelsTreeView() *tview.TreeView { - v := tview.NewTreeView() - v. - SetTopLevel(1). - SetRoot(tview.NewTreeNode("")). - SetTitleAlign(tview.AlignLeft). - SetBorder(true). - SetBorderPadding(0, 0, 1, 0) - - return v -} diff --git a/ui/message_inputfield.go b/ui/message_inputfield.go deleted file mode 100644 index 7d06946..0000000 --- a/ui/message_inputfield.go +++ /dev/null @@ -1,19 +0,0 @@ -package ui - -import ( - "github.com/gdamore/tcell/v2" - "github.com/rivo/tview" -) - -func NewMessageInputField() *tview.InputField { - i := tview.NewInputField() - i. - SetPlaceholder("Message..."). - SetPlaceholderTextColor(tcell.ColorWhite). - SetFieldBackgroundColor(tview.Styles.PrimitiveBackgroundColor). - SetTitleAlign(tview.AlignLeft). - SetBorder(true). - SetBorderPadding(0, 0, 1, 0) - - return i -} diff --git a/ui/messages_textview.go b/ui/messages_textview.go deleted file mode 100644 index b4b7112..0000000 --- a/ui/messages_textview.go +++ /dev/null @@ -1,16 +0,0 @@ -package ui - -import "github.com/rivo/tview" - -func NewMessagesTextView() *tview.TextView { - v := tview.NewTextView() - v. - SetRegions(true). - SetDynamicColors(true). - SetWordWrap(true). - SetTitleAlign(tview.AlignLeft). - SetBorder(true). - SetBorderPadding(0, 0, 1, 0) - - return v -} diff --git a/ui/login_form.go b/ui/views.go similarity index 100% rename from ui/login_form.go rename to ui/views.go diff --git a/util/config.go b/util/config.go deleted file mode 100644 index 29387c0..0000000 --- a/util/config.go +++ /dev/null @@ -1,139 +0,0 @@ -package util - -import ( - "os" - - "github.com/BurntSushi/toml" - "github.com/rivo/tview" -) - -const userAgent = "" + - "Mozilla/5.0 (X11; Linux x86_64) " + - "AppleWebKit/537.36 (KHTML, like Gecko) " + - "Chrome/92.0.4515.131 Safari/537.36" - -type keybindings struct { - FocusChannelsTree []string `toml:"focus_channels_tree"` - FocusMessagesView []string `toml:"focus_messages_view"` - FocusMessageInputField []string `toml:"focus_message_input_field"` - - SelectPreviousMessage []string `toml:"select_previous_message"` - SelectNextMessage []string `toml:"select_next_message"` - SelectFirstMessage []string `toml:"select_first_message"` - SelectLastMessage []string `toml:"select_last_message"` - SelectMessageReference []string `toml:"select_message_reference"` - ReplySelectedMessage []string `toml:"reply_selected_message"` - MentionReplySelectedMessage []string `toml:"mention_reply_selected_message"` - CopySelectedMessage []string `toml:"copy_selected_message"` -} - -type theme struct { - Background string `toml:"background"` - - Border string `toml:"border"` - Title string `toml:"title"` - Graphics string `toml:"graphics"` - Text string `toml:"text"` -} - -type borders struct { - Horizontal rune - Vertical rune - TopLeft rune - TopRight rune - BottomLeft rune - BottomRight rune - - HorizontalFocus rune - VerticalFocus rune - TopLeftFocus rune - TopRightFocus rune - BottomLeftFocus rune - BottomRightFocus rune -} - -type Config struct { - Token string `toml:"token"` - UserAgent string `toml:"user_agent"` - Mouse bool `toml:"mouse"` - Notifications bool `toml:"notifications"` - GetMessagesLimit int `toml:"get_messages_limit"` - - Theme theme `toml:"theme"` - Keybindings keybindings `toml:"keybindings"` - Borders borders `toml:"borders"` -} - -// LoadConfig loads the configuration file, if the configuration file exists or creates a new one if not, and returns it. -func LoadConfig() *Config { - configPath, err := os.UserConfigDir() - if err != nil { - panic(err) - } - - configPath += "/discordo.toml" - - var c Config - if _, err = os.Stat(configPath); os.IsNotExist(err) { - f, err := os.Create(configPath) - if err != nil { - panic(err) - } - defer f.Close() - - c = Config{ - Mouse: true, - Notifications: true, - UserAgent: userAgent, - GetMessagesLimit: 50, - Borders: borders{ - Horizontal: 0, - Vertical: 0, - TopLeft: 0, - TopRight: 0, - BottomLeft: 0, - BottomRight: 0, - - HorizontalFocus: tview.BoxDrawingsLightHorizontal, - VerticalFocus: tview.BoxDrawingsLightVertical, - TopLeftFocus: tview.BoxDrawingsLightDownAndRight, - TopRightFocus: tview.BoxDrawingsLightDownAndLeft, - BottomLeftFocus: tview.BoxDrawingsLightUpAndRight, - BottomRightFocus: tview.BoxDrawingsLightUpAndLeft, - }, - Theme: theme{ - Background: "black", - - Border: "white", - Title: "white", - Graphics: "white", - Text: "white", - }, - Keybindings: keybindings{ - FocusChannelsTree: []string{"Alt+Left"}, - FocusMessagesView: []string{"Alt+Right"}, - FocusMessageInputField: []string{"Alt+Down"}, - - SelectPreviousMessage: []string{"Up"}, - SelectNextMessage: []string{"Down"}, - SelectFirstMessage: []string{"Home"}, - SelectLastMessage: []string{"End"}, - ReplySelectedMessage: []string{"Rune[r]"}, - MentionReplySelectedMessage: []string{"Rune[R]"}, - CopySelectedMessage: []string{"Rune[c]"}, - SelectMessageReference: []string{"Rune[m]"}, - }, - } - err = toml.NewEncoder(f).Encode(c) - if err != nil { - panic(err) - } - } else { - _, err = toml.DecodeFile(configPath, &c) - if err != nil { - panic(err) - } - } - - return &c -}