Skip to content

fix: unescape literal \n sequences in Telegram message formatting#193

Closed
ptone wants to merge 2 commits into
mainfrom
scion/telegram-newlines
Closed

fix: unescape literal \n sequences in Telegram message formatting#193
ptone wants to merge 2 commits into
mainfrom
scion/telegram-newlines

Conversation

@ptone

@ptone ptone commented Jun 9, 2026

Copy link
Copy Markdown
Owner

Summary

  • Adds unescapeNewlines helper that replaces literal \n and \t escape sequences with actual newline and tab characters
  • Applies the helper in both FormatMessage and FormatMessageV2 before writing msg.Msg to the output buffer
  • Message text can arrive with literal escape sequences when it passes through JSON encoding (e.g. FormatForDelivery) and is forwarded without decoding, or when shell arguments carry un-interpreted backslash escapes

Closes #48

Test plan

  • Added TestUnescapeNewlines with 7 cases covering no escapes, single/double newlines, tabs, mixed, actual newlines unchanged, and empty string
  • Added TestFormatMessage_UnescapesLiteralNewlines verifying FormatMessage output contains actual newlines
  • Added TestFormatMessageV2_UnescapesLiteralNewlines verifying FormatMessageV2 output contains actual newlines
  • Full telegram test suite passes (all existing tests unaffected)

Message text arriving at the Telegram formatter can contain literal
backslash-n escape sequences instead of actual newlines — either from
JSON encoding round-trips (FormatForDelivery) or from shell arguments
that don't interpret \n. Apply unescapeNewlines in FormatMessage and
FormatMessageV2 so Telegram displays proper line breaks.

Closes #48

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a helper function unescapeNewlines to replace literal escape sequences (\n and \t) with their actual characters in formatted Telegram messages, and adds corresponding unit tests. Feedback suggests optimizing this helper by declaring the strings.Replacer as a package-level variable to avoid the overhead of recreating it on every function call.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +335 to +341
// unescapeNewlines replaces literal escape sequences (\n, \t) with their actual
// characters. Message text may arrive with these sequences when it passes through
// JSON encoding (e.g. FormatForDelivery) and is later forwarded without decoding,
// or when shell arguments carry un-interpreted backslash escapes.
func unescapeNewlines(s string) string {
return strings.NewReplacer(`\n`, "\n", `\t`, "\t").Replace(s)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Creating a new strings.Replacer on every call to unescapeNewlines is inefficient because strings.NewReplacer performs preprocessing to build its internal lookup structures. Declaring the replacer as a package-level variable avoids this overhead and improves performance.

Suggested change
// unescapeNewlines replaces literal escape sequences (\n, \t) with their actual
// characters. Message text may arrive with these sequences when it passes through
// JSON encoding (e.g. FormatForDelivery) and is later forwarded without decoding,
// or when shell arguments carry un-interpreted backslash escapes.
func unescapeNewlines(s string) string {
return strings.NewReplacer(`\n`, "\n", `\t`, "\t").Replace(s)
}
var unescapeReplacer = strings.NewReplacer("\\n", "\n", "\\t", "\t")
// unescapeNewlines replaces literal escape sequences (\n, \t) with their actual
// characters. Message text may arrive with these sequences when it passes through
// JSON encoding (e.g. FormatForDelivery) and is later forwarded without decoding,
// or when shell arguments carry un-interpreted backslash escapes.
func unescapeNewlines(s string) string {
return unescapeReplacer.Replace(s)
}

Avoids re-allocating the replacer on every call to unescapeNewlines.
@ptone ptone closed this Jun 9, 2026
@ptone ptone deleted the scion/telegram-newlines branch June 9, 2026 17:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant