X-Git-Url: http://git.giacomolli.uk/onechat/blobdiff_plain/1379d7d0d0173416237ddf8ebe820743d2cecfa6..de170709599e849c6b409d247b800dc68b0c7ab7:/telegram_markdown.go?ds=inline diff --git a/telegram_markdown.go b/telegram_markdown.go index 54bfbcb..16b83f2 100644 --- a/telegram_markdown.go +++ b/telegram_markdown.go @@ -68,6 +68,37 @@ func telegramMarkdownEntities(markdown string) (string, []TelegramEntity) { return out.text.String(), out.entities } +// telegramEscapeTags puts a backslash before each < of markdown outside inline +// code and fenced code blocks, so that rich Markdown shows a tag name as text +// and reads no raw HTML. A < that a backslash already makes plain stays as it +// is. A code block that does not close runs to the end, as in Markdown. +func telegramEscapeTags(markdown string) string { + var out strings.Builder + lines := strings.Split(markdown, "\n") + for index := 0; index < len(lines); index++ { + if index > 0 { + out.WriteString("\n") + } + + line := lines[index] + _, fence := telegramCodeFence(line) + if fence == "" { + telegramEscapeLineTags(&out, line) + continue + } + + end := telegramClosingFence(lines, index, fence) + if end < 0 { + end = len(lines) - 1 + } + + out.WriteString(strings.Join(lines[index:end+1], "\n")) + index = end + } + + return out.String() +} + // telegramCodeFence returns the language of a line that opens a fenced code // block, and the fence. The fence is "" when line does not open a block. func telegramCodeFence(line string) (string, string) { @@ -225,6 +256,39 @@ func telegramHeadingText(line string) string { return rest } +// telegramEscapeLineTags writes line to out with a backslash before each < that +// is outside inline code and not already plain. A run of backticks that opens +// no inline code stays as text whole, as in Markdown. +func telegramEscapeLineTags(out *strings.Builder, line string) { + for index := 0; index < len(line); { + switch line[index] { + case '\\': + if index+1 < len(line) && strings.IndexByte(telegramMarkdownPunctuation, line[index+1]) >= 0 { + out.WriteString(line[index : index+2]) + index += 2 + + continue + } + case '`': + end := index + telegramBackticks(line[index:]) + span, found := telegramCodeSpan(line, index) + if found { + end = span.end + } + + out.WriteString(line[index:end]) + index = end + + continue + case '<': + out.WriteByte('\\') + } + + out.WriteByte(line[index]) + index++ + } +} + // telegramMarkSpan returns the inline mark that starts at index of line and // closes in line. It returns false when no mark starts there or the mark does // not close.