Merge branch 'main' into add-nix
This commit is contained in:
commit
0dd45a3fbc
7 changed files with 176 additions and 179 deletions
42
README.md
42
README.md
|
|
@ -55,46 +55,6 @@ go build .
|
|||
|
||||
2. Enter your email and password and click on the "Login" button to continue.
|
||||
|
||||
## Keymaps
|
||||
|
||||
### Global
|
||||
|
||||
- `Ctrl+G`: Focus Guilds Tree
|
||||
- `Ctrl+T`: Focus Messages Text
|
||||
- `Ctrl+P`: Focus Message Input
|
||||
- `Ctrl+B`: Toggle Guilds Tree (sidebar)
|
||||
- `Esc`: Reset message selection or close the channel selection popup.
|
||||
- `Ctrl+C`: Quit the application.
|
||||
- `Ctrl+D`: Log out and remove the authentication token from keyring (requires re-login upon restart).
|
||||
|
||||
#### Navigation
|
||||
|
||||
- `k`: Select Previous (any context except input)
|
||||
- `j`: Select Next (any context except input)
|
||||
- `g`: Select First (any context except input)
|
||||
- `G`: Select Last (any context except input)
|
||||
|
||||
### Guilds Tree
|
||||
|
||||
- `Enter`: Select the currently highlighted text-based channel or expand a guild or channel.
|
||||
|
||||
### Message Text
|
||||
|
||||
- `s`: Select the message reference (reply) of the selected channel.
|
||||
- `p`: Select the pinned message.
|
||||
- `r`: Reply to the selected message.
|
||||
- `R`: Reply (with mention) to the selected message.
|
||||
- `d`: Delete the selected message.
|
||||
- `y`: Yank (copy) the selected message's content.
|
||||
- `o`: Open the selected message's attachments in the default browser application.
|
||||
|
||||
### Message Input
|
||||
|
||||
- `Alt+Enter`: Insert a new line to the current text.
|
||||
- `Enter`: Send the message.
|
||||
- `Ctrl+E`: Open message input in your default `$EDITOR`.
|
||||
- `Esc`: Remove existing text or cancel reply.
|
||||
|
||||
## Configuration
|
||||
|
||||
The configuration file allows you to configure and customize the behavior, keybindings, and theme of the application.
|
||||
|
|
@ -103,7 +63,7 @@ The configuration file allows you to configure and customize the behavior, keybi
|
|||
- Darwin: `$HOME/Library/Application Support/discordo/config.toml`
|
||||
- Windows: `%AppData%/discordo/config.toml`
|
||||
|
||||
[The default configuration can be found here](./internal/config/config.go).
|
||||
[The default configuration can be found here](./internal/config/config.toml).
|
||||
|
||||
## FAQ
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,11 @@ var (
|
|||
|
||||
func Run() error {
|
||||
logLevel := flag.String("log-level", "info", "log level")
|
||||
logFormat := flag.String("log-format", "text", "log format")
|
||||
token := flag.String("token", "", "authentication token")
|
||||
configPath := flag.String("config", config.DefaultPath(), "path to the configuration file")
|
||||
flag.Parse()
|
||||
|
||||
var level slog.Level
|
||||
switch *logLevel {
|
||||
case "debug":
|
||||
|
|
@ -33,7 +38,6 @@ func Run() error {
|
|||
level = slog.LevelError
|
||||
}
|
||||
|
||||
logFormat := flag.String("log-format", "text", "log format")
|
||||
var format logger.Format
|
||||
switch *logFormat {
|
||||
case "text":
|
||||
|
|
@ -46,7 +50,6 @@ func Run() error {
|
|||
return err
|
||||
}
|
||||
|
||||
token := flag.String("token", "", "authentication token")
|
||||
tok := *token
|
||||
if tok == "" {
|
||||
var err error
|
||||
|
|
@ -56,7 +59,7 @@ func Run() error {
|
|||
}
|
||||
}
|
||||
|
||||
cfg, err := config.Load()
|
||||
cfg, err := config.Load(*configPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ func (p *BorderPreset) UnmarshalTOML(v any) error {
|
|||
*p = borderPresetThick()
|
||||
case "round":
|
||||
*p = borderPresetRound()
|
||||
case "light":
|
||||
*p = borderPresetLight()
|
||||
case "hidden":
|
||||
*p = BorderPreset{
|
||||
Horizontal: ' ',
|
||||
|
|
@ -65,3 +67,14 @@ func borderPresetRound() BorderPreset {
|
|||
BottomRight: tview.BoxDrawingsLightArcUpAndLeft,
|
||||
}
|
||||
}
|
||||
|
||||
func borderPresetLight() BorderPreset {
|
||||
return BorderPreset{
|
||||
Horizontal: tview.BoxDrawingsLightHorizontal,
|
||||
Vertical: tview.BoxDrawingsLightVertical,
|
||||
TopLeft: tview.BoxDrawingsLightDownAndRight,
|
||||
TopRight: tview.BoxDrawingsLightDownAndLeft,
|
||||
BottomLeft: tview.BoxDrawingsLightUpAndRight,
|
||||
BottomRight: tview.BoxDrawingsLightUpAndLeft,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/ayn2op/discordo/internal/consts"
|
||||
|
|
@ -56,57 +56,31 @@ type (
|
|||
}
|
||||
)
|
||||
|
||||
func defaultConfig() *Config {
|
||||
return &Config{
|
||||
Mouse: true,
|
||||
Editor: "default",
|
||||
//go:embed config.toml
|
||||
var defaultCfg []byte
|
||||
|
||||
HideBlockedUsers: true,
|
||||
ShowAttachmentLinks: true,
|
||||
MessagesLimit: 50,
|
||||
|
||||
MarkdownEnabled: true,
|
||||
|
||||
Timestamps: Timestamps{
|
||||
Enabled: true,
|
||||
Format: time.Kitchen,
|
||||
},
|
||||
|
||||
Identify: Identify{
|
||||
Status: discord.OnlineStatus,
|
||||
Browser: consts.Browser,
|
||||
BrowserVersion: consts.BrowserVersion,
|
||||
UserAgent: consts.UserAgent,
|
||||
},
|
||||
|
||||
Notifications: Notifications{
|
||||
Enabled: true,
|
||||
Duration: 500,
|
||||
Sound: Sound{
|
||||
Enabled: true,
|
||||
OnlyOnPing: true,
|
||||
},
|
||||
},
|
||||
|
||||
Keys: defaultKeys(),
|
||||
Theme: defaultTheme(),
|
||||
}
|
||||
}
|
||||
|
||||
// Reads the configuration file and parses it.
|
||||
func Load() (*Config, error) {
|
||||
func DefaultPath() string {
|
||||
path, err := os.UserConfigDir()
|
||||
if err != nil {
|
||||
slog.Info("user configuration directory path cannot be determined; falling back to the current directory path")
|
||||
path = "."
|
||||
}
|
||||
|
||||
path = filepath.Join(path, consts.Name, fileName)
|
||||
return filepath.Join(path, consts.Name, fileName)
|
||||
}
|
||||
|
||||
// Reads the configuration file and parses it.
|
||||
func Load(path string) (*Config, error) {
|
||||
f, err := os.Open(path)
|
||||
|
||||
cfg := defaultConfig()
|
||||
var cfg *Config
|
||||
if err := toml.Unmarshal(defaultCfg, &cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if os.IsNotExist(err) {
|
||||
slog.Info("the configuration file does not exist, falling back to the default configuration", "path", path, "err", err)
|
||||
handleDefaults(cfg)
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
|
|
@ -119,5 +93,18 @@ func Load() (*Config, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
handleDefaults(cfg)
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func handleDefaults(cfg *Config) {
|
||||
if cfg.Identify.Browser == "default" {
|
||||
cfg.Identify.Browser = consts.Browser
|
||||
}
|
||||
if cfg.Identify.BrowserVersion == "default" {
|
||||
cfg.Identify.BrowserVersion = consts.BrowserVersion
|
||||
}
|
||||
if cfg.Identify.UserAgent == "default" {
|
||||
cfg.Identify.UserAgent = consts.UserAgent
|
||||
}
|
||||
}
|
||||
|
|
|
|||
128
internal/config/config.toml
Normal file
128
internal/config/config.toml
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
# Enable mouse controls
|
||||
mouse = true
|
||||
|
||||
# "default" means use $EDITOR.
|
||||
editor = "default"
|
||||
|
||||
hide_blocked_users = true
|
||||
show_attachment_links = true
|
||||
messages_limit = 50
|
||||
markdown_enabled = true
|
||||
|
||||
# Timestamps uses Go timestamp format
|
||||
# See: https://gosamples.dev/date-time-format-cheatsheet
|
||||
[timestamps]
|
||||
enabled = true
|
||||
format = "3:04PM"
|
||||
|
||||
[notifications]
|
||||
enabled = true
|
||||
duration = 500
|
||||
[notifications.sound]
|
||||
enabled = true
|
||||
only_on_ping = true
|
||||
|
||||
# How Discord sees us.
|
||||
# status: "online", "idle", "dnd" (Do Not Disturb), "" (invisible),
|
||||
# note: does not seem to work
|
||||
[identify]
|
||||
status = "online"
|
||||
browser = "default"
|
||||
browser_version = "default"
|
||||
user_agent = "default"
|
||||
|
||||
# Global shortcuts
|
||||
# Esc: Reset message selection or close the channel selection popup.
|
||||
[keys]
|
||||
focus_guilds_tree = "Ctrl+G"
|
||||
focus_messages_text = "Ctrl+T"
|
||||
focus_message_input = "Ctrl+P"
|
||||
# Hide/show the guilds tree
|
||||
toggle_guilds_tree = "Ctrl+B"
|
||||
quit = "Ctrl+C"
|
||||
# Log out and remove the authentication token from keyring.
|
||||
# Requires re-login upon restart.
|
||||
logout = "Ctrl+D"
|
||||
|
||||
# Only while focusing on the guilds tree
|
||||
[keys.guilds_tree]
|
||||
select_previous = "Rune[k]"
|
||||
select_next = "Rune[j]"
|
||||
select_first = "Rune[g]"
|
||||
select_last = "Rune[G]"
|
||||
# Select the currently highlighted text-based channel or expand a guild or channel.
|
||||
select_current = "Enter"
|
||||
yank_id = "Rune[i]"
|
||||
collapse_parent_node = "Rune[-]"
|
||||
move_to_parent_node = "Rune[p]"
|
||||
|
||||
# Only while focusing on sent messages
|
||||
[keys.messages_text]
|
||||
select_previous = "Rune[k]"
|
||||
select_next = "Rune[j]"
|
||||
select_first = "Rune[g]"
|
||||
select_last = "Rune[G]"
|
||||
# Select the message reference (reply) of the selected channel.
|
||||
select_reply = "Rune[s]"
|
||||
# Reply to the selected message.
|
||||
reply = "Rune[r]"
|
||||
# Reply (with mention) to the selected message.
|
||||
reply_mention = "Rune[R]"
|
||||
cancel = "Esc"
|
||||
delete = "Rune[d]"
|
||||
# Open the selected message's attachments or hyperlinks in the message
|
||||
# using the default browser application.
|
||||
open = "Rune[o]"
|
||||
# Yank (copy) the selected message's content/url/id.
|
||||
yank_content = "Rune[y]"
|
||||
yank_url = "Rune[u]"
|
||||
yank_id = "Rune[i]"
|
||||
|
||||
# Only while typing a message
|
||||
# Alt+Enter: Insert a new line to the current text.
|
||||
[keys.message_input]
|
||||
# Send the message.
|
||||
send = "Enter"
|
||||
# Open message input in your editor.
|
||||
editor = "Ctrl+E"
|
||||
# Remove existing text or cancel reply.
|
||||
cancel = "Esc"
|
||||
|
||||
# Applies to all
|
||||
[theme]
|
||||
background_color = "default"
|
||||
|
||||
[theme.title]
|
||||
# Title color of non-focused widgets
|
||||
color = "default"
|
||||
# Title color of the focused widget
|
||||
active_color = "green"
|
||||
align = "left"
|
||||
|
||||
[theme.border]
|
||||
enabled = true
|
||||
# [top, bottom, left, right]
|
||||
padding = [0, 0, 1, 1]
|
||||
color = "default"
|
||||
active_color = "green"
|
||||
preset = "round"
|
||||
|
||||
[theme.guilds_tree]
|
||||
auto_expand_folders = true
|
||||
# Give tree-like shape
|
||||
graphics = true
|
||||
private_channel_color = "white"
|
||||
guild_color = "white"
|
||||
channel_color = "white"
|
||||
|
||||
[theme.messages_text]
|
||||
# Set to false to show messages with usernames instead of nicknames
|
||||
show_user_nicks = true
|
||||
show_user_colors = true
|
||||
reply_indicator = ">"
|
||||
forwarded_indicator = "<"
|
||||
author_color = "aqua"
|
||||
content_color = "white"
|
||||
emoji_color = "green"
|
||||
link_color = "blue"
|
||||
attachment_color = "yellow"
|
||||
|
|
@ -52,55 +52,3 @@ type (
|
|||
Cancel string `toml:"cancel"`
|
||||
}
|
||||
)
|
||||
|
||||
func defaultKeys() Keys {
|
||||
return Keys{
|
||||
FocusGuildsTree: "Ctrl+G",
|
||||
FocusMessagesText: "Ctrl+T",
|
||||
FocusMessageInput: "Ctrl+P",
|
||||
ToggleGuildsTree: "Ctrl+B",
|
||||
|
||||
Logout: "Ctrl+D",
|
||||
Quit: "Ctrl+C",
|
||||
|
||||
GuildsTree: GuildsTreeKeys{
|
||||
NavigationKeys: NavigationKeys{
|
||||
SelectPrevious: "Rune[k]",
|
||||
SelectNext: "Rune[j]",
|
||||
SelectFirst: "Rune[g]",
|
||||
SelectLast: "Rune[G]",
|
||||
},
|
||||
SelectCurrent: "Enter",
|
||||
YankID: "Rune[i]",
|
||||
CollapseParentNode: "Rune[-]",
|
||||
MoveToParentNode: "Rune[p]",
|
||||
},
|
||||
|
||||
MessagesText: MessagesTextKeys{
|
||||
NavigationKeys: NavigationKeys{
|
||||
SelectPrevious: "Rune[k]",
|
||||
SelectNext: "Rune[j]",
|
||||
SelectFirst: "Rune[g]",
|
||||
SelectLast: "Rune[G]",
|
||||
},
|
||||
SelectReply: "Rune[s]",
|
||||
|
||||
Reply: "Rune[r]",
|
||||
ReplyMention: "Rune[R]",
|
||||
|
||||
Cancel: "Esc",
|
||||
Delete: "Rune[d]",
|
||||
Open: "Rune[o]",
|
||||
|
||||
YankContent: "Rune[y]",
|
||||
YankURL: "Rune[u]",
|
||||
YankID: "Rune[i]",
|
||||
},
|
||||
|
||||
MessageInput: MessageInputKeys{
|
||||
Send: "Enter",
|
||||
Editor: "Ctrl+E",
|
||||
Cancel: "Esc",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,45 +68,3 @@ type (
|
|||
AttachmentColor string `toml:"attachment_color"`
|
||||
}
|
||||
)
|
||||
|
||||
func defaultTheme() Theme {
|
||||
return Theme{
|
||||
BackgroundColor: "default",
|
||||
|
||||
Border: BorderTheme{
|
||||
Enabled: true,
|
||||
Padding: [...]int{0, 0, 1, 1},
|
||||
|
||||
Color: "default",
|
||||
ActiveColor: "green",
|
||||
Preset: borderPresetRound(),
|
||||
},
|
||||
|
||||
Title: TitleTheme{
|
||||
Color: "default",
|
||||
ActiveColor: "green",
|
||||
Align: tview.AlignLeft,
|
||||
},
|
||||
|
||||
GuildsTree: GuildsTreeTheme{
|
||||
AutoExpandFolders: true,
|
||||
ChannelColor: tview.Styles.PrimaryTextColor.String(),
|
||||
Graphics: true,
|
||||
GuildColor: tview.Styles.PrimaryTextColor.String(),
|
||||
PrivateChannelColor: tview.Styles.PrimaryTextColor.String(),
|
||||
},
|
||||
MessagesText: MessagesTextTheme{
|
||||
ShowNicknames: true,
|
||||
ShowUsernameColors: true,
|
||||
|
||||
ReplyIndicator: ">",
|
||||
ForwardedIndicator: "<",
|
||||
|
||||
AuthorColor: "aqua",
|
||||
ContentColor: tview.Styles.PrimaryTextColor.String(),
|
||||
EmojiColor: "green",
|
||||
LinkColor: "blue",
|
||||
AttachmentColor: "yellow",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue