Current section

Files

Jump to
telega src telega@format.erl
Raw

src/telega@format.erl

-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>>, <<"&amp;"/utf8>>),
_pipe@2 = gleam@string:replace(_pipe@1, <<"<"/utf8>>, <<"&lt;"/utf8>>),
_pipe@3 = gleam@string:replace(_pipe@2, <<">"/utf8>>, <<"&gt;"/utf8>>),
gleam@string:replace(_pipe@3, <<"\""/utf8>>, <<"&quot;"/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} ->
<<<<"<b>"/utf8, (escape_html(Text@1))/binary>>/binary, "</b>"/utf8>>;
{italic, Text@2} ->
<<<<"<i>"/utf8, (escape_html(Text@2))/binary>>/binary, "</i>"/utf8>>;
{underline, Text@3} ->
<<<<"<u>"/utf8, (escape_html(Text@3))/binary>>/binary, "</u>"/utf8>>;
{strikethrough, Text@4} ->
<<<<"<s>"/utf8, (escape_html(Text@4))/binary>>/binary, "</s>"/utf8>>;
{spoiler, Text@5} ->
<<<<"<tg-spoiler>"/utf8, (escape_html(Text@5))/binary>>/binary,
"</tg-spoiler>"/utf8>>;
{code, Text@6} ->
<<<<"<code>"/utf8, (escape_html(Text@6))/binary>>/binary,
"</code>"/utf8>>;
{pre, Code, none} ->
<<<<"<pre>"/utf8, (escape_html(Code))/binary>>/binary,
"</pre>"/utf8>>;
{pre, Code@1, {some, Lang}} ->
<<<<<<<<"<pre><code class=\"language-"/utf8,
(escape_html(Lang))/binary>>/binary,
"\">"/utf8>>/binary,
(escape_html(Code@1))/binary>>/binary,
"</code></pre>"/utf8>>;
{link, Text@7, Url} ->
<<<<<<<<"<a href=\""/utf8, (escape_html(Url))/binary>>/binary,
"\">"/utf8>>/binary,
(escape_html(Text@7))/binary>>/binary,
"</a>"/utf8>>;
{mention, Username} ->
<<"@"/utf8, (escape_html(Username))/binary>>;
{custom_emoji, Emoji, Id} ->
<<<<<<<<"<tg-emoji emoji-id=\""/utf8, (escape_html(Id))/binary>>/binary,
"\">"/utf8>>/binary,
(escape_html(Emoji))/binary>>/binary,
"</tg-emoji>"/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}).