Skip to content

Commit

Permalink
message: don't require target to format
Browse files Browse the repository at this point in the history
  • Loading branch information
zephyrtronium committed Feb 22, 2025
1 parent db6b9b3 commit 1b60287
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 53 deletions.
24 changes: 12 additions & 12 deletions command/marriage.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,15 @@ func Affection(ctx context.Context, robo *Robot, call *Invocation) {
// Check for the broadcaster. They get special treatment.
if strings.EqualFold(call.Message.Sender.Name, strings.TrimPrefix(call.Channel.Name, "#")) {
if _, ok := call.Channel.Extra.LoadOrStore(broadcasterAffectionKey{}, struct{}{}); ok {
call.Channel.Message(ctx, message.Format("", "Don't make me repeat myself, it's embarrassing! %s", e).AsReply(call.Message.ID))
call.Channel.Message(ctx, message.Format("Don't make me repeat myself, it's embarrassing! %s", e).AsReply(call.Message.ID))
return
}
const funnyMessage = `It's a bit awkward to think of you like that, streamer... But, well, it's so fun to be here, and I have you to thank for that! So I'd say a whole bunch! %s`
call.Channel.Message(ctx, message.Format("", funnyMessage, e).AsReply(call.Message.ID))
call.Channel.Message(ctx, message.Format(funnyMessage, e).AsReply(call.Message.ID))
return
}
// possible!
call.Channel.Message(ctx, message.Format("", "literally zero %s", e).AsReply(call.Message.ID))
call.Channel.Message(ctx, message.Format("literally zero %s", e).AsReply(call.Message.ID))
return
}
s := affections.Pick(rand.Uint32())
Expand All @@ -123,15 +123,15 @@ func Marry(ctx context.Context, robo *Robot, call *Invocation) {
e := call.Channel.Emotes.Pick(rand.Uint32())
broadcaster := strings.EqualFold(call.Message.Sender.Name, strings.TrimPrefix(call.Channel.Name, "#")) && x == 0
if x < 10 && !broadcaster {
call.Channel.Message(ctx, message.Format("", "no %s", e).AsReply(call.Message.ID))
call.Channel.Message(ctx, message.Format("no %s", e).AsReply(call.Message.ID))
return
}
me := &partner{who: call.Message.Sender.ID, until: call.Message.Time().Add(time.Hour)}
for {
l, ok := call.Channel.Extra.LoadOrStore(partnerKey{}, me)
if !ok {
// No competition. We're a shoo-in.
call.Channel.Message(ctx, message.Format("", "sure why not %s", e).AsReply(call.Message.ID))
call.Channel.Message(ctx, message.Format("sure why not %s", e).AsReply(call.Message.ID))
return
}
cur := l.(*partner)
Expand All @@ -143,19 +143,19 @@ func Marry(ctx context.Context, robo *Robot, call *Invocation) {
// but start over anyway.
continue
}
call.Channel.Message(ctx, message.Format("", "How could you forget we're already together? I hate you! Unsubbed, unfollowed, unloved! %s", e).AsReply(call.Message.ID))
call.Channel.Message(ctx, message.Format("How could you forget we're already together? I hate you! Unsubbed, unfollowed, unloved! %s", e).AsReply(call.Message.ID))
return
}
call.Channel.Message(ctx, message.Format("", "We're already together, silly! You're so funny and cute haha. %s", e).AsReply(call.Message.ID))
call.Channel.Message(ctx, message.Format("We're already together, silly! You're so funny and cute haha. %s", e).AsReply(call.Message.ID))
return
}
if call.Message.Time().Before(cur.until) {
call.Channel.Message(ctx, message.Format("", "My heart yet belongs to another... %s", e).AsReply(call.Message.ID))
call.Channel.Message(ctx, message.Format("My heart yet belongs to another... %s", e).AsReply(call.Message.ID))
return
}
y, _, _, _, _ := score(robo.Log, &call.Channel.History, cur.who)
if x < y && !broadcaster {
call.Channel.Message(ctx, message.Format("", "I'm touched, but I must decline. I'm in love with someone else. %s", e).AsReply(call.Message.ID))
call.Channel.Message(ctx, message.Format("I'm touched, but I must decline. I'm in love with someone else. %s", e).AsReply(call.Message.ID))
return
}
if !call.Channel.Extra.CompareAndSwap(partnerKey{}, cur, me) {
Expand All @@ -165,9 +165,9 @@ func Marry(ctx context.Context, robo *Robot, call *Invocation) {
// We win. Now just decide which message to send.
// TODO(zeph): since pick.Dist exists now, we could randomize
if call.Args["partnership"] != "" {
call.Channel.Message(ctx, message.Format("", "Yes! I'll be your %s! %s", call.Args["partnership"], e).AsReply(call.Message.ID))
call.Channel.Message(ctx, message.Format("Yes! I'll be your %s! %s", call.Args["partnership"], e).AsReply(call.Message.ID))
} else {
call.Channel.Message(ctx, message.Format("", "Yes! I'll marry you! %s", e).AsReply(call.Message.ID))
call.Channel.Message(ctx, message.Format("Yes! I'll marry you! %s", e).AsReply(call.Message.ID))
}
return
}
Expand All @@ -177,7 +177,7 @@ func Marry(ctx context.Context, robo *Robot, call *Invocation) {
// No args.
func DescribeMarriage(ctx context.Context, robo *Robot, call *Invocation) {
if t := call.Channel.SilentTime(); call.Message.Time().Before(t) {
call.Channel.Message(ctx, message.Format("", "I'm being quiet for the next %v, so the marriage system is disabled until then.", t.Sub(call.Message.Time())).AsReply(call.Message.ID))
call.Channel.Message(ctx, message.Format("I'm being quiet for the next %v, so the marriage system is disabled until then.", t.Sub(call.Message.Time())).AsReply(call.Message.ID))
return
}
const s = `I am looking for a long series of short-term relationships and am holding a ranked competitive how-much-I-like-you tournament to decide my suitors! Politely ask me to marry you (or become your partner) and I'll evaluate your score. I like copypasta, memes, and long walks in the chat.`
Expand Down
14 changes: 7 additions & 7 deletions command/moderate.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ func Forget(ctx context.Context, robo *Robot, call *Invocation) {
var r message.Sent
switch n {
case 0:
r = message.Format("", "No messages contained %q.", term)
r = message.Format("No messages contained %q.", term)
case 1:
r = message.Format("", "Forgot 1 message.")
r = message.Format("Forgot 1 message.")
default:
r = message.Format("", "Forgot %d messages.", n)
r = message.Format("Forgot %d messages.", n)
}
call.Channel.Message(ctx, r.AsReply(call.Message.ID))
}
Expand Down Expand Up @@ -75,7 +75,7 @@ func Quiet(ctx context.Context, robo *Robot, call *Invocation) {
n, err := strconv.Atoi(m[1])
if err != nil {
// Should be impossible.
call.Channel.Message(ctx, message.Format("", `sorry? (%v)`, err).AsReply(call.Message.ID))
call.Channel.Message(ctx, message.Format(`sorry? (%v)`, err).AsReply(call.Message.ID))
return
}
switch m[2][0] {
Expand All @@ -89,7 +89,7 @@ func Quiet(ctx context.Context, robo *Robot, call *Invocation) {
var err error
dur, err = time.ParseDuration(call.Args["dur"])
if err != nil {
call.Channel.Message(ctx, message.Format("", `sorry? (%v)`, err).AsReply(call.Message.ID))
call.Channel.Message(ctx, message.Format(`sorry? (%v)`, err).AsReply(call.Message.ID))
return
}
}
Expand All @@ -102,7 +102,7 @@ func Quiet(ctx context.Context, robo *Robot, call *Invocation) {
// Only do the spiel if the timer isn't very short.
// Otherwise it's likely just clearing an existing silent time.
if dur > 5*time.Second {
call.Channel.Message(ctx, message.Format("", `I won't talk or learn for %v. Some commands relating to moderation and privacy will still make me talk. I'll mention when quiet time is up.`, dur).AsReply(call.Message.ID))
call.Channel.Message(ctx, message.Format(`I won't talk or learn for %v. Some commands relating to moderation and privacy will still make me talk. I'll mention when quiet time is up.`, dur).AsReply(call.Message.ID))
}
t := time.NewTimer(dur)
defer t.Stop()
Expand All @@ -116,7 +116,7 @@ func Quiet(ctx context.Context, robo *Robot, call *Invocation) {
if call.Channel.Silent.Load() != n {
return
}
call.Channel.Message(ctx, message.Format("", `@%s My quiet time has ended.`, call.Message.Sender.Name))
call.Channel.Message(ctx, message.Format(`@%s My quiet time has ended.`, call.Message.Sender.Name))
}
}

Expand Down
10 changes: 5 additions & 5 deletions command/privacy.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,25 @@ func Private(ctx context.Context, robo *Robot, call *Invocation) {
err := robo.Privacy.Add(ctx, call.Message.Sender.ID)
if err != nil {
robo.Log.ErrorContext(ctx, "privacy add failed", slog.Any("err", err), slog.String("channel", call.Channel.Name))
call.Channel.Message(ctx, message.Format("", "Something went wrong while trying to add you to the privacy list. Try again. Sorry!").AsReply(call.Message.ID))
call.Channel.Message(ctx, message.Format("Something went wrong while trying to add you to the privacy list. Try again. Sorry!").AsReply(call.Message.ID))
return
}
e := call.Channel.Emotes.Pick(rand.Uint32())
call.Channel.Message(ctx, message.Format("", `Sure, I won't learn from your messages. Most of my functionality will still work for you. If you'd like to have me learn from you again, just tell me, "learn from me again." %s`, e).AsReply(call.Message.ID))
call.Channel.Message(ctx, message.Format(`Sure, I won't learn from your messages. Most of my functionality will still work for you. If you'd like to have me learn from you again, just tell me, "learn from me again." %s`, e).AsReply(call.Message.ID))
}

func Unprivate(ctx context.Context, robo *Robot, call *Invocation) {
err := robo.Privacy.Remove(ctx, call.Message.Sender.ID)
if err != nil {
robo.Log.ErrorContext(ctx, "privacy remove failed", slog.Any("err", err), slog.String("channel", call.Channel.Name))
call.Channel.Message(ctx, message.Format("", "Something went wrong while trying to add you to the privacy list. Try again. Sorry!").AsReply(call.Message.ID))
call.Channel.Message(ctx, message.Format("Something went wrong while trying to add you to the privacy list. Try again. Sorry!").AsReply(call.Message.ID))
return
}
e := call.Channel.Emotes.Pick(rand.Uint32())
call.Channel.Message(ctx, message.Format("", `Sure, I'll learn from you again! %s`, e).AsReply(call.Message.ID))
call.Channel.Message(ctx, message.Format(`Sure, I'll learn from you again! %s`, e).AsReply(call.Message.ID))
}

func DescribePrivacy(ctx context.Context, robo *Robot, call *Invocation) {
// TODO(zeph): describe privacy
call.Channel.Message(ctx, message.Format("", `See here for a description of what information I collect, and how to opt out of all collection: https://github.com/zephyrtronium/robot#what-data-does-robot-store`).AsReply(call.Message.ID))
call.Channel.Message(ctx, message.Format(`See here for a description of what information I collect, and how to opt out of all collection: https://github.com/zephyrtronium/robot#what-data-does-robot-store`).AsReply(call.Message.ID))
}
30 changes: 15 additions & 15 deletions command/talk.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ func Rawr(ctx context.Context, robo *Robot, call *Invocation) {
r.CancelAt(t)
return
}
call.Channel.Message(ctx, message.Format("", "rawr %s", e).AsReply(call.Message.ID))
call.Channel.Message(ctx, message.Format("rawr %s", e).AsReply(call.Message.ID))
}

// HappyBirthdayToYou wishes the robot a happy birthday.
Expand All @@ -169,32 +169,32 @@ func HappyBirthdayToYou(ctx context.Context, robo *Robot, call *Invocation) {
var m message.Sent
switch t.Month() {
case time.January:
m = message.Format("", "No no no my birthday is next month. %s", e)
m = message.Format("No no no my birthday is next month. %s", e)
case time.February:
switch t.Day() {
case 1, 2, 3, 4, 5:
m = message.Format("", "Oh, but my birthday is later this month. %s", e)
m = message.Format("Oh, but my birthday is later this month. %s", e)
case 6:
m = message.Format("", "My birthday is just a week away! I am so excited about this information. %s", e)
m = message.Format("My birthday is just a week away! I am so excited about this information. %s", e)
case 7, 8, 9, 10:
m = message.Format("", "My birthday is still less than a week away. %s", e)
m = message.Format("My birthday is still less than a week away. %s", e)
case 11:
m = message.Format("", "Two days away...! %s", e)
m = message.Format("Two days away...! %s", e)
case 12:
m = message.Format("", "My birthday is tomorrow! At least in my timezone. %s", e)
m = message.Format("My birthday is tomorrow! At least in my timezone. %s", e)
case 13:
m = message.Format("", "Thank you! Happy my birthday to you, too! %s", e)
m = message.Format("Thank you! Happy my birthday to you, too! %s", e)
case 14:
m = message.Format("", "You missed it. My birthday was yesterday. You are disqualified from being my valentine. %s", e)
m = message.Format("You missed it. My birthday was yesterday. You are disqualified from being my valentine. %s", e)
case 15, 16, 17, 18, 19, 20:
m = message.Format("", "My birthday was the other day, actually, but I appreciate the sentiment. %s", e)
m = message.Format("My birthday was the other day, actually, but I appreciate the sentiment. %s", e)
default:
m = message.Format("", "My birthday was earlier this month, actually, but I appreciate the sentiment. %s", e)
m = message.Format("My birthday was earlier this month, actually, but I appreciate the sentiment. %s", e)
}
case time.March:
m = message.Format("", "No no no my birthday was last month. %s", e)
m = message.Format("No no no my birthday was last month. %s", e)
default:
m = message.Format("", "My birthday is in February, silly %s", e)
m = message.Format("My birthday is in February, silly %s", e)
}
call.Channel.Message(ctx, m.AsReply(call.Message.ID))
}
Expand All @@ -211,11 +211,11 @@ func Source(ctx context.Context, robo *Robot, call *Invocation) {
func Who(ctx context.Context, robo *Robot, call *Invocation) {
const whoMessage = `I'm a Markov chain bot! I learn from things people say in chat, then spew vaguely intelligible memes back. More info at: https://github.com/zephyrtronium/robot#how-robot-works %s`
e := call.Channel.Emotes.Pick(rand.Uint32())
call.Channel.Message(ctx, message.Format("", whoMessage, e).AsReply(call.Message.ID))
call.Channel.Message(ctx, message.Format(whoMessage, e).AsReply(call.Message.ID))
}

// Contact gives information on how to contact the bot owner.
func Contact(ctx context.Context, robo *Robot, call *Invocation) {
e := call.Channel.Emotes.Pick(rand.Uint32())
call.Channel.Message(ctx, message.Format("", "My operator is %[1]s. %[2]s is the best way to contact %[1]s. %[3]s", robo.Owner, robo.Contact, e).AsReply(call.Message.ID))
call.Channel.Message(ctx, message.Format("My operator is %[1]s. %[2]s is the best way to contact %[1]s. %[3]s", robo.Owner, robo.Contact, e).AsReply(call.Message.ID))
}
18 changes: 9 additions & 9 deletions command/tamagotchi.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func Tamagotchi(ctx context.Context, robo *Robot, call *Invocation) {
e := call.Channel.Emotes.Pick(rand.Uint32())
sat := robo.Pet.Satisfaction(call.Message.Time())
_, m := satmsg(sat)
call.Channel.Message(ctx, message.Format("", "%s %s", m, e).AsReply(call.Message.ID))
call.Channel.Message(ctx, message.Format("%s %s", m, e).AsReply(call.Message.ID))
}

type dinner struct {
Expand Down Expand Up @@ -154,12 +154,12 @@ func Eat(ctx context.Context, robo *Robot, call *Invocation) {
)
if !ok {
s := fullmsgs.Pick(rand.Uint32())
call.Channel.Message(ctx, message.Format("", "%s %s", s, e).AsReply(call.Message.ID))
call.Channel.Message(ctx, message.Format("%s %s", s, e).AsReply(call.Message.ID))
return
}
c, m := satmsg(sat)
chew := chewmsgs.Pick(rand.Uint32())
call.Channel.Message(ctx, message.Format("", "%s %s %s %s %s%s %s %s", chew[0], menu[0].name, menu[1].name, menu[2].name, chew[1], c, m, e).AsReply(call.Message.ID))
call.Channel.Message(ctx, message.Format("%s %s %s %s %s%s %s %s", chew[0], menu[0].name, menu[1].name, menu[2].name, chew[1], c, m, e).AsReply(call.Message.ID))
}

var cleancounts = pick.New([]pick.Case[int]{
Expand Down Expand Up @@ -208,15 +208,15 @@ func Clean(ctx context.Context, robo *Robot, call *Invocation) {
var msg message.Sent
switch len(rooms) {
case 0:
msg = message.Format("", "Everything's already clean! %s %s", m, e)
msg = message.Format("Everything's already clean! %s %s", m, e)
case 1:
msg = message.Format("", "%s %s%s Now %s %s", clean[0], rooms[0], clean[1], m, e)
msg = message.Format("%s %s%s Now %s %s", clean[0], rooms[0], clean[1], m, e)
case 2:
msg = message.Format("", "%s %s and %s%s Now %s %s", clean[0], rooms[0], rooms[1], clean[1], m, e)
msg = message.Format("%s %s and %s%s Now %s %s", clean[0], rooms[0], rooms[1], clean[1], m, e)
case 3:
msg = message.Format("", "%s %s, %s, and %s%s Now %s %s", clean[0], rooms[0], rooms[1], rooms[2], clean[1], m, e)
msg = message.Format("%s %s, %s, and %s%s Now %s %s", clean[0], rooms[0], rooms[1], rooms[2], clean[1], m, e)
case 4:
msg = message.Format("", "%s whole home%s Now %s %s", clean[0], clean[1], m, e)
msg = message.Format("%s whole home%s Now %s %s", clean[0], clean[1], m, e)
}
call.Channel.Message(ctx, msg.AsReply(call.Message.ID))
}
Expand Down Expand Up @@ -280,5 +280,5 @@ func Pat(ctx context.Context, robo *Robot, call *Invocation) {
)
sat := robo.Pet.Pat(call.Message.Time(), pat.love)
_, m := satmsg(sat)
call.Channel.Message(ctx, message.Format("", "%s %s %s", pat.where, m, e).AsReply(call.Message.ID))
call.Channel.Message(ctx, message.Format("%s %s %s", pat.where, m, e).AsReply(call.Message.ID))
}
10 changes: 7 additions & 3 deletions message/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ type Sent struct {
// Reply is a message to reply to. If empty, the message is not interpreted
// as a reply.
Reply string
// To is the channel to whom the message is sent.
// To is the channel to which the message is sent.
To string
// Text is the message text.
Text string
Expand All @@ -60,14 +60,18 @@ func (m Sent) AsReply(reply string) Sent {
return m
}

func (m Sent) SendTo(to string) Sent {
m.To = to
return m
}

// formatString is a type to prevent misuse of format strings passed to [Format].
type formatString string

// Format constructs a message to send from a format string literal and
// formatting arguments.
func Format(to string, f formatString, args ...any) Sent {
func Format(f formatString, args ...any) Sent {
return Sent{
To: to,
Text: strings.TrimSpace(fmt.Sprintf(string(f), args...)),
}
}
4 changes: 2 additions & 2 deletions privmsg.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ func (robo *Robot) tmiMessage(ctx context.Context, send chan<- *tmi.Message, msg
slog.String("text", s),
slog.String("effect", f),
)
msg := message.Format(ch.Name, "%s", s)
msg := message.Format("%s", s).SendTo(ch.Name)
robo.sendTMI(ctx, send, msg)
return
default:
Expand Down Expand Up @@ -165,7 +165,7 @@ func (robo *Robot) tmiMessage(ctx context.Context, send chan<- *tmi.Message, msg
r.CancelAt(t)
return
}
out := message.Format(ch.Name, "%s", sef)
out := message.Format("%s", sef).SendTo(ch.Name)
robo.sendTMI(ctx, send, out)
}

Expand Down

0 comments on commit 1b60287

Please sign in to comment.