feat: add toast notifications (#527)
This commit is contained in:
parent
c21ba4ed8d
commit
7bc948b0d0
9 changed files with 299 additions and 8 deletions
|
|
@ -5,6 +5,7 @@ import (
|
|||
"log/slog"
|
||||
"runtime"
|
||||
|
||||
"github.com/ayn2op/discordo/internal/notifications"
|
||||
"github.com/diamondburned/arikawa/v3/api"
|
||||
"github.com/diamondburned/arikawa/v3/gateway"
|
||||
"github.com/diamondburned/arikawa/v3/utils/httputil/httpdriver"
|
||||
|
|
@ -84,6 +85,10 @@ func (s *State) onMessageCreate(m *gateway.MessageCreateEvent) {
|
|||
if app.guildsTree.selectedChannelID.IsValid() && app.guildsTree.selectedChannelID == m.ChannelID {
|
||||
app.messagesText.createMessage(m.Message)
|
||||
}
|
||||
|
||||
if err := notifications.HandleIncomingMessage(*s.State, m, app.cfg); err != nil {
|
||||
slog.Error("Notification failed", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *State) onMessageDelete(m *gateway.MessageDeleteEvent) {
|
||||
|
|
|
|||
6
go.mod
6
go.mod
|
|
@ -5,9 +5,11 @@ go 1.24.0
|
|||
require (
|
||||
github.com/BurntSushi/toml v1.5.0
|
||||
github.com/atotto/clipboard v0.1.4
|
||||
github.com/deckarep/gosx-notifier v0.0.0-20180201035817-e127226297fb
|
||||
github.com/diamondburned/arikawa/v3 v3.4.0
|
||||
github.com/diamondburned/ningen/v3 v3.0.1-0.20240808103805-f1a24c0da3d8
|
||||
github.com/gdamore/tcell/v2 v2.8.1
|
||||
github.com/gen2brain/beeep v0.0.0-20240516210008-9c006672e7f4
|
||||
github.com/rivo/tview v0.0.0-20250325173046-7b72abf45814
|
||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
|
||||
github.com/spf13/cobra v1.9.1
|
||||
|
|
@ -19,16 +21,18 @@ require (
|
|||
al.essio.dev/pkg/shellescape v1.6.0 // indirect
|
||||
github.com/danieljoos/wincred v1.2.2 // indirect
|
||||
github.com/gdamore/encoding v1.0.1 // indirect
|
||||
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4 // indirect
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
github.com/gorilla/schema v1.4.1 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/sahilm/fuzzy v0.1.1
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
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/sys v0.31.0 // indirect
|
||||
|
|
|
|||
13
go.sum
13
go.sum
|
|
@ -34,6 +34,8 @@ 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/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.4.0 h1:wI3Qv8h2E2dkeddF1I35nv4T6OQ3RtA21rbghW/fnd0=
|
||||
github.com/diamondburned/arikawa/v3 v3.4.0/go.mod h1:WVkbdenUfsCCkptIlqSglF4eo2/HSXv74eCqGnOZaYY=
|
||||
github.com/diamondburned/ningen/v3 v3.0.1-0.20240808103805-f1a24c0da3d8 h1:wgvgSzI4N+BHhCWhGhHKfW4gm0UtBVptiDaBGPdHmcs=
|
||||
|
|
@ -44,8 +46,12 @@ github.com/gdamore/encoding v1.0.1 h1:YzKZckdBL6jVt2Gc+5p82qhrGiqMdG/eNs6Wy0u3Uh
|
|||
github.com/gdamore/encoding v1.0.1/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo=
|
||||
github.com/gdamore/tcell/v2 v2.8.1 h1:KPNxyqclpWpWQlPLx6Xui1pMk8S+7+R37h3g07997NU=
|
||||
github.com/gdamore/tcell/v2 v2.8.1/go.mod h1:bj8ori1BG3OYMjmb3IklZVWfZUJ1UBQt9JXrOCOhGWw=
|
||||
github.com/gen2brain/beeep v0.0.0-20240516210008-9c006672e7f4 h1:ygs9POGDQpQGLJPlq4+0LBUmMBNox1N4JSpw+OETcvI=
|
||||
github.com/gen2brain/beeep v0.0.0-20240516210008-9c006672e7f4/go.mod h1:0W7dI87PvXJ1Sjs0QPvWXKcQmNERY77e8l7GFhZB/s4=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4 h1:qZNfIGkIANxGv/OqtnntR4DfOY2+BgwR60cAcu/i3SE=
|
||||
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4/go.mod h1:kW3HQ4UdaAyrUCSSDR4xUzBKW6O2iA4uHhk7AtyYp10=
|
||||
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
|
|
@ -97,6 +103,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/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ=
|
||||
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
|
|
@ -111,8 +119,6 @@ github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUc
|
|||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
|
||||
github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA=
|
||||
github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
|
||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=
|
||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
|
||||
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
||||
|
|
@ -125,6 +131,8 @@ github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/
|
|||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af h1:6yITBqGTE2lEeTPG04SN9W+iWHCRyHqlVYILiSXziwk=
|
||||
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af/go.mod h1:4F09kP5F+am0jAwlQLddpoMDM+iewkxxt6nxUQ5nq5o=
|
||||
github.com/twmb/murmur3 v1.1.8 h1:8Yt9taO/WN3l08xErzjeschgZU2QSrwm1kclYq+0aRg=
|
||||
github.com/twmb/murmur3 v1.1.8/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
|
|
@ -231,6 +239,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
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=
|
||||
|
|
|
|||
|
|
@ -32,9 +32,10 @@ type (
|
|||
Timestamps bool `toml:"timestamps"`
|
||||
TimestampsFormat string `toml:"timestamps_format"`
|
||||
|
||||
Identify Identify `toml:"identify"`
|
||||
Keys Keys `toml:"keys"`
|
||||
Theme Theme `toml:"theme"`
|
||||
Identify Identify `toml:"identify"`
|
||||
Keys Keys `toml:"keys"`
|
||||
Theme Theme `toml:"theme"`
|
||||
Notifications Notifications `toml:"notifications"`
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -57,8 +58,9 @@ func defaultConfig() *Config {
|
|||
UserAgent: consts.UserAgent,
|
||||
},
|
||||
|
||||
Keys: defaultKeys(),
|
||||
Theme: defaultTheme(),
|
||||
Keys: defaultKeys(),
|
||||
Theme: defaultTheme(),
|
||||
Notifications: defaultNotifications(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
25
internal/config/notifications.go
Normal file
25
internal/config/notifications.go
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
package config
|
||||
|
||||
type (
|
||||
Notifications struct {
|
||||
Enabled bool `toml:"enabled"`
|
||||
Duration int `toml:"duration"`
|
||||
Sound Sound `toml:"sound"`
|
||||
}
|
||||
|
||||
Sound struct {
|
||||
Enabled bool `toml:"enabled"`
|
||||
OnlyOnPing bool `toml:"only_on_ping"`
|
||||
}
|
||||
)
|
||||
|
||||
func defaultNotifications() Notifications {
|
||||
return Notifications{
|
||||
Enabled: true,
|
||||
Duration: 500,
|
||||
Sound: Sound{
|
||||
Enabled: true,
|
||||
OnlyOnPing: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
18
internal/notifications/desktop_toast.go
Normal file
18
internal/notifications/desktop_toast.go
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
//go:build !darwin
|
||||
|
||||
package notifications
|
||||
|
||||
import "github.com/gen2brain/beeep"
|
||||
|
||||
func sendDesktopNotification(title string, body string, image string, playSound bool, duration int) error {
|
||||
beeep.DefaultDuration = duration
|
||||
|
||||
if err := beeep.Notify(title, body, image); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if playSound {
|
||||
return beeep.Beep(beeep.DefaultFreq, beeep.DefaultDuration)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
19
internal/notifications/desktop_toast_darwin.go
Normal file
19
internal/notifications/desktop_toast_darwin.go
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
//go:build darwin
|
||||
|
||||
package notifications
|
||||
|
||||
import (
|
||||
gosxnotifier "github.com/deckarep/gosx-notifier"
|
||||
)
|
||||
|
||||
func sendDesktopNotification(title string, body string, image string, playSound bool, _ int) error {
|
||||
notify := gosxnotifier.NewNotification(body)
|
||||
notify.Title = title
|
||||
notify.ContentImage = image
|
||||
|
||||
if playSound {
|
||||
notify.Sound = gosxnotifier.Default
|
||||
}
|
||||
|
||||
return notify.Push()
|
||||
}
|
||||
117
internal/notifications/notifications.go
Normal file
117
internal/notifications/notifications.go
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
package notifications
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/ayn2op/discordo/internal/config"
|
||||
"github.com/ayn2op/discordo/internal/consts"
|
||||
"github.com/diamondburned/arikawa/v3/discord"
|
||||
"github.com/diamondburned/arikawa/v3/gateway"
|
||||
"github.com/diamondburned/ningen/v3"
|
||||
"github.com/diamondburned/ningen/v3/discordmd"
|
||||
)
|
||||
|
||||
func HandleIncomingMessage(s ningen.State, m *gateway.MessageCreateEvent, cfg *config.Config) error {
|
||||
// Only display notification if enabled and unmuted
|
||||
if !cfg.Notifications.Enabled || s.MessageMentions(&m.Message) == 0 || cfg.Identify.Status == discord.DoNotDisturbStatus {
|
||||
return nil
|
||||
}
|
||||
|
||||
ch, err := s.Cabinet.Channel(m.ChannelID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
isChannelDM := ch.Type == discord.DirectMessage || ch.Type == discord.GroupDM
|
||||
guild := (*discord.Guild)(nil)
|
||||
if !isChannelDM {
|
||||
guild, err = s.Cabinet.Guild(ch.GuildID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Render message
|
||||
src := []byte(m.Content)
|
||||
ast := discordmd.ParseWithMessage(src, *s.Cabinet, &m.Message, false)
|
||||
buff := strings.Builder{}
|
||||
if err := PlainTextRenderer.Render(&buff, src, ast); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Handle sent files
|
||||
notifContent := buff.String()
|
||||
if m.Message.Content == "" && len(m.Message.Attachments) > 0 {
|
||||
notifContent = "Uploaded " + m.Message.Attachments[0].Filename
|
||||
}
|
||||
|
||||
if m.Author.DisplayOrTag() == "" || notifContent == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
notifTitle := m.Author.DisplayOrTag()
|
||||
if guild != nil {
|
||||
member, _ := s.Member(ch.GuildID, m.Author.ID)
|
||||
if member.Nick != "" {
|
||||
notifTitle = member.Nick
|
||||
}
|
||||
|
||||
notifTitle = notifTitle + " (#" + ch.Name + ", " + guild.Name + ")"
|
||||
}
|
||||
|
||||
hash := m.Author.Avatar
|
||||
if hash == "" {
|
||||
hash = "default"
|
||||
}
|
||||
imagePath, err := getCachedProfileImage(hash, m.Author.AvatarURLWithType(discord.PNGImage))
|
||||
if err != nil {
|
||||
slog.Error("Failed to retrieve avatar image for notification", "err", err)
|
||||
}
|
||||
|
||||
shouldChime := cfg.Notifications.Sound.Enabled && (!cfg.Notifications.Sound.OnlyOnPing || (isChannelDM || s.MessageMentions(&m.Message) == 3))
|
||||
if err := sendDesktopNotification(notifTitle, notifContent, imagePath, shouldChime, cfg.Notifications.Duration); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getCachedProfileImage(avatarHash discord.Hash, url string) (string, error) {
|
||||
path, err := os.UserCacheDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
path = filepath.Join(path, consts.Name)
|
||||
if err := os.MkdirAll(path, os.ModePerm); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
path = filepath.Join(path, avatarHash+".png")
|
||||
if _, err := os.Stat(path); err == nil {
|
||||
return path, nil
|
||||
}
|
||||
|
||||
image, err := os.Create(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer image.Close()
|
||||
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if _, err := io.Copy(image, resp.Body); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return path, nil
|
||||
}
|
||||
92
internal/notifications/renderer.go
Normal file
92
internal/notifications/renderer.go
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
package notifications
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/diamondburned/ningen/v3/discordmd"
|
||||
"github.com/yuin/goldmark/ast"
|
||||
gmr "github.com/yuin/goldmark/renderer"
|
||||
)
|
||||
|
||||
// Using a modified version of the discordmd BasicRenderer
|
||||
var PlainTextRenderer = newRenderer()
|
||||
|
||||
type renderer struct {
|
||||
config *gmr.Config
|
||||
}
|
||||
|
||||
func newRenderer() *renderer {
|
||||
config := gmr.NewConfig()
|
||||
return &renderer{config}
|
||||
}
|
||||
|
||||
func (r *renderer) AddOptions(opts ...gmr.Option) {
|
||||
for _, opt := range opts {
|
||||
opt.SetConfig(r.config)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *renderer) Render(w io.Writer, source []byte, n ast.Node) error {
|
||||
return ast.Walk(n, func(n ast.Node, entering bool) (ast.WalkStatus, error) {
|
||||
switch n := n.(type) {
|
||||
case *ast.Document:
|
||||
// noop
|
||||
case *ast.Blockquote:
|
||||
io.WriteString(w, "\"")
|
||||
case *ast.Heading:
|
||||
io.WriteString(w, "\n")
|
||||
case *ast.FencedCodeBlock:
|
||||
io.WriteString(w, "\n")
|
||||
|
||||
if entering {
|
||||
for i := range n.Lines().Len() {
|
||||
line := n.Lines().At(i)
|
||||
io.WriteString(w, "| ")
|
||||
w.Write(line.Value(source))
|
||||
}
|
||||
}
|
||||
case *ast.AutoLink:
|
||||
if entering {
|
||||
w.Write(n.URL(source))
|
||||
}
|
||||
case *ast.Link:
|
||||
if !entering {
|
||||
io.WriteString(w, " ("+string(n.Destination)+")")
|
||||
}
|
||||
case *discordmd.Inline:
|
||||
if n.Attr&discordmd.AttrSpoiler != 0 {
|
||||
if entering {
|
||||
io.WriteString(w, "*spoiler*")
|
||||
}
|
||||
return ast.WalkSkipChildren, nil
|
||||
}
|
||||
case *ast.Text:
|
||||
if entering {
|
||||
w.Write(n.Segment.Value(source))
|
||||
switch {
|
||||
case n.HardLineBreak():
|
||||
io.WriteString(w, "\n\n")
|
||||
case n.SoftLineBreak():
|
||||
io.WriteString(w, "\n")
|
||||
}
|
||||
}
|
||||
case *discordmd.Mention:
|
||||
if entering {
|
||||
switch {
|
||||
case n.Channel != nil:
|
||||
io.WriteString(w, "#"+n.Channel.Name)
|
||||
case n.GuildUser != nil:
|
||||
io.WriteString(w, "@"+n.GuildUser.Username)
|
||||
case n.GuildRole != nil:
|
||||
io.WriteString(w, "@"+n.GuildRole.Name)
|
||||
}
|
||||
}
|
||||
case *discordmd.Emoji:
|
||||
if entering {
|
||||
io.WriteString(w, ":"+string(n.Name)+":")
|
||||
}
|
||||
}
|
||||
|
||||
return ast.WalkContinue, nil
|
||||
})
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue