X-Git-Url: https://git.giacomolli.uk/onechat/blobdiff_plain/f5c601f1801aaa276f8c335fcb51c373edc0b50c..80e348724041a694002fc38f57e8868b9b9a2be9:/telegram_markdown.go?ds=inline diff --git a/telegram_markdown.go b/telegram_markdown.go index fc68634..b6ea5a2 100644 --- a/telegram_markdown.go +++ b/telegram_markdown.go @@ -14,6 +14,75 @@ var ( telegramTagUnescaper = strings.NewReplacer("&", "&", "<", "<") ) +// TelegramMarkdownText is the plain text of a Markdown reply and its Telegram +// entities, while the conversion builds it. Units counts the UTF-16 code units +// of text, the unit of the entity offsets and lengths. +type TelegramMarkdownText struct { + text strings.Builder + units int + entities []TelegramEntity +} + +// add appends text. +func (m *TelegramMarkdownText) add(text string) { + m.text.WriteString(text) + + m.units += telegramUTF16Units(text) +} + +// entity keeps entity, unless it is empty, because Telegram refuses an entity +// of length 0. +func (m *TelegramMarkdownText) entity(entity TelegramEntity) { + if entity.Length > 0 { + m.entities = append(m.entities, entity) + } +} + +// inline appends one line of Markdown with its inline marks as entities. A +// backslash before an ASCII punctuation character makes the character plain +// text. +func (m *TelegramMarkdownText) inline(line string) { + plain := 0 + index := 0 + for index < len(line) { + if line[index] == '\\' && index+1 < len(line) && strings.IndexByte(markdownPunctuation, line[index+1]) >= 0 { + m.add(line[plain:index]) + + plain = index + 1 + index += 2 + + continue + } + + span, found := markdownMarkSpan(line, index) + if !found { + index++ + continue + } + + m.add(line[plain:index]) + + start := m.units + if span.kind == "code" { + m.add(span.content) + } else { + m.inline(span.content) + } + + m.entity(TelegramEntity{ + Type: span.kind, + Offset: start, + Length: m.units - start, + URL: span.url, + }) + + index = span.end + plain = span.end + } + + m.add(line[plain:]) +} + // telegramMarkdownEntities converts the Markdown of a reply to plain text and // Telegram message entities. It knows bold (** and __), italic (* and _), // strikethrough (~~), inline code, fenced code blocks with an optional @@ -102,75 +171,6 @@ func telegramUTF16Units(text string) int { return units } -// TelegramMarkdownText is the plain text of a Markdown reply and its Telegram -// entities, while the conversion builds it. Units counts the UTF-16 code units -// of text, the unit of the entity offsets and lengths. -type TelegramMarkdownText struct { - text strings.Builder - units int - entities []TelegramEntity -} - -// add appends text. -func (m *TelegramMarkdownText) add(text string) { - m.text.WriteString(text) - - m.units += telegramUTF16Units(text) -} - -// entity keeps entity, unless it is empty, because Telegram refuses an entity -// of length 0. -func (m *TelegramMarkdownText) entity(entity TelegramEntity) { - if entity.Length > 0 { - m.entities = append(m.entities, entity) - } -} - -// inline appends one line of Markdown with its inline marks as entities. A -// backslash before an ASCII punctuation character makes the character plain -// text. -func (m *TelegramMarkdownText) inline(line string) { - plain := 0 - index := 0 - for index < len(line) { - if line[index] == '\\' && index+1 < len(line) && strings.IndexByte(markdownPunctuation, line[index+1]) >= 0 { - m.add(line[plain:index]) - - plain = index + 1 - index += 2 - - continue - } - - span, found := markdownMarkSpan(line, index) - if !found { - index++ - continue - } - - m.add(line[plain:index]) - - start := m.units - if span.kind == "code" { - m.add(span.content) - } else { - m.inline(span.content) - } - - m.entity(TelegramEntity{ - Type: span.kind, - Offset: start, - Length: m.units - start, - URL: span.url, - }) - - index = span.end - plain = span.end - } - - m.add(line[plain:]) -} - // telegramRewriteProse returns markdown with rewrite applied to each part of a // line outside inline code and fenced code blocks. A code block that does not // close runs to the end, as in Markdown.