package config import ( "github.com/BurntSushi/toml" "github.com/ayn2op/tview/keybind" ) type Keybind struct { keybind.Keybind } var _ toml.Unmarshaler = (*Keybind)(nil) func (k *Keybind) UnmarshalTOML(value any) error { var keys []string switch value := value.(type) { case string: keys = []string{value} case []any: for _, key := range value { if key, ok := key.(string); ok { keys = append(keys, key) } } default: return nil } kb := keybind.New(keys...) // Keep displayed help key aligned with configured key(s). help := k.Help() if keys := kb.Keys(); len(keys) > 0 { help.Key = keys[0] } k.Keybind = kb.WithHelp(help.Key, help.Desc) return nil } // desc builds a Keybind with only a help description; keys come from config.toml. func desc(s string) Keybind { return Keybind{ Keybind: keybind.New().WithHelp("", s), } } type ScrollKeybinds struct { ScrollUp Keybind `toml:"scroll_up"` ScrollDown Keybind `toml:"scroll_down"` ScrollTop Keybind `toml:"scroll_top"` ScrollBottom Keybind `toml:"scroll_bottom"` } type SelectionKeybinds struct { SelectUp Keybind `toml:"select_up"` SelectDown Keybind `toml:"select_down"` SelectTop Keybind `toml:"select_top"` SelectBottom Keybind `toml:"select_bottom"` } type PickerKeybinds struct { SelectionKeybinds Select Keybind `toml:"select"` Cancel Keybind `toml:"cancel"` } type TreeKeybinds struct { SelectionKeybinds SelectCurrent Keybind `toml:"select_current"` YankID Keybind `toml:"yank_id"` CollapseAll Keybind `toml:"collapse_all"` CollapseParentNode Keybind `toml:"collapse_parent_node"` MoveToParentNode Keybind `toml:"move_to_parent_node"` } type MessagesListKeybinds struct { SelectionKeybinds ScrollKeybinds SelectReply Keybind `toml:"select_reply"` Reply Keybind `toml:"reply"` ReplyMention Keybind `toml:"reply_mention"` Cancel Keybind `toml:"cancel"` Edit Keybind `toml:"edit"` Delete Keybind `toml:"delete"` DeleteConfirm Keybind `toml:"delete_confirm"` Open Keybind `toml:"open"` OpenInBrowser Keybind `toml:"open_in_browser"` Download Keybind `toml:"download"` YankContent Keybind `toml:"yank_content"` YankURL Keybind `toml:"yank_url"` YankID Keybind `toml:"yank_id"` } type ComposerKeybinds struct { EditLast Keybind `toml:"edit_last"` Paste Keybind `toml:"paste"` Send Keybind `toml:"send"` Newline Keybind `toml:"newline"` Cancel Keybind `toml:"cancel"` TabComplete Keybind `toml:"tab_complete"` ToggleReplyMention Keybind `toml:"toggle_reply_mention"` Undo Keybind `toml:"undo"` OpenEditor Keybind `toml:"open_editor"` OpenFilePicker Keybind `toml:"open_file_picker"` } type MentionsListKeybinds struct { SelectionKeybinds } type Keybinds struct { ToggleGuildsTree Keybind `toml:"toggle_guilds_tree"` ToggleMembersTree Keybind `toml:"toggle_members_tree"` ToggleChannelsPicker Keybind `toml:"toggle_channels_picker"` ToggleHelp Keybind `toml:"toggle_help"` ToggleFullHelp Keybind `toml:"toggle_full_help"` Suspend Keybind `toml:"suspend"` FocusGuildsTree Keybind `toml:"focus_guilds_tree"` FocusMembersTree Keybind `toml:"focus_members_tree"` FocusMessagesList Keybind `toml:"focus_messages_list"` FocusComposer Keybind `toml:"focus_composer"` FocusPrevious Keybind `toml:"focus_previous"` FocusNext Keybind `toml:"focus_next"` Picker PickerKeybinds `toml:"picker"` GuildsTree TreeKeybinds `toml:"guilds_tree"` MembersTree TreeKeybinds `toml:"members_tree"` MessagesList MessagesListKeybinds `toml:"messages_list"` Composer ComposerKeybinds `toml:"composer"` MentionsList MentionsListKeybinds `toml:"mentions_list"` Logout Keybind `toml:"logout"` Quit Keybind `toml:"quit"` } func defaultSelectionKeybinds() SelectionKeybinds { return SelectionKeybinds{ SelectUp: desc("up"), SelectDown: desc("down"), SelectTop: desc("top"), SelectBottom: desc("btm"), } } func defaultPickerKeybinds() PickerKeybinds { return PickerKeybinds{ SelectionKeybinds: defaultSelectionKeybinds(), Cancel: desc("cancel"), Select: desc("sel"), } } func defaultTreeKeybinds() TreeKeybinds { return TreeKeybinds{ SelectionKeybinds: defaultSelectionKeybinds(), SelectCurrent: desc("select"), YankID: desc("copy id"), CollapseAll: desc("collapse all"), CollapseParentNode: desc("collapse parent"), MoveToParentNode: desc("parent"), } } func defaultMessagesListKeybinds() MessagesListKeybinds { return MessagesListKeybinds{ SelectionKeybinds: defaultSelectionKeybinds(), ScrollUp: desc("scr up"), ScrollDown: desc("scr down"), ScrollTop: desc("scr top"), ScrollBottom: desc("scr btm"), SelectReply: desc("sel reply"), Reply: desc("reply"), ReplyMention: desc("@reply"), Cancel: desc("cancel"), Edit: desc("edit"), Delete: desc("force delete"), DeleteConfirm: desc("delete"), Open: desc("open"), OpenInBrowser: desc("open browser"), Download: desc("download"), YankContent: desc("copy text"), YankURL: desc("copy url"), YankID: desc("copy id"), } } func defaultComposerKeybinds() ComposerKeybinds { return ComposerKeybinds{ EditLast: desc("edit last"), Paste: desc("paste"), Send: desc("send"), Newline: desc("nl"), Cancel: desc("cancel"), TabComplete: desc("complete"), ToggleReplyMention: desc("toggle @reply"), Undo: desc("undo"), OpenEditor: desc("editor"), OpenFilePicker: desc("attach"), } } func defaultMentionsListKeybinds() MentionsListKeybinds { return MentionsListKeybinds{ SelectionKeybinds: defaultSelectionKeybinds(), } } func defaultKeybinds() Keybinds { return Keybinds{ ToggleGuildsTree: desc("toggle guilds"), ToggleMembersTree: desc("toggle members"), ToggleChannelsPicker: desc("channels picker"), ToggleHelp: desc("toggle help"), ToggleFullHelp: desc("full help"), Suspend: desc("suspend"), FocusGuildsTree: desc("guilds"), FocusMembersTree: desc("members"), FocusMessagesList: desc("messages"), FocusComposer: desc("composer"), FocusPrevious: desc("focus prev"), FocusNext: desc("focus next"), Logout: desc("logout"), Quit: desc("quit"), Picker: defaultPickerKeybinds(), GuildsTree: defaultTreeKeybinds(), MembersTree: defaultTreeKeybinds(), MessagesList: defaultMessagesListKeybinds(), Composer: defaultComposerKeybinds(), MentionsList: defaultMentionsListKeybinds(), } }