refactor: improve SplitMessage API clarity
- Accept hard upper limit (maxLen) instead of pre-subtracted value - Caller now passes actual platform limit (e.g., 2000 for Discord) - Internal buffer of 500 chars is handled within message.go - Preferred split at maxLen - 500, may extend to maxLen for code blocks - Never exceeds maxLen, no more mental math for callers
This commit is contained in:
parent
94a1b8664b
commit
e03124dc8a
2 changed files with 24 additions and 19 deletions
|
|
@ -105,7 +105,7 @@ func (c *DiscordChannel) Send(ctx context.Context, msg bus.OutboundMessage) erro
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
chunks := utils.SplitMessage(msg.Content, 1500) // Discord has a limit of 2000 characters per message, leave 500 for natural split e.g. code blocks
|
chunks := utils.SplitMessage(msg.Content, 2000) // Discord hard limit: 2000 chars (prefers split at 1500 to leave room for code blocks)
|
||||||
|
|
||||||
for _, chunk := range chunks {
|
for _, chunk := range chunks {
|
||||||
if err := c.sendChunk(ctx, channelID, chunk); err != nil {
|
if err := c.sendChunk(ctx, channelID, chunk); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -4,26 +4,35 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SplitMessage splits long messages into chunks, preserving code block integrity
|
const defaultCodeBlockBuffer = 500
|
||||||
// Uses natural boundaries (newlines, spaces) and extends messages slightly to avoid breaking code blocks
|
|
||||||
func SplitMessage(content string, limit int) []string {
|
// SplitMessage splits long messages into chunks, preserving code block integrity.
|
||||||
|
// The maxLen parameter is the hard upper limit - no message will exceed this length.
|
||||||
|
// The function prefers to split at maxLen - defaultCodeBlockBuffer to leave room for code blocks,
|
||||||
|
// but may extend up to maxLen when needed to avoid breaking incomplete code blocks.
|
||||||
|
func SplitMessage(content string, maxLen int) []string {
|
||||||
var messages []string
|
var messages []string
|
||||||
|
codeBlockBuffer := defaultCodeBlockBuffer
|
||||||
|
|
||||||
for len(content) > 0 {
|
for len(content) > 0 {
|
||||||
if len(content) <= limit {
|
if len(content) <= maxLen {
|
||||||
messages = append(messages, content)
|
messages = append(messages, content)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
msgEnd := limit
|
// Effective split point: maxLen minus buffer, to leave room for code blocks
|
||||||
|
effectiveLimit := maxLen - codeBlockBuffer
|
||||||
|
if effectiveLimit < maxLen/2 {
|
||||||
|
effectiveLimit = maxLen / 2
|
||||||
|
}
|
||||||
|
|
||||||
// Find natural split point within the limit
|
// Find natural split point within the effective limit
|
||||||
msgEnd = FindLastNewline(content[:limit], 200)
|
msgEnd := FindLastNewline(content[:effectiveLimit], 200)
|
||||||
if msgEnd <= 0 {
|
if msgEnd <= 0 {
|
||||||
msgEnd = FindLastSpace(content[:limit], 100)
|
msgEnd = FindLastSpace(content[:effectiveLimit], 100)
|
||||||
}
|
}
|
||||||
if msgEnd <= 0 {
|
if msgEnd <= 0 {
|
||||||
msgEnd = limit
|
msgEnd = effectiveLimit
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this would end with an incomplete code block
|
// Check if this would end with an incomplete code block
|
||||||
|
|
@ -32,15 +41,14 @@ func SplitMessage(content string, limit int) []string {
|
||||||
|
|
||||||
if unclosedIdx >= 0 {
|
if unclosedIdx >= 0 {
|
||||||
// Message would end with incomplete code block
|
// Message would end with incomplete code block
|
||||||
// Try to extend to include the closing ``` (with some buffer)
|
// Try to extend up to maxLen (hard limit, never exceed) to include the closing ```
|
||||||
extendedLimit := limit + 500 // Allow 500 char buffer for code blocks
|
if len(content) > msgEnd {
|
||||||
if len(content) > extendedLimit {
|
|
||||||
closingIdx := FindNextClosingCodeBlock(content, msgEnd)
|
closingIdx := FindNextClosingCodeBlock(content, msgEnd)
|
||||||
if closingIdx > 0 && closingIdx <= extendedLimit {
|
if closingIdx > 0 && closingIdx <= maxLen {
|
||||||
// Extend to include the closing ```
|
// Extend to include the closing ```
|
||||||
msgEnd = closingIdx
|
msgEnd = closingIdx
|
||||||
} else {
|
} else {
|
||||||
// Can't find closing, split before the code block
|
// Can't find closing within maxLen, split before the code block
|
||||||
msgEnd = FindLastNewline(content[:unclosedIdx], 200)
|
msgEnd = FindLastNewline(content[:unclosedIdx], 200)
|
||||||
if msgEnd <= 0 {
|
if msgEnd <= 0 {
|
||||||
msgEnd = FindLastSpace(content[:unclosedIdx], 100)
|
msgEnd = FindLastSpace(content[:unclosedIdx], 100)
|
||||||
|
|
@ -49,14 +57,11 @@ func SplitMessage(content string, limit int) []string {
|
||||||
msgEnd = unclosedIdx
|
msgEnd = unclosedIdx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Remaining content fits within extended limit
|
|
||||||
msgEnd = len(content)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if msgEnd <= 0 {
|
if msgEnd <= 0 {
|
||||||
msgEnd = limit
|
msgEnd = effectiveLimit
|
||||||
}
|
}
|
||||||
|
|
||||||
messages = append(messages, content[:msgEnd])
|
messages = append(messages, content[:msgEnd])
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue