-module(telega@format). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/telega/format.gleam"). -export([parse_mode_to_string/1, build/0, with_mode/2, text/2, bold_text/2, italic_text/2, underline_text/2, strikethrough_text/2, spoiler_text/2, code_text/2, pre_text/3, link_text/3, mention_text/2, custom_emoji_text/3, line_break/1, escape_html/1, to_html/1, escape_markdown/1, to_markdown/1, escape_markdown_v2/1, to_markdown_v2/1, to_formatted/1, render/1, bold/1, italic/1, underline/1, strikethrough/1, spoiler/1, code/1, pre/2, link/2, mention/1]). -export_type([parse_mode/0, formatted_text/0, segment/0, format_builder/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC( " Provides utilities for text formatting in Telegram messages.\n" " Supports HTML, Markdown, and MarkdownV2 parse modes.\n" "\n" " ## Quick Start\n" " ```gleam\n" " import telega/format as fmt\n" "\n" " // Simple formatting\n" " let text = fmt.bold(\"Important!\") <> \" \" <> fmt.italic(\"Read this\")\n" "\n" " // Complex formatting with builder\n" " let message = fmt.build()\n" " |> fmt.text(\"Hello \")\n" " |> fmt.bold_text(\"World\")\n" " |> fmt.line_break()\n" " |> fmt.link_text(\"Click here\", \"https://example.com\")\n" " |> fmt.to_html()\n" " ```\n" ). -type parse_mode() :: h_t_m_l | markdown | markdown_v2. -opaque formatted_text() :: {formatted_text, list(segment()), parse_mode()}. -type segment() :: {plain, binary()} | {bold, binary()} | {italic, binary()} | {underline, binary()} | {strikethrough, binary()} | {spoiler, binary()} | {code, binary()} | {pre, binary(), gleam@option:option(binary())} | {link, binary(), binary()} | {mention, binary()} | {custom_emoji, binary(), binary()} | {nested, list(segment())}. -opaque format_builder() :: {format_builder, list(segment()), parse_mode()}. -file("src/telega/format.gleam", 32). ?DOC(" Convert ParseMode to string for API\n"). -spec parse_mode_to_string(parse_mode()) -> binary(). parse_mode_to_string(Mode) -> case Mode of h_t_m_l -> <<"HTML"/utf8>>; markdown -> <<"Markdown"/utf8>>; markdown_v2 -> <<"MarkdownV2"/utf8>> end. -file("src/telega/format.gleam", 67). ?DOC(" Create a new format builder with HTML as default\n"). -spec build() -> format_builder(). build() -> {format_builder, [], h_t_m_l}. -file("src/telega/format.gleam", 72). ?DOC(" Set parse mode for builder\n"). -spec with_mode(format_builder(), parse_mode()) -> format_builder(). with_mode(Builder, Mode) -> {format_builder, erlang:element(2, Builder), Mode}. -file("src/telega/format.gleam", 77). ?DOC(" Add plain text\n"). -spec text(format_builder(), binary()) -> format_builder(). text(Builder, Text) -> {format_builder, [{plain, Text} | erlang:element(2, Builder)], erlang:element(3, Builder)}. -file("src/telega/format.gleam", 82). ?DOC(" Add bold text using builder\n"). -spec bold_text(format_builder(), binary()) -> format_builder(). bold_text(Builder, Text) -> {format_builder, [{bold, Text} | erlang:element(2, Builder)], erlang:element(3, Builder)}. -file("src/telega/format.gleam", 87). ?DOC(" Add italic text using builder\n"). -spec italic_text(format_builder(), binary()) -> format_builder(). italic_text(Builder, Text) -> {format_builder, [{italic, Text} | erlang:element(2, Builder)], erlang:element(3, Builder)}. -file("src/telega/format.gleam", 92). ?DOC(" Add underlined text using builder\n"). -spec underline_text(format_builder(), binary()) -> format_builder(). underline_text(Builder, Text) -> {format_builder, [{underline, Text} | erlang:element(2, Builder)], erlang:element(3, Builder)}. -file("src/telega/format.gleam", 97). ?DOC(" Add strikethrough text using builder\n"). -spec strikethrough_text(format_builder(), binary()) -> format_builder(). strikethrough_text(Builder, Text) -> {format_builder, [{strikethrough, Text} | erlang:element(2, Builder)], erlang:element(3, Builder)}. -file("src/telega/format.gleam", 105). ?DOC(" Add spoiler text using builder\n"). -spec spoiler_text(format_builder(), binary()) -> format_builder(). spoiler_text(Builder, Text) -> {format_builder, [{spoiler, Text} | erlang:element(2, Builder)], erlang:element(3, Builder)}. -file("src/telega/format.gleam", 110). ?DOC(" Add inline code using builder\n"). -spec code_text(format_builder(), binary()) -> format_builder(). code_text(Builder, Text) -> {format_builder, [{code, Text} | erlang:element(2, Builder)], erlang:element(3, Builder)}. -file("src/telega/format.gleam", 115). ?DOC(" Add code block using builder\n"). -spec pre_text(format_builder(), binary(), gleam@option:option(binary())) -> format_builder(). pre_text(Builder, Code, Language) -> {format_builder, [{pre, Code, Language} | erlang:element(2, Builder)], erlang:element(3, Builder)}. -file("src/telega/format.gleam", 124). ?DOC(" Add hyperlink using builder\n"). -spec link_text(format_builder(), binary(), binary()) -> format_builder(). link_text(Builder, Text, Url) -> {format_builder, [{link, Text, Url} | erlang:element(2, Builder)], erlang:element(3, Builder)}. -file("src/telega/format.gleam", 133). ?DOC(" Add mention using builder\n"). -spec mention_text(format_builder(), binary()) -> format_builder(). mention_text(Builder, Username) -> {format_builder, [{mention, Username} | erlang:element(2, Builder)], erlang:element(3, Builder)}. -file("src/telega/format.gleam", 138). ?DOC(" Add custom emoji using builder\n"). -spec custom_emoji_text(format_builder(), binary(), binary()) -> format_builder(). custom_emoji_text(Builder, Emoji, Id) -> {format_builder, [{custom_emoji, Emoji, Id} | erlang:element(2, Builder)], erlang:element(3, Builder)}. -file("src/telega/format.gleam", 150). ?DOC(" Add line break\n"). -spec line_break(format_builder()) -> format_builder(). line_break(Builder) -> {format_builder, [{plain, <<"\n"/utf8>>} | erlang:element(2, Builder)], erlang:element(3, Builder)}. -file("src/telega/format.gleam", 255). ?DOC(" Escape special characters for HTML\n"). -spec escape_html(binary()) -> binary(). escape_html(Text) -> _pipe = Text, _pipe@1 = gleam@string:replace(_pipe, <<"&"/utf8>>, <<"&"/utf8>>), _pipe@2 = gleam@string:replace(_pipe@1, <<"<"/utf8>>, <<"<"/utf8>>), _pipe@3 = gleam@string:replace(_pipe@2, <<">"/utf8>>, <<">"/utf8>>), gleam@string:replace(_pipe@3, <<"\""/utf8>>, <<"""/utf8>>). -file("src/telega/format.gleam", 302). -spec segment_to_html(segment()) -> binary(). segment_to_html(Segment) -> case Segment of {plain, Text} -> escape_html(Text); {bold, Text@1} -> <<<<""/utf8, (escape_html(Text@1))/binary>>/binary, ""/utf8>>; {italic, Text@2} -> <<<<""/utf8, (escape_html(Text@2))/binary>>/binary, ""/utf8>>; {underline, Text@3} -> <<<<""/utf8, (escape_html(Text@3))/binary>>/binary, ""/utf8>>; {strikethrough, Text@4} -> <<<<""/utf8, (escape_html(Text@4))/binary>>/binary, ""/utf8>>; {spoiler, Text@5} -> <<<<""/utf8, (escape_html(Text@5))/binary>>/binary, ""/utf8>>; {code, Text@6} -> <<<<""/utf8, (escape_html(Text@6))/binary>>/binary, ""/utf8>>; {pre, Code, none} -> <<<<"
"/utf8, (escape_html(Code))/binary>>/binary,
                "
