feat: support for attachments (#578)

This commit is contained in:
Ayyan 2025-07-10 18:09:15 -04:00 • committed by GitHub
parent be410c5e62
commit 3b91275596
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 112 additions and 56 deletions

View file

@ -9,6 +9,7 @@ Discordo is a lightweight, secure, and feature-rich Discord terminal client. Hea
- Lightweight
- Configurable
- Mouse & clipboard support
- Attachments
- Notifications
- 2-Factor authentication
- Discord-flavored markdown

View file

@ -1,9 +1,12 @@
package cmd
import (
"fmt"
"io"
"log/slog"
"os"
"os/exec"
"path/filepath"
"regexp"
"slices"
"strings"
@ -18,9 +21,10 @@ import (
"github.com/diamondburned/arikawa/v3/api"
"github.com/diamondburned/arikawa/v3/discord"
"github.com/diamondburned/arikawa/v3/state"
"github.com/diamondburned/arikawa/v3/utils/json/option"
"github.com/diamondburned/arikawa/v3/utils/sendpart"
"github.com/diamondburned/ningen/v3/discordmd"
"github.com/gdamore/tcell/v2"
"github.com/ncruces/zenity"
"github.com/sahilm/fuzzy"
"github.com/yuin/goldmark/ast"
)
@ -33,20 +37,22 @@ type messageInput struct {
*tview.TextArea
cfg *config.Config
cache *cache.Cache
mentionsList *tview.List
replyMessageID discord.MessageID
lastSearch time.Time
sendMessageData *api.SendMessageData
cache *cache.Cache
mentionsList *tview.List
lastSearch time.Time
}
type memberList []discord.Member
func newMessageInput(cfg *config.Config) *messageInput {
mi := &messageInput{
TextArea: tview.NewTextArea(),
cfg: cfg,
cache: cache.NewCache(),
mentionsList: tview.NewList(),
TextArea: tview.NewTextArea(),
cfg: cfg,
sendMessageData: &api.SendMessageData{},
cache: cache.NewCache(),
mentionsList: tview.NewList(),
}
mi.Box = ui.ConfigureBox(mi.Box, &cfg.Theme)
@ -75,7 +81,7 @@ func newMessageInput(cfg *config.Config) *messageInput {
}
func (mi *messageInput) reset() {
mi.replyMessageID = 0
mi.sendMessageData = &api.SendMessageData{}
mi.SetTitle("")
mi.SetText("", true)
}
@ -90,10 +96,14 @@ func (mi *messageInput) onInputCapture(event *tcell.EventKey) *tcell.EventKey {
mi.send()
return nil
case mi.cfg.Keys.MessageInput.Editor:
case mi.cfg.Keys.MessageInput.OpenEditor:
mi.stopTabCompletion()
mi.editor()
return nil
case mi.cfg.Keys.MessageInput.OpenFilePicker:
mi.stopTabCompletion()
mi.openFilePicker()
return nil
case mi.cfg.Keys.MessageInput.Cancel:
if app.pages.GetVisibile(mentionsListPageName) {
mi.stopTabCompletion()
@ -135,31 +145,22 @@ func (mi *messageInput) send() {
return
}
text := strings.TrimSpace(mi.GetText())
if text == "" {
return
data := mi.sendMessageData
if text := strings.TrimSpace(mi.GetText()); text != "" {
data.Content = processText(app.guildsTree.selectedChannelID, []byte(text))
}
// Process mentions (there's no shortcut, just parse the entire message
// as markdown and then expand non-code mentions)
data := api.SendMessageData{
Content: processText(app.guildsTree.selectedChannelID, []byte(text)),
if _, err := discordState.SendMessageComplex(app.guildsTree.selectedChannelID, *data); err != nil {
slog.Error("failed to send message in channel", "channel_id", app.guildsTree.selectedChannelID, "err", err)
}
if mi.replyMessageID != 0 {
data.Reference = &discord.MessageReference{MessageID: mi.replyMessageID}
data.AllowedMentions = &api.AllowedMentions{RepliedUser: option.False}
if strings.HasPrefix(mi.GetTitle(), "[@]") {
data.AllowedMentions.RepliedUser = option.True
// Close the attached files after sending the message.
for _, file := range mi.sendMessageData.Files {
if closer, ok := file.Reader.(io.Closer); ok {
_ = closer.Close()
}
}
go func() {
if _, err := discordState.SendMessageComplex(app.guildsTree.selectedChannelID, data); err != nil {
slog.Error("failed to send message in channel", "channel_id", app.guildsTree.selectedChannelID, "err", err)
}
}()
mi.reset()
app.messagesList.Highlight()
app.messagesList.ScrollToEnd()
@ -470,3 +471,38 @@ func (mi *messageInput) editor() {
mi.SetText(strings.TrimSpace(string(msg)), true)
}
func (mi *messageInput) addTitle(s string) {
title := mi.GetTitle()
if title != "" {
title += " | "
}
mi.SetTitle(title + s)
}
func (mi *messageInput) openFilePicker() {
if !app.guildsTree.selectedChannelID.IsValid() {
return
}
paths, err := zenity.SelectFileMultiple()
if err != nil {
slog.Error("failed to open file dialog", "err", err)
return
}
for _, path := range paths {
file, err := os.Open(path)
if err != nil {
slog.Error("failed to open file", "path", path, "err", err)
continue
}
name := filepath.Base(path)
mi.sendMessageData.Files = append(mi.sendMessageData.Files, sendpart.File{Name: name, Reader: file})
title := fmt.Sprintf("Attached %s", name)
mi.addTitle(title)
}
}

View file

@ -15,9 +15,11 @@ import (
"github.com/ayn2op/discordo/internal/markdown"
"github.com/ayn2op/discordo/internal/ui"
"github.com/ayn2op/tview"
"github.com/diamondburned/arikawa/v3/api"
"github.com/diamondburned/arikawa/v3/discord"
"github.com/diamondburned/arikawa/v3/gateway"
"github.com/diamondburned/arikawa/v3/state"
"github.com/diamondburned/arikawa/v3/utils/json/option"
"github.com/diamondburned/ningen/v3/discordmd"
"github.com/gdamore/tcell/v2"
"github.com/skratchdot/open-golang/open"
@ -81,8 +83,6 @@ func (ml *messagesList) drawMsgs(cID discord.ChannelID) {
func (ml *messagesList) reset() {
ml.selectedMessageID = 0
app.messageInput.replyMessageID = 0
ml.
Clear().
Highlight().
@ -267,7 +267,6 @@ func (ml *messagesList) onInputCapture(event *tcell.EventKey) *tcell.EventKey {
switch event.Name() {
case ml.cfg.Keys.MessagesList.Cancel:
ml.selectedMessageID = 0
app.messageInput.replyMessageID = 0
ml.Highlight()
case ml.cfg.Keys.MessagesList.SelectPrevious, ml.cfg.Keys.MessagesList.SelectNext, ml.cfg.Keys.MessagesList.SelectFirst, ml.cfg.Keys.MessagesList.SelectLast, ml.cfg.Keys.MessagesList.SelectReply:
@ -493,13 +492,6 @@ func openURL(url string) {
}
func (ml *messagesList) reply(mention bool) {
var title string
if mention {
title += "[@] Replying to "
} else {
title += "Replying to "
}
msg, err := ml.selectedMsg()
if err != nil {
slog.Error("failed to get selected message", "err", err)
@ -518,9 +510,18 @@ func (ml *messagesList) reply(mention bool) {
name = ui.PreferredName(msg.Author, ml.cfg.Theme)
}
title += name
app.messageInput.SetTitle(title)
app.messageInput.replyMessageID = ml.selectedMessageID
data := app.messageInput.sendMessageData
data.Reference = &discord.MessageReference{MessageID: ml.selectedMessageID}
data.AllowedMentions = &api.AllowedMentions{RepliedUser: option.False}
title := "Replying to "
if mention {
data.AllowedMentions.RepliedUser = option.True
title = "[@] " + title
}
app.messageInput.sendMessageData = data
app.messageInput.addTitle(title + name)
app.SetFocus(app.messageInput)
}
@ -549,7 +550,6 @@ func (ml *messagesList) delete() {
}
ml.selectedMessageID = 0
app.messageInput.replyMessageID = 0
ml.Highlight()
if err := discordState.MessageRemove(app.guildsTree.selectedChannelID, msg.ID); err != nil {

6
go.mod
View file

@ -11,6 +11,7 @@ require (
github.com/diamondburned/ningen/v3 v3.0.1-0.20250703054403-e5dc4cf15e84
github.com/gdamore/tcell/v2 v2.8.1
github.com/gen2brain/beeep v0.11.1
github.com/ncruces/zenity v0.10.14
github.com/sahilm/fuzzy v0.1.1
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
github.com/spf13/cobra v1.9.1
@ -21,7 +22,9 @@ require (
require (
al.essio.dev/pkg/shellescape v1.6.0 // indirect
git.sr.ht/~jackmordaunt/go-toast v1.1.2 // indirect
github.com/akavel/rsrc v0.10.2 // indirect
github.com/danieljoos/wincred v1.2.2 // indirect
github.com/dchest/jsmin v1.0.0 // indirect
github.com/esiqveland/notify v0.13.3 // indirect
github.com/gdamore/encoding v1.0.1 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
@ -30,10 +33,12 @@ require (
github.com/gorilla/websocket v1.5.3 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackmordaunt/icns/v3 v3.0.1 // indirect
github.com/josephspurrier/goversioninfo v1.5.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/randall77/makefat v0.0.0-20210315173500-7ddd0e42c844 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/sergeymakinen/go-bmp v1.0.0 // indirect
github.com/sergeymakinen/go-ico v1.0.0-beta.0 // indirect
@ -41,6 +46,7 @@ require (
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af // indirect
github.com/twmb/murmur3 v1.1.8 // indirect
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
golang.org/x/image v0.29.0 // indirect
golang.org/x/sys v0.34.0 // indirect
golang.org/x/term v0.33.0 // indirect
golang.org/x/text v0.27.0 // indirect

31
go.sum
View file

@ -23,6 +23,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/akavel/rsrc v0.10.2 h1:Zxm8V5eI1hW4gGaYsJQUhxpjkENuG91ki8B4zCrvEsw=
github.com/akavel/rsrc v0.10.2/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
github.com/ayn2op/tview v0.0.0-20250618224732-91a1a2f06994 h1:heK43Ba0uvQPH2BgJVFiB2G8vIJk1XocvFYCPfOSNhU=
@ -38,14 +40,14 @@ github.com/danieljoos/wincred v1.2.2/go.mod h1:w7w4Utbrz8lqeMbDAK0lkNJUv5sAOkFi7
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dchest/jsmin v0.0.0-20220218165748-59f39799265f h1:OGqDDftRTwrvUoL6pOG7rYTmWsTCvyEWFsMjg+HcOaA=
github.com/dchest/jsmin v0.0.0-20220218165748-59f39799265f/go.mod h1:Dv9D0NUlAsaQcGQZa5kc5mqR9ua72SmA8VXi4cd+cBw=
github.com/dchest/jsmin v1.0.0 h1:Y2hWXmGZiRxtl+VcTksyucgTlYxnhPzTozCwx9gy9zI=
github.com/dchest/jsmin v1.0.0/go.mod h1:AVBIund7Mr7lKXT70hKT2YgL3XEXUaUk5iw9DZ8b0Uc=
github.com/deckarep/gosx-notifier v0.0.0-20180201035817-e127226297fb h1:6S+TKObz6+Io2c8IOkcbK4Sz7nj6RpEVU7TkvmsZZcw=
github.com/deckarep/gosx-notifier v0.0.0-20180201035817-e127226297fb/go.mod h1:wf3nKtOnQqCp7kp9xB7hHnNlZ6m3NoiOxjrB9hFRq4Y=
github.com/diamondburned/arikawa/v3 v3.5.1-0.20250702014048-91c175a8e0e4 h1:24TheqHAPtaJG0RFkGq9XugUYKwg5xkmuEUCCrUeQgs=
github.com/diamondburned/arikawa/v3 v3.5.1-0.20250702014048-91c175a8e0e4/go.mod h1:thocAM2X8lRDHuEZR5vWYaT4w+tb/vOKa1qm+r0gs5A=
github.com/diamondburned/arikawa/v3 v3.5.1-0.20250703053218-19d9c3f2e011 h1:N8ylXHkkDXsbtsA/by/yZUDKmfWZJ1JjTXGpHmIiR9M=
github.com/diamondburned/arikawa/v3 v3.5.1-0.20250703053218-19d9c3f2e011/go.mod h1:thocAM2X8lRDHuEZR5vWYaT4w+tb/vOKa1qm+r0gs5A=
github.com/diamondburned/ningen/v3 v3.0.1-0.20250607192146-d6b46a4689a5 h1:JSR20qwKLYVl3KKy6mUY7f8ziD2GtGAa3P9G2CyFgwk=
github.com/diamondburned/ningen/v3 v3.0.1-0.20250607192146-d6b46a4689a5/go.mod h1:UU1lud9g/GBl2+CZ8nPCe3Qk1U6fABEP1fk1sUzo7w0=
github.com/diamondburned/ningen/v3 v3.0.1-0.20250703054403-e5dc4cf15e84 h1:O/6NA4fQimjVNuT5F02kodPT2cz9Ltq2U96vxKYL0oA=
github.com/diamondburned/ningen/v3 v3.0.1-0.20250703054403-e5dc4cf15e84/go.mod h1:UU1lud9g/GBl2+CZ8nPCe3Qk1U6fABEP1fk1sUzo7w0=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@ -103,6 +105,10 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jackmordaunt/icns/v3 v3.0.1 h1:xxot6aNuGrU+lNgxz5I5H0qSeCjNKp8uTXB1j8D4S3o=
github.com/jackmordaunt/icns/v3 v3.0.1/go.mod h1:5sHL59nqTd2ynTnowxB/MDQFhKNqkK8X687uKNygaSQ=
github.com/josephspurrier/goversioninfo v1.4.1 h1:5LvrkP+n0tg91J9yTkoVnt/QgNnrI1t4uSsWjIonrqY=
github.com/josephspurrier/goversioninfo v1.4.1/go.mod h1:JWzv5rKQr+MmW+LvM412ToT/IkYDZjaclF2pKDss8IY=
github.com/josephspurrier/goversioninfo v1.5.0 h1:9TJtORoyf4YMoWSOo/cXFN9A/lB3PniJ91OxIH6e7Zg=
github.com/josephspurrier/goversioninfo v1.5.0/go.mod h1:6MoTvFZ6GKJkzcdLnU5T/RGYUbHQbKpYeNP0AgQLd2o=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
@ -115,6 +121,8 @@ github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/ncruces/zenity v0.10.14 h1:OBFl7qfXcvsdo1NUEGxTlZvAakgWMqz9nG38TuiaGLI=
github.com/ncruces/zenity v0.10.14/go.mod h1:ZBW7uVe/Di3IcRYH0Br8X59pi+O6EPnNIOU66YHpOO4=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@ -122,6 +130,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
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/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/randall77/makefat v0.0.0-20210315173500-7ddd0e42c844 h1:GranzK4hv1/pqTIhMTXt2X8MmMOuH3hMeUR0o9SP5yc=
github.com/randall77/makefat v0.0.0-20210315173500-7ddd0e42c844/go.mod h1:T1TLSfyWVBRXVGzWd0o9BI4kfoO9InEgfQe4NV3mLz8=
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.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
@ -147,6 +157,7 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
@ -165,6 +176,8 @@ go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go4.org v0.0.0-20230225012048-214862532bf5 h1:nifaUDeh+rPaBCMPMQHZmvJf+QdpLFnuQPwx+LxVmtc=
go4.org v0.0.0-20230225012048-214862532bf5/go.mod h1:F57wTi5Lrj6WLyswp5EYV1ncrEbFGHD4hhz6S1ZYeaU=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@ -185,6 +198,10 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.20.0 h1:7cVCUjQwfL18gyBJOmYvptfSHS8Fb3YUDtfLIZ7Nbpw=
golang.org/x/image v0.20.0/go.mod h1:0a88To4CYVBAHp5FXJm8o7QbUl37Vd85ply1vyD8auM=
golang.org/x/image v0.29.0 h1:HcdsyR4Gsuys/Axh0rDEmlBmB68rW1U9BUdB3UVHsas=
golang.org/x/image v0.29.0/go.mod h1:RVJROnf3SLK8d26OW91j4FrIHGbsJ8QnbEocVTOWQDA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@ -266,8 +283,6 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
@ -279,8 +294,6 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg=
golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -295,8 +308,6 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=

View file

@ -88,12 +88,12 @@ yank_id = "Rune[i]"
# Alt+Enter: Insert a new line to the current text.
[keys.message_input]
send = "Enter"
# Open message input in your editor.
editor = "Ctrl+E"
# Remove existing text or cancel reply.
cancel = "Esc"
# Complete usernames when mentioning
tab_complete = "Tab"
open_editor = "Ctrl+E"
open_file_picker = "Ctrl+\\"
[keys.mentions_list]
up = "Up"

View file

@ -49,9 +49,11 @@ type (
MessageInputKeys struct {
Send string `toml:"send"`
Editor string `toml:"editor"`
Cancel string `toml:"cancel"`
TabComplete string `toml:"tab_complete"`
OpenEditor string `toml:"open_editor"`
OpenFilePicker string `toml:"open_file_picker"`
}
MentionsListKeys struct {