diff --git a/src/api/api.go b/src/api/api.go index 62a2664..7361eff 100644 --- a/src/api/api.go +++ b/src/api/api.go @@ -395,7 +395,7 @@ func (a *Api) Send(c *gin.Context) { // @Summary Send a signal message. // @Tags Messages -// @Description Send a signal message. Set the text_mode to 'styled' in case you want to add formatting to your text message. Styling Options: *italic text*, **bold text**, ~strikethrough text~. +// @Description Send a signal message. Set the text_mode to 'styled' in case you want to add formatting to your text message. Styling Options: *italic text*, **bold text**, ~strikethrough text~. If you want to escape a character, prefix it with two backslashes ('\\') // @Accept json // @Produce json // @Success 201 {object} SendMessageResponse diff --git a/src/docs/docs.go b/src/docs/docs.go index bf16429..77d517f 100644 --- a/src/docs/docs.go +++ b/src/docs/docs.go @@ -2014,7 +2014,7 @@ const docTemplate = `{ }, "/v2/send": { "post": { - "description": "Send a signal message. Set the text_mode to 'styled' in case you want to add formatting to your text message. Styling Options: *italic text*, **bold text**, ~strikethrough text~.", + "description": "Send a signal message. Set the text_mode to 'styled' in case you want to add formatting to your text message. Styling Options: *italic text*, **bold text**, ~strikethrough text~. If you want to escape a character, prefix it with two backslashes ('\\\\')", "consumes": [ "application/json" ], diff --git a/src/docs/swagger.json b/src/docs/swagger.json index 71dab60..b032016 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -2011,7 +2011,7 @@ }, "/v2/send": { "post": { - "description": "Send a signal message. Set the text_mode to 'styled' in case you want to add formatting to your text message. Styling Options: *italic text*, **bold text**, ~strikethrough text~.", + "description": "Send a signal message. Set the text_mode to 'styled' in case you want to add formatting to your text message. Styling Options: *italic text*, **bold text**, ~strikethrough text~. If you want to escape a character, prefix it with two backslashes ('\\\\')", "consumes": [ "application/json" ], diff --git a/src/docs/swagger.yaml b/src/docs/swagger.yaml index 9876554..0f55f66 100644 --- a/src/docs/swagger.yaml +++ b/src/docs/swagger.yaml @@ -1754,7 +1754,8 @@ paths: - application/json description: 'Send a signal message. Set the text_mode to ''styled'' in case you want to add formatting to your text message. Styling Options: *italic - text*, **bold text**, ~strikethrough text~.' + text*, **bold text**, ~strikethrough text~. If you want to escape a character, + prefix it with two backslashes (''\\'')' parameters: - description: Input Data in: body diff --git a/src/utils/textstyleparser.go b/src/utils/textstyleparser.go index 6abd348..8df7f57 100644 --- a/src/utils/textstyleparser.go +++ b/src/utils/textstyleparser.go @@ -25,6 +25,8 @@ const ( SpoilerBegin = 9 ) +const EscapeCharacter rune = '\\' + func getUtf16StringLength(s string) int { runes := []rune(s) //turn string to slice @@ -74,7 +76,6 @@ type TextstyleParser struct { tokens Stack fullString string signalCliFormatStrings []string - //numOfControlTokens int } func NewTextstyleParser(input string) *TextstyleParser { @@ -93,9 +94,6 @@ func (l *TextstyleParser) next() (rune rune) { l.width = 0 return eof } - //r := []rune(l.input[l.pos:])[0] - //l.width = utf16.RuneLen(r) - //l.pos += l.width rune, l.width = utf8.DecodeRuneInString(l.input[l.pos:]) l.pos += l.width return rune @@ -129,6 +127,7 @@ func (l *TextstyleParser) handleToken(tokenType int, signalCliStylingType string } func (l *TextstyleParser) Parse() (string, []string) { + var prevChar rune for { c := l.next() if c == eof { @@ -140,20 +139,45 @@ func (l *TextstyleParser) Parse() (string, []string) { if c == '*' { if nextRune == '*' { //Bold l.next() + if prevChar == EscapeCharacter { + prevChar = c + continue + } l.handleToken(BoldBegin, Bold) } else { //Italic + if prevChar == EscapeCharacter { + prevChar = c + continue + } l.handleToken(ItalicBegin, Italic) } } else if (c == '|') && (nextRune == '|') { l.next() + if prevChar == EscapeCharacter { + prevChar = c + continue + } l.handleToken(SpoilerBegin, Spoiler) } else if c == '~' { + if prevChar == EscapeCharacter { + prevChar = c + continue + } l.handleToken(StrikethroughBegin, Strikethrough) } else if c == '`' { + if prevChar == EscapeCharacter { + prevChar = c + continue + } l.handleToken(MonoSpaceBegin, Monospace) + } else if ((c == EscapeCharacter) && (nextRune == '*')) || ((c == EscapeCharacter) && (nextRune == '`')) || ((c == EscapeCharacter) && (nextRune == '|')) || ((c == EscapeCharacter) && (nextRune == '~')) { + prevChar = c + continue } else { l.fullString += string(c) } + + prevChar = c } return l.fullString, l.signalCliFormatStrings diff --git a/src/utils/textstyleparser_test.go b/src/utils/textstyleparser_test.go index ea0055c..eb8dfe2 100644 --- a/src/utils/textstyleparser_test.go +++ b/src/utils/textstyleparser_test.go @@ -119,3 +119,31 @@ func TestBoldTextInsideSpoiler(t *testing.T) { expectMessageEqual(t, message, "this is a bold text inside a spoiler") expectFormatStringsEqual(t, signalCliFormatStrings, []string{"0:36:BOLD", "0:36:SPOILER"}) } + +func TestEscapeAsterisks(t *testing.T) { + textstyleParser := NewTextstyleParser("\\*escaped text\\*") + message, signalCliFormatStrings := textstyleParser.Parse() + expectMessageEqual(t, message, "escaped text") + expectFormatStringsEqual(t, signalCliFormatStrings, []string{}) +} + +func TestEscapeAsterisks1(t *testing.T) { + textstyleParser := NewTextstyleParser("\\**escaped text\\**") + message, signalCliFormatStrings := textstyleParser.Parse() + expectMessageEqual(t, message, "escaped text") + expectFormatStringsEqual(t, signalCliFormatStrings, []string{}) +} + +func TestEscapeBackticks(t *testing.T) { + textstyleParser := NewTextstyleParser("\\`escaped text\\`") + message, signalCliFormatStrings := textstyleParser.Parse() + expectMessageEqual(t, message, "escaped text") + expectFormatStringsEqual(t, signalCliFormatStrings, []string{}) +} + +func TestEscapeTilde(t *testing.T) { + textstyleParser := NewTextstyleParser("\\~escaped text\\~") + message, signalCliFormatStrings := textstyleParser.Parse() + expectMessageEqual(t, message, "escaped text") + expectFormatStringsEqual(t, signalCliFormatStrings, []string{}) +}