"/utf8>>; {pre, Code@1, {some, Lang}} -> <<<<<<<<"
>/binary,
                        "\">"/utf8>>/binary,
                    (escape_html(Code@1))/binary>>/binary,
                "
"/utf8>>; {link, Text@7, Url} -> <<<<<<<<">/binary, "\">"/utf8>>/binary, (escape_html(Text@7))/binary>>/binary, ""/utf8>>; {mention, Username} -> <<"@"/utf8, (escape_html(Username))/binary>>; {custom_emoji, Emoji, Id} -> <<<<<<<<">/binary, "\">"/utf8>>/binary, (escape_html(Emoji))/binary>>/binary, ""/utf8>>; {nested, Segments} -> _pipe = Segments, _pipe@1 = gleam@list:map(_pipe, fun segment_to_html/1), gleam@string:join(_pipe@1, <<""/utf8>>) end. -file("src/telega/format.gleam", 155). ?DOC(" Build to HTML string\n"). -spec to_html(format_builder()) -> binary(). to_html(Builder) -> _pipe = erlang:element(2, Builder), _pipe@1 = lists:reverse(_pipe), _pipe@2 = gleam@list:map(_pipe@1, fun segment_to_html/1), gleam@string:join(_pipe@2, <<""/utf8>>). -file("src/telega/format.gleam", 264). ?DOC(" Escape special characters for Markdown\n"). -spec escape_markdown(binary()) -> binary(). escape_markdown(Text) -> _pipe = Text, _pipe@1 = gleam@string:replace(_pipe, <<"\\"/utf8>>, <<"\\\\"/utf8>>), _pipe@2 = gleam@string:replace(_pipe@1, <<"_"/utf8>>, <<"\\_"/utf8>>), _pipe@3 = gleam@string:replace(_pipe@2, <<"*"/utf8>>, <<"\\*"/utf8>>), _pipe@4 = gleam@string:replace(_pipe@3, <<"["/utf8>>, <<"\\["/utf8>>), _pipe@5 = gleam@string:replace(_pipe@4, <<"]"/utf8>>, <<"\\]"/utf8>>), _pipe@6 = gleam@string:replace(_pipe@5, <<"("/utf8>>, <<"\\("/utf8>>), _pipe@7 = gleam@string:replace(_pipe@6, <<")"/utf8>>, <<"\\)"/utf8>>), gleam@string:replace(_pipe@7, <<"`"/utf8>>, <<"\\`"/utf8>>). -file("src/telega/format.gleam", 334). -spec segment_to_markdown(segment()) -> binary(). segment_to_markdown(Segment) -> case Segment of {plain, Text} -> escape_markdown(Text); {bold, Text@1} -> <<<<"*"/utf8, (escape_markdown(Text@1))/binary>>/binary, "*"/utf8>>; {italic, Text@2} -> <<<<"_"/utf8, (escape_markdown(Text@2))/binary>>/binary, "_"/utf8>>; {code, Text@3} -> <<<<"`"/utf8, Text@3/binary>>/binary, "`"/utf8>>; {pre, Code, _} -> <<<<"```\n"/utf8, Code/binary>>/binary, "\n```"/utf8>>; {link, Text@4, Url} -> <<<<<<<<"["/utf8, (escape_markdown(Text@4))/binary>>/binary, "]("/utf8>>/binary, Url/binary>>/binary, ")"/utf8>>; {underline, Text@5} -> escape_markdown(Text@5); {strikethrough, Text@5} -> escape_markdown(Text@5); {spoiler, Text@5} -> escape_markdown(Text@5); {mention, Username} -> <<"@"/utf8, (escape_markdown(Username))/binary>>; {custom_emoji, Emoji, _} -> Emoji; {nested, Segments} -> _pipe = Segments, _pipe@1 = gleam@list:map(_pipe, fun segment_to_markdown/1), gleam@string:join(_pipe@1, <<""/utf8>>) end. -file("src/telega/format.gleam", 163). ?DOC(" Build to Markdown string\n"). -spec to_markdown(format_builder()) -> binary(). to_markdown(Builder) -> _pipe = erlang:element(2, Builder), _pipe@1 = lists:reverse(_pipe), _pipe@2 = gleam@list:map(_pipe@1, fun segment_to_markdown/1), gleam@string:join(_pipe@2, <<""/utf8>>). -file("src/telega/format.gleam", 277). ?DOC(" Escape special characters for MarkdownV2\n"). -spec escape_markdown_v2(binary()) -> binary(). escape_markdown_v2(Text) -> _pipe = Text, _pipe@1 = gleam@string:replace(_pipe, <<"\\"/utf8>>, <<"\\\\"/utf8>>), _pipe@2 = gleam@string:replace(_pipe@1, <<"_"/utf8>>, <<"\\_"/utf8>>), _pipe@3 = gleam@string:replace(_pipe@2, <<"*"/utf8>>, <<"\\*"/utf8>>), _pipe@4 = gleam@string:replace(_pipe@3, <<"["/utf8>>, <<"\\["/utf8>>), _pipe@5 = gleam@string:replace(_pipe@4, <<"]"/utf8>>, <<"\\]"/utf8>>), _pipe@6 = gleam@string:replace(_pipe@5, <<"("/utf8>>, <<"\\("/utf8>>), _pipe@7 = gleam@string:replace(_pipe@6, <<")"/utf8>>, <<"\\)"/utf8>>), _pipe@8 = gleam@string:replace(_pipe@7, <<"~"/utf8>>, <<"\\~"/utf8>>), _pipe@9 = gleam@string:replace(_pipe@8, <<"`"/utf8>>, <<"\\`"/utf8>>), _pipe@10 = gleam@string:replace(_pipe@9, <<">"/utf8>>, <<"\\>"/utf8>>), _pipe@11 = gleam@string:replace(_pipe@10, <<"#"/utf8>>, <<"\\#"/utf8>>), _pipe@12 = gleam@string:replace(_pipe@11, <<"+"/utf8>>, <<"\\+"/utf8>>), _pipe@13 = gleam@string:replace(_pipe@12, <<"-"/utf8>>, <<"\\-"/utf8>>), _pipe@14 = gleam@string:replace(_pipe@13, <<"="/utf8>>, <<"\\="/utf8>>), _pipe@15 = gleam@string:replace(_pipe@14, <<"|"/utf8>>, <<"\\|"/utf8>>), _pipe@16 = gleam@string:replace(_pipe@15, <<"{"/utf8>>, <<"\\{"/utf8>>), _pipe@17 = gleam@string:replace(_pipe@16, <<"}"/utf8>>, <<"\\}"/utf8>>), _pipe@18 = gleam@string:replace(_pipe@17, <<"."/utf8>>, <<"\\."/utf8>>), gleam@string:replace(_pipe@18, <<"!"/utf8>>, <<"\\!"/utf8>>). -file("src/telega/format.gleam", 354). -spec segment_to_markdown_v2(segment()) -> binary(). segment_to_markdown_v2(Segment) -> case Segment of {plain, Text} -> escape_markdown_v2(Text); {bold, Text@1} -> <<<<"*"/utf8, (escape_markdown_v2(Text@1))/binary>>/binary, "*"/utf8>>; {italic, Text@2} -> <<<<"_"/utf8, (escape_markdown_v2(Text@2))/binary>>/binary, "_"/utf8>>; {underline, Text@3} -> <<<<"__"/utf8, (escape_markdown_v2(Text@3))/binary>>/binary, "__"/utf8>>; {strikethrough, Text@4} -> <<<<"~"/utf8, (escape_markdown_v2(Text@4))/binary>>/binary, "~"/utf8>>; {spoiler, Text@5} -> <<<<"||"/utf8, (escape_markdown_v2(Text@5))/binary>>/binary, "||"/utf8>>; {code, Text@6} -> <<<<"`"/utf8, Text@6/binary>>/binary, "`"/utf8>>; {pre, Code, none} -> <<<<"```\n"/utf8, Code/binary>>/binary, "\n```"/utf8>>; {pre, Code@1, {some, Lang}} -> <<<<<<<<"```"/utf8, Lang/binary>>/binary, "\n"/utf8>>/binary, Code@1/binary>>/binary, "\n```"/utf8>>; {link, Text@7, Url} -> <<<<<<<<"["/utf8, (escape_markdown_v2(Text@7))/binary>>/binary, "]("/utf8>>/binary, (escape_markdown_v2(Url))/binary>>/binary, ")"/utf8>>; {mention, Username} -> <<"@"/utf8, (escape_markdown_v2(Username))/binary>>; {custom_emoji, Emoji, Id} -> <<<<<<<<"!["/utf8, Emoji/binary>>/binary, "](tg://emoji?id="/utf8>>/binary, Id/binary>>/binary, ")"/utf8>>; {nested, Segments} -> _pipe = Segments, _pipe@1 = gleam@list:map(_pipe, fun segment_to_markdown_v2/1), gleam@string:join(_pipe@1, <<""/utf8>>) end. -file("src/telega/format.gleam", 171). ?DOC(" Build to MarkdownV2 string\n"). -spec to_markdown_v2(format_builder()) -> binary(). to_markdown_v2(Builder) -> _pipe = erlang:element(2, Builder), _pipe@1 = lists:reverse(_pipe), _pipe@2 = gleam@list:map(_pipe@1, fun segment_to_markdown_v2/1), gleam@string:join(_pipe@2, <<""/utf8>>). -file("src/telega/format.gleam", 179). ?DOC(" Convert to FormattedText for use with reply functions\n"). -spec to_formatted(format_builder()) -> formatted_text(). to_formatted(Builder) -> {formatted_text, lists:reverse(erlang:element(2, Builder)), erlang:element(3, Builder)}. -file("src/telega/format.gleam", 187). ?DOC(" Render FormattedText to string with parse mode\n"). -spec render(formatted_text()) -> {binary(), parse_mode()}. render(Formatted) -> Text = case erlang:element(3, Formatted) of h_t_m_l -> _pipe = erlang:element(2, Formatted), _pipe@1 = gleam@list:map(_pipe, fun segment_to_html/1), gleam@string:join(_pipe@1, <<""/utf8>>); markdown -> _pipe@2 = erlang:element(2, Formatted), _pipe@3 = gleam@list:map(_pipe@2, fun segment_to_markdown/1), gleam@string:join(_pipe@3, <<""/utf8>>); markdown_v2 -> _pipe@4 = erlang:element(2, Formatted), _pipe@5 = gleam@list:map(_pipe@4, fun segment_to_markdown_v2/1), gleam@string:join(_pipe@5, <<""/utf8>>) end, {Text, erlang:element(3, Formatted)}. -file("src/telega/format.gleam", 208). ?DOC(" Format text as bold (HTML)\n"). -spec bold(binary()) -> binary(). bold(Text) -> segment_to_html({bold, Text}). -file("src/telega/format.gleam", 213). ?DOC(" Format text as italic (HTML)\n"). -spec italic(binary()) -> binary(). italic(Text) -> segment_to_html({italic, Text}). -file("src/telega/format.gleam", 218). ?DOC(" Format text as underline (HTML)\n"). -spec underline(binary()) -> binary(). underline(Text) -> segment_to_html({underline, Text}). -file("src/telega/format.gleam", 223). ?DOC(" Format text as strikethrough (HTML)\n"). -spec strikethrough(binary()) -> binary(). strikethrough(Text) -> segment_to_html({strikethrough, Text}). -file("src/telega/format.gleam", 228). ?DOC(" Format text as spoiler (HTML)\n"). -spec spoiler(binary()) -> binary(). spoiler(Text) -> segment_to_html({spoiler, Text}). -file("src/telega/format.gleam", 233). ?DOC(" Format text as inline code (HTML)\n"). -spec code(binary()) -> binary(). code(Text) -> segment_to_html({code, Text}). -file("src/telega/format.gleam", 238). ?DOC(" Format text as code block (HTML)\n"). -spec pre(binary(), gleam@option:option(binary())) -> binary(). pre(Code, Language) -> segment_to_html({pre, Code, Language}). -file("src/telega/format.gleam", 243). ?DOC(" Format text as hyperlink (HTML)\n"). -spec link(binary(), binary()) -> binary(). link(Text, Url) -> segment_to_html({link, Text, Url}). -file("src/telega/format.gleam", 248). ?DOC(" Format text as mention (HTML)\n"). -spec mention(binary()) -> binary(). mention(Username) -> segment_to_html({mention, Username}).