diff --git a/cmd/run/attachment_image.go b/cmd/attachment_image.go similarity index 69% rename from cmd/run/attachment_image.go rename to cmd/attachment_image.go index c9d29d8..d867ec2 100644 --- a/cmd/run/attachment_image.go +++ b/cmd/attachment_image.go @@ -1,4 +1,4 @@ -package run +package cmd import ( "image" @@ -6,7 +6,6 @@ import ( _ "image/png" "net/http" - "github.com/ayn2op/discordo/config" "github.com/diamondburned/arikawa/v3/discord" "github.com/gdamore/tcell/v2" "github.com/rivo/tview" @@ -22,13 +21,13 @@ func newAttachmentImage(a discord.Attachment) (*AttachmentImage, error) { } ai.SetInputCapture(ai.onInputCapture) - ai.SetBackgroundColor(tcell.GetColor(config.Current.Theme.BackgroundColor)) - ai.SetTitleColor(tcell.GetColor(config.Current.Theme.TitleColor)) + ai.SetBackgroundColor(tcell.GetColor(cfg.Theme.BackgroundColor)) + ai.SetTitleColor(tcell.GetColor(cfg.Theme.TitleColor)) ai.SetTitleAlign(tview.AlignLeft) - p := config.Current.Theme.BorderPadding - ai.SetBorder(config.Current.Theme.Border) - ai.SetBorderColor(tcell.GetColor(config.Current.Theme.BorderColor)) + p := cfg.Theme.BorderPadding + ai.SetBorder(cfg.Theme.Border) + ai.SetBorderColor(tcell.GetColor(cfg.Theme.BorderColor)) ai.SetBorderPadding(p[0], p[1], p[2], p[3]) resp, err := http.Get(a.URL) @@ -48,7 +47,7 @@ func newAttachmentImage(a discord.Attachment) (*AttachmentImage, error) { } func (ai *AttachmentImage) onInputCapture(event *tcell.EventKey) *tcell.EventKey { - if event.Name() == config.Current.Keys.Cancel { + if event.Name() == cfg.Keys.Cancel { app.SetRoot(mainFlex, true) app.SetFocus(mainFlex.messagesText) return nil diff --git a/cmd/run/guilds_tree.go b/cmd/guilds_tree.go similarity index 90% rename from cmd/run/guilds_tree.go rename to cmd/guilds_tree.go index 9cbcc0c..f0c7e3b 100644 --- a/cmd/run/guilds_tree.go +++ b/cmd/guilds_tree.go @@ -1,4 +1,4 @@ -package run +package cmd import ( "fmt" @@ -6,7 +6,6 @@ import ( "sort" "strings" - "github.com/ayn2op/discordo/config" "github.com/diamondburned/arikawa/v3/discord" "github.com/diamondburned/arikawa/v3/gateway" "github.com/gdamore/tcell/v2" @@ -29,17 +28,17 @@ func newGuildsTree() *GuildsTree { gt.SetTopLevel(1) gt.SetRoot(gt.root) - gt.SetGraphics(config.Current.Theme.GuildsTree.Graphics) - gt.SetBackgroundColor(tcell.GetColor(config.Current.Theme.BackgroundColor)) + gt.SetGraphics(cfg.Theme.GuildsTree.Graphics) + gt.SetBackgroundColor(tcell.GetColor(cfg.Theme.BackgroundColor)) gt.SetSelectedFunc(gt.onSelected) gt.SetTitle("Guilds") - gt.SetTitleColor(tcell.GetColor(config.Current.Theme.TitleColor)) + gt.SetTitleColor(tcell.GetColor(cfg.Theme.TitleColor)) gt.SetTitleAlign(tview.AlignLeft) - p := config.Current.Theme.BorderPadding - gt.SetBorder(config.Current.Theme.Border) - gt.SetBorderColor(tcell.GetColor(config.Current.Theme.BorderColor)) + p := cfg.Theme.BorderPadding + gt.SetBorder(cfg.Theme.Border) + gt.SetBorderColor(tcell.GetColor(cfg.Theme.BorderColor)) gt.SetBorderPadding(p[0], p[1], p[2], p[3]) return gt @@ -188,7 +187,7 @@ func (gt *GuildsTree) onSelected(n *tview.TreeNode) { gt.createChannelNodes(n, cs) case discord.ChannelID: - ms, err := discordState.Messages(ref, config.Current.MessagesLimit) + ms, err := discordState.Messages(ref, uint(cfg.MessagesLimit)) if err != nil { log.Println(err) return diff --git a/cmd/run/main_flex.go b/cmd/main_flex.go similarity index 84% rename from cmd/run/main_flex.go rename to cmd/main_flex.go index 28d4776..26ad881 100644 --- a/cmd/run/main_flex.go +++ b/cmd/main_flex.go @@ -1,7 +1,6 @@ -package run +package cmd import ( - "github.com/ayn2op/discordo/config" "github.com/gdamore/tcell/v2" "github.com/rivo/tview" ) @@ -43,7 +42,7 @@ func (mf *MainFlex) init() { func (mf *MainFlex) onInputCapture(event *tcell.EventKey) *tcell.EventKey { switch event.Name() { - case config.Current.Keys.GuildsTree.Toggle: + case cfg.Keys.GuildsTree.Toggle: // The guilds tree is visible if the numbers of items is two. if mf.GetItemCount() == 2 { mf.RemoveItem(mf.guildsTree) @@ -57,13 +56,13 @@ func (mf *MainFlex) onInputCapture(event *tcell.EventKey) *tcell.EventKey { } return nil - case config.Current.Keys.GuildsTree.Focus: + case cfg.Keys.GuildsTree.Focus: app.SetFocus(mf.guildsTree) return nil - case config.Current.Keys.MessagesText.Focus: + case cfg.Keys.MessagesText.Focus: app.SetFocus(mf.messagesText) return nil - case config.Current.Keys.MessageInput.Focus: + case cfg.Keys.MessageInput.Focus: app.SetFocus(mf.messageInput) return nil } diff --git a/cmd/run/message_input.go b/cmd/message_input.go similarity index 81% rename from cmd/run/message_input.go rename to cmd/message_input.go index 5e3d18a..2ab9b57 100644 --- a/cmd/run/message_input.go +++ b/cmd/message_input.go @@ -1,4 +1,4 @@ -package run +package cmd import ( "log" @@ -7,7 +7,6 @@ import ( "strings" "github.com/atotto/clipboard" - "github.com/ayn2op/discordo/config" "github.com/ayn2op/discordo/internal/constants" "github.com/diamondburned/arikawa/v3/api" "github.com/diamondburned/arikawa/v3/discord" @@ -25,7 +24,7 @@ func newMessageInput() *MessageInput { TextArea: tview.NewTextArea(), } - mi.SetTextStyle(tcell.StyleDefault.Background(tcell.GetColor(config.Current.Theme.BackgroundColor))) + mi.SetTextStyle(tcell.StyleDefault.Background(tcell.GetColor(cfg.Theme.BackgroundColor))) mi.SetClipboard(func(s string) { _ = clipboard.WriteAll(s) }, func() string { @@ -34,14 +33,14 @@ func newMessageInput() *MessageInput { }) mi.SetInputCapture(mi.onInputCapture) - mi.SetBackgroundColor(tcell.GetColor(config.Current.Theme.BackgroundColor)) + mi.SetBackgroundColor(tcell.GetColor(cfg.Theme.BackgroundColor)) - mi.SetTitleColor(tcell.GetColor(config.Current.Theme.TitleColor)) + mi.SetTitleColor(tcell.GetColor(cfg.Theme.TitleColor)) mi.SetTitleAlign(tview.AlignLeft) - p := config.Current.Theme.BorderPadding - mi.SetBorder(config.Current.Theme.Border) - mi.SetBorderColor(tcell.GetColor(config.Current.Theme.BorderColor)) + p := cfg.Theme.BorderPadding + mi.SetBorder(cfg.Theme.Border) + mi.SetBorderColor(tcell.GetColor(cfg.Theme.BorderColor)) mi.SetBorderPadding(p[0], p[1], p[2], p[3]) return mi @@ -54,15 +53,15 @@ func (mi *MessageInput) reset() { func (mi *MessageInput) onInputCapture(event *tcell.EventKey) *tcell.EventKey { switch event.Name() { - case config.Current.Keys.MessageInput.Send: + case cfg.Keys.MessageInput.Send: mi.sendAction() return nil case "Alt+Enter": return tcell.NewEventKey(tcell.KeyEnter, 0, tcell.ModNone) - case config.Current.Keys.MessageInput.LaunchEditor: + case cfg.Keys.MessageInput.LaunchEditor: mainFlex.messageInput.launchEditorAction() return nil - case config.Current.Keys.Cancel: + case cfg.Keys.Cancel: mi.reset() return nil } @@ -108,7 +107,7 @@ func (mi *MessageInput) sendAction() { } func (mi *MessageInput) launchEditorAction() { - e := config.Current.Editor + e := cfg.Editor if e == "default" { e = os.Getenv("EDITOR") } diff --git a/cmd/run/messages_text.go b/cmd/messages_text.go similarity index 84% rename from cmd/run/messages_text.go rename to cmd/messages_text.go index baa3078..5b660a2 100644 --- a/cmd/run/messages_text.go +++ b/cmd/messages_text.go @@ -1,4 +1,4 @@ -package run +package cmd import ( "fmt" @@ -7,7 +7,6 @@ import ( "time" "github.com/atotto/clipboard" - "github.com/ayn2op/discordo/config" "github.com/ayn2op/discordo/markdown" "github.com/diamondburned/arikawa/v3/discord" "github.com/gdamore/tcell/v2" @@ -36,15 +35,15 @@ func newMessagesText() *MessagesText { app.Draw() }) - mt.SetBackgroundColor(tcell.GetColor(config.Current.Theme.BackgroundColor)) + mt.SetBackgroundColor(tcell.GetColor(cfg.Theme.BackgroundColor)) mt.SetTitle("Messages") - mt.SetTitleColor(tcell.GetColor(config.Current.Theme.TitleColor)) + mt.SetTitleColor(tcell.GetColor(cfg.Theme.TitleColor)) mt.SetTitleAlign(tview.AlignLeft) - p := config.Current.Theme.BorderPadding - mt.SetBorder(config.Current.Theme.Border) - mt.SetBorderColor(tcell.GetColor(config.Current.Theme.BorderColor)) + p := cfg.Theme.BorderPadding + mt.SetBorder(cfg.Theme.Border) + mt.SetBorderColor(tcell.GetColor(cfg.Theme.BorderColor)) mt.SetBorderPadding(p[0], p[1], p[2], p[3]) return mt @@ -85,17 +84,17 @@ func (mt *MessagesText) createMessage(m discord.Message) { func (mt *MessagesText) createHeader(w io.Writer, m discord.Message, isReply bool) { time := m.Timestamp.Format(time.Kitchen) - if config.Current.Timestamps && config.Current.TimestampsBeforeAuthor { + if cfg.Timestamps && cfg.TimestampsBeforeAuthor { fmt.Fprintf(w, "[::d]%7s[::-] ", time) } if isReply { - fmt.Fprintf(mt, "[::d]%s", config.Current.Theme.MessagesText.ReplyIndicator) + fmt.Fprintf(mt, "[::d]%s", cfg.Theme.MessagesText.ReplyIndicator) } - fmt.Fprintf(w, "[%s]%s[-:-:-] ", config.Current.Theme.MessagesText.AuthorColor, m.Author.Username) + fmt.Fprintf(w, "[%s]%s[-:-:-] ", cfg.Theme.MessagesText.AuthorColor, m.Author.Username) - if config.Current.Timestamps && !config.Current.TimestampsBeforeAuthor { + if cfg.Timestamps && !cfg.TimestampsBeforeAuthor { fmt.Fprintf(w, "[::d]%s[::-] ", time) } } @@ -113,37 +112,37 @@ func (mt *MessagesText) createFooter(w io.Writer, m discord.Message) { func (mt *MessagesText) onInputCapture(event *tcell.EventKey) *tcell.EventKey { switch event.Name() { - case config.Current.Keys.MessagesText.CopyContent: + case cfg.Keys.MessagesText.CopyContent: mt.copyContentAction() return nil - case config.Current.Keys.MessagesText.Reply: + case cfg.Keys.MessagesText.Reply: mt.replyAction(false) return nil - case config.Current.Keys.MessagesText.ReplyMention: + case cfg.Keys.MessagesText.ReplyMention: mt.replyAction(true) return nil - case config.Current.Keys.MessagesText.SelectPrevious: + case cfg.Keys.MessagesText.SelectPrevious: mt.selectPreviousAction() return nil - case config.Current.Keys.MessagesText.SelectNext: + case cfg.Keys.MessagesText.SelectNext: mt.selectNextAction() return nil - case config.Current.Keys.MessagesText.SelectFirst: + case cfg.Keys.MessagesText.SelectFirst: mt.selectFirstAction() return nil - case config.Current.Keys.MessagesText.SelectLast: + case cfg.Keys.MessagesText.SelectLast: mt.selectLastAction() return nil - case config.Current.Keys.MessagesText.SelectReply: + case cfg.Keys.MessagesText.SelectReply: mt.selectReplyAction() return nil - case config.Current.Keys.MessagesText.ShowImage: + case cfg.Keys.MessagesText.ShowImage: mt.showImageAction() return nil - case config.Current.Keys.MessagesText.Delete: + case cfg.Keys.MessagesText.Delete: mt.deleteAction() return nil - case config.Current.Keys.Cancel: + case cfg.Keys.Cancel: mainFlex.guildsTree.selectedChannelID = 0 mainFlex.messagesText.reset() diff --git a/cmd/run/run.go b/cmd/run.go similarity index 76% rename from cmd/run/run.go rename to cmd/run.go index d4c04db..dd9fd5a 100644 --- a/cmd/run/run.go +++ b/cmd/run.go @@ -1,11 +1,13 @@ -package run +package cmd import ( + "fmt" "log" "os" "path/filepath" - "github.com/ayn2op/discordo/config" + oldConfig "github.com/ayn2op/discordo/config" + "github.com/ayn2op/discordo/internal/config" "github.com/ayn2op/discordo/ui" "github.com/rivo/tview" ) @@ -13,23 +15,21 @@ import ( var ( discordState *State + cfg *config.Config app = tview.NewApplication() mainFlex *MainFlex ) func Run(token string) error { - path := config.DefaultPath() - err := os.MkdirAll(filepath.Dir(path), os.ModePerm) + var err error + cfg, err = config.Load() if err != nil { return err } - err = config.Load(path) - if err != nil { - return err - } + fmt.Printf("%+v\n", cfg) - path = config.DefaultLogPath() + path := oldConfig.DefaultLogPath() err = os.MkdirAll(filepath.Dir(path), os.ModePerm) if err != nil { return err @@ -44,7 +44,7 @@ func Run(token string) error { log.SetFlags(log.LstdFlags | log.Llongfile) if token == "" { - lf := ui.NewLoginForm() + lf := ui.NewLoginForm(cfg) go func() { mainFlex = newMainFlex() @@ -73,6 +73,6 @@ func Run(token string) error { app.SetRoot(mainFlex, true) } - app.EnableMouse(config.Current.Mouse) + app.EnableMouse(cfg.Mouse) return app.Run() } diff --git a/cmd/run/state.go b/cmd/state.go similarity index 99% rename from cmd/run/state.go rename to cmd/state.go index 51e0ae2..b1ed7e8 100644 --- a/cmd/run/state.go +++ b/cmd/state.go @@ -1,4 +1,4 @@ -package run +package cmd import ( "context" diff --git a/config/config.go b/config/config.go index 8cb8d04..4b4f481 100644 --- a/config/config.go +++ b/config/config.go @@ -5,74 +5,8 @@ import ( "path/filepath" "github.com/ayn2op/discordo/internal/constants" - "gopkg.in/yaml.v3" ) -var Current = defConfig() - -type Config struct { - // Mouse indicates whether the mouse is usable or not. - Mouse bool `yaml:"mouse"` - // MessagesLimit is the number of messages to fetch when a text-based channel is selected. - MessagesLimit uint `yaml:"messages_limit"` - // TimestampsBeforeAuthor indicates whether to draw the timestamp before or after the author. - TimestampsBeforeAuthor bool `yaml:"timestamps_before_author"` - // Timestamps indicates whether to draw the timestamp in front of the message or not. - Timestamps bool `yaml:"timestamps"` - // Editor is the program to open when the `LaunchEditor` key is pressed. If the value of the field is "default", the `$EDITOR` environment variable is used instead. - Editor string `yaml:"editor"` - - Keys Keys `yaml:"keys"` - Theme Theme `yaml:"theme"` -} - -func defConfig() Config { - return Config{ - Mouse: true, - TimestampsBeforeAuthor: false, - Timestamps: false, - MessagesLimit: 50, - Editor: "default", - - Keys: defKeys(), - Theme: defTheme(), - } -} - -func Load(path string) error { - _, err := os.Stat(path) - if os.IsNotExist(err) { - f, err := os.Create(path) - if err != nil { - return err - } - defer f.Close() - - err = yaml.NewEncoder(f).Encode(Current) - if err != nil { - return err - } - } else { - f, err := os.Open(path) - if err != nil { - return err - } - defer f.Close() - - err = yaml.NewDecoder(f).Decode(&Current) - if err != nil { - return err - } - } - - return nil -} - -func DefaultPath() string { - path, _ := os.UserConfigDir() - return filepath.Join(path, constants.Name, "config.yml") -} - func DefaultLogPath() string { path, _ := os.UserCacheDir() return filepath.Join(path, constants.Name, "logs.txt") diff --git a/config/keys.go b/config/keys.go deleted file mode 100644 index e526de4..0000000 --- a/config/keys.go +++ /dev/null @@ -1,77 +0,0 @@ -package config - -type ( - GuildsTreeKeys struct { - Focus string `yaml:"focus"` - Toggle string `yaml:"toggle"` - } - - MessagesTextKeys struct { - Focus string `yaml:"focus"` - - ShowImage string `yaml:"show_image"` - CopyContent string `yaml:"copy_content"` - - Reply string `yaml:"reply"` - ReplyMention string `yaml:"reply_mention"` - SelectReply string `yaml:"select_reply"` - - Delete string `yaml:"delete"` - - SelectPrevious string `yaml:"select_previous"` - SelectNext string `yaml:"select_next"` - SelectFirst string `yaml:"select_first"` - SelectLast string `yaml:"select_last"` - } - - MessageInputKeys struct { - Focus string `yaml:"focus"` - - Send string `yaml:"send"` - LaunchEditor string `yaml:"launch_editor"` - } -) - -type Keys struct { - Cancel string `yaml:"cancel"` - - GuildsTree GuildsTreeKeys `yaml:"guilds_tree"` - MessagesText MessagesTextKeys `yaml:"messages_text"` - MessageInput MessageInputKeys `yaml:"message_input"` -} - -func defKeys() Keys { - return Keys{ - Cancel: "Esc", - - GuildsTree: GuildsTreeKeys{ - Focus: "Alt+Rune[g]", - Toggle: "Alt+Rune[b]", - }, - - MessagesText: MessagesTextKeys{ - Focus: "Alt+Rune[m]", - - ShowImage: "Rune[i]", - CopyContent: "Rune[c]", - - Reply: "Rune[r]", - ReplyMention: "Rune[R]", - SelectReply: "Rune[s]", - - Delete: "Rune[d]", - - SelectPrevious: "Up", - SelectNext: "Down", - SelectFirst: "Home", - SelectLast: "End", - }, - - MessageInput: MessageInputKeys{ - Focus: "Alt+Rune[i]", - - Send: "Enter", - LaunchEditor: "Ctrl+E", - }, - } -} diff --git a/config/theme.go b/config/theme.go deleted file mode 100644 index 4572560..0000000 --- a/config/theme.go +++ /dev/null @@ -1,48 +0,0 @@ -package config - -type ( - GuildsTreeTheme struct { - // Graphics indicates whether to draw the line graphics to illustrate the hierarchy or not. - Graphics bool `yaml:"graphics"` - } - - MessagesTextTheme struct { - AuthorColor string `yaml:"author_color"` - ReplyIndicator string `yaml:"reply_indicator"` - } - - MessageInputTheme struct{} -) - -type Theme struct { - Border bool `yaml:"border"` - BorderColor string `yaml:"border_color"` - BorderPadding [4]int `yaml:"border_padding,flow"` - - TitleColor string `yaml:"title_color"` - BackgroundColor string `yaml:"background_color"` - - GuildsTree GuildsTreeTheme `yaml:"guilds_tree"` - MessagesText MessagesTextTheme `yaml:"messages_text"` - MessageInput MessageInputTheme `yaml:"message_input"` -} - -func defTheme() Theme { - return Theme{ - Border: true, - BorderColor: "default", - BorderPadding: [...]int{0, 0, 1, 1}, - - TitleColor: "default", - BackgroundColor: "default", - - GuildsTree: GuildsTreeTheme{ - Graphics: true, - }, - MessagesText: MessagesTextTheme{ - AuthorColor: "aqua", - ReplyIndicator: "╭", - }, - MessageInput: MessageInputTheme{}, - } -} diff --git a/go.mod b/go.mod index afaaf2f..b31fb7f 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/atotto/clipboard v0.1.4 github.com/diamondburned/arikawa/v3 v3.3.3 github.com/gdamore/tcell/v2 v2.6.0 - github.com/rivo/tview v0.0.0-20231007183732-6c844bdc5f7a + github.com/rivo/tview v0.0.0-20231024211518-8b7bcf9883df github.com/zalando/go-keyring v0.2.3 gopkg.in/yaml.v3 v3.0.1 ) diff --git a/go.sum b/go.sum index 784c54f..a773b25 100644 --- a/go.sum +++ b/go.sum @@ -30,6 +30,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/tview v0.0.0-20231007183732-6c844bdc5f7a h1:368NWOLkcJirQFjVSUfB6LWbkas6fd8lQ3DbO66tw1w= github.com/rivo/tview v0.0.0-20231007183732-6c844bdc5f7a/go.mod h1:nVwGv4MP47T0jvlk7KuTTjjuSmrGO4JF0iaiNt4bufE= +github.com/rivo/tview v0.0.0-20231024211518-8b7bcf9883df h1:G91TSQNNlR4hRz11lqKKp98ffxqPbEu2rUjxJSkUM4A= +github.com/rivo/tview v0.0.0-20231024211518-8b7bcf9883df/go.mod h1:nVwGv4MP47T0jvlk7KuTTjjuSmrGO4JF0iaiNt4bufE= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= diff --git a/internal/config/config.go b/internal/config/config.go new file mode 100644 index 0000000..2082970 --- /dev/null +++ b/internal/config/config.go @@ -0,0 +1,110 @@ +package config + +import ( + "bytes" + _ "embed" + "io" + "os" + "path/filepath" + + "github.com/ayn2op/discordo/internal/constants" + "gopkg.in/yaml.v3" +) + +//go:embed config.yml +var defaultConfig []byte + +type Config struct { + Mouse bool `yaml:"mouse"` + + Timestamps bool `yaml:"timestamps"` + TimestampsBeforeAuthor bool `yaml:"timestamps_before_author"` + + MessagesLimit uint8 `yaml:"messages_limit"` + + Editor string `yaml:"editor"` + + Keys struct { + Cancel string `yaml:"cancel"` + + GuildsTree struct { + Focus string `yaml:"focus"` + Toggle string `yaml:"toggle"` + } `yaml:"guilds_tree"` + + MessagesText struct { + Focus string `yaml:"focus"` + + ShowImage string `yaml:"show_image"` + CopyContent string `yaml:"copy_content"` + + Reply string `yaml:"reply"` + ReplyMention string `yaml:"reply_mention"` + + Delete string `yaml:"delete"` + + SelectPrevious string `yaml:"select_previous"` + SelectNext string `yaml:"select_next"` + SelectFirst string `yaml:"select_first"` + SelectLast string `yaml:"select_last"` + SelectReply string `yaml:"select_reply"` + } `yaml:"messages_text"` + + MessageInput struct { + Focus string `yaml:"focus"` + + Send string `yaml:"send"` + LaunchEditor string `yaml:"launch_editor"` + } `yaml:"message_input"` + } `yaml:"keys"` + Theme struct { + Border bool `yaml:"border"` + BorderColor string `yaml:"border_color"` + BorderPadding [4]int `yaml:"border_padding,flow"` + + TitleColor string `yaml:"title_color"` + BackgroundColor string `yaml:"background_color"` + + GuildsTree struct { + Graphics bool `yaml:"graphics"` + } `yaml:"guilds_tree"` + + MessagesText struct { + AuthorColor string `yaml:"author_color"` + ReplyIndicator string `yaml:"reply_indicator"` + } `yaml:"messages_text"` + } `yaml:"theme"` +} + +func Load() (*Config, error) { + path, err := os.UserConfigDir() + if err != nil { + return nil, err + } + + path = filepath.Join(path, constants.Name) + if err := os.MkdirAll(path, os.ModePerm); err != nil { + return nil, err + } + + path = filepath.Join(path, "config.yml") + + f, err := os.Open(path) + reader := io.Reader(f) + if os.IsNotExist(err) { + err = os.WriteFile(path, defaultConfig, os.ModePerm) + reader = bytes.NewReader(defaultConfig) + } + + if err != nil { + return nil, err + } + defer f.Close() + + var cfg Config + if err := yaml.NewDecoder(reader).Decode(&cfg); err != nil { + return nil, err + } + + return &cfg, nil +} diff --git a/internal/config/config.yml b/internal/config/config.yml new file mode 100644 index 0000000..c55c4ff --- /dev/null +++ b/internal/config/config.yml @@ -0,0 +1,56 @@ +# Whether the mouse is usable or not. +mouse: true + +# Whether to draw the timestamps of the corresponding message in front of it. +timestamps: false +# Whether to draw the timestamps before the name of author of the message or not. +timestamps_before_author: false + +# The number of messages to fetch when a text-based channel is selected. The value must be >0 and <=100. +messages_limit: 50 + +# The name of the program to launch when the launch_editor key is pressed. If the value of the field is set to "default", the `$EDITOR` environment variable is used instead. +editor: default + +keys: + cancel: Esc + + guilds_tree: + focus: Alt+Rune[g] + toggle: Alt+Rune[b] + + messages_text: + focus: Alt+Rune[m] + show_image: Rune[i] + copy_content: Rune[c] + delete: Rune[d] + + reply: Rune[r] + reply_mention: Rune[R] + + select_previous: Up + select_next: Down + select_first: Home + select_last: End + select_reply: Rune[s] + + message_input: + focus: Alt+Rune[i] + + send: Enter + launch_editor: Ctrl+E + +theme: + border: true + border_color: default + border_padding: [0, 0, 1, 1] + + title_color: default + background_color: default + + guilds_tree: + graphics: true + + messages_text: + author_color: aqua + reply_indicator: ╭ diff --git a/internal/config/config_test.go b/internal/config/config_test.go new file mode 100644 index 0000000..d912156 --- /dev/null +++ b/internal/config/config_test.go @@ -0,0 +1 @@ +package config diff --git a/main.go b/main.go index fafc40e..937ac42 100644 --- a/main.go +++ b/main.go @@ -4,7 +4,7 @@ import ( "flag" "log" - "github.com/ayn2op/discordo/cmd/run" + "github.com/ayn2op/discordo/cmd" "github.com/ayn2op/discordo/internal/constants" "github.com/zalando/go-keyring" ) @@ -14,7 +14,7 @@ func main() { token := flag.String("token", t, "The authentication token.") flag.Parse() - if err := run.Run(*token); err != nil { + if err := cmd.Run(*token); err != nil { log.Fatal(err) } } diff --git a/ui/login_form.go b/ui/login_form.go index 0586ac5..f217f67 100644 --- a/ui/login_form.go +++ b/ui/login_form.go @@ -3,7 +3,7 @@ package ui import ( "errors" - "github.com/ayn2op/discordo/config" + "github.com/ayn2op/discordo/internal/config" "github.com/ayn2op/discordo/internal/constants" "github.com/diamondburned/arikawa/v3/api" "github.com/gdamore/tcell/v2" @@ -17,7 +17,7 @@ type LoginForm struct { Error chan error } -func NewLoginForm() *LoginForm { +func NewLoginForm(cfg *config.Config) *LoginForm { lf := &LoginForm{ Form: tview.NewForm(), Token: make(chan string, 1), @@ -31,12 +31,12 @@ func NewLoginForm() *LoginForm { lf.AddButton("Login", lf.onLoginButtonSelected) lf.SetTitle("Login") - lf.SetTitleColor(tcell.GetColor(config.Current.Theme.TitleColor)) + lf.SetTitleColor(tcell.GetColor(cfg.Theme.TitleColor)) lf.SetTitleAlign(tview.AlignLeft) - p := config.Current.Theme.BorderPadding - lf.SetBorder(config.Current.Theme.Border) - lf.SetBorderColor(tcell.GetColor(config.Current.Theme.BorderColor)) + p := cfg.Theme.BorderPadding + lf.SetBorder(cfg.Theme.Border) + lf.SetBorderColor(tcell.GetColor(cfg.Theme.BorderColor)) lf.SetBorderPadding(p[0], p[1], p[2], p[3]) return lf