Skip to content

Commit 8797261

Browse files
committed
New features and fixes:
* Added a new mechanism for truncating text using fractions * Bugfixes * Code improvements
1 parent 359cd0a commit 8797261

File tree

2 files changed

+95
-19
lines changed

2 files changed

+95
-19
lines changed

src/irc_messages/irc_make.erl

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -130,19 +130,30 @@ notice_max_size(Id, Msgtarget) ->
130130
%% Command: NOTICE
131131
%% Parameters: <msgtarget> <text to be sent>
132132

133-
notice(Id, Recv, Text) -> notice(Id, Recv, Text, {truncate, ?DEFAULT_TRUNC}).
133+
notice(Id, Recv, Text) -> notice(Id, Recv, Text, #{mode => truncate}).
134134

135135

136-
notice(Id, Recv, Text, {truncate, Ellipsis}) ->
137-
MaxSize = notice_max_size(Id, Recv),
138-
TruncText = irc_text:truncate(clean_up(Text), MaxSize, Ellipsis),
139-
{message, #{command => privmsg,
136+
notice(Id, Recv, Text, #{mode := truncate} = Opts) ->
137+
Ellipsis = maps:get(ellipsis, Opts, ?DEFAULT_TRUNC),
138+
Max = notice_max_size(Id, Recv),
139+
Out = irc_text:truncate(clean_up(Text), Max, Ellipsis),
140+
{message, #{command => notice,
141+
receiver => Recv,
142+
message => irc_command:notice(Recv, Out)}};
143+
144+
notice(Id, Recv, Texts, #{mode := fractional} = Opts) ->
145+
Ellipsis = maps:get(ellipsis, Opts, ?DEFAULT_TRUNC),
146+
Max = notice_max_size(Id, Recv),
147+
Ts = [{F, clean_up(T)} || {F, T} <- Texts],
148+
Out = irc_text:fractional_truncate(Ts, Max, Ellipsis),
149+
{message, #{command => notice,
140150
receiver => Recv,
141-
message => irc_command:notice(Recv, TruncText)}};
151+
message => irc_command:notice(Recv, Out)}};
152+
142153
notice(Id, Recv, Text, divide) ->
143154
MaxSize = notice_max_size(Id, Recv),
144155
TextList = irc_text:divide(clean_up(Text), MaxSize),
145-
F = fun (X) -> {message, #{command => privmsg,
156+
F = fun (X) -> {message, #{command => notice,
146157
receiver => Recv,
147158
message => irc_command:notice(Recv, X)}}
148159
end,
@@ -178,18 +189,29 @@ privmsg_max_size(Id, Msgtarget) ->
178189
%% Command: PRIVMSG
179190
%% Parameters: <msgtarget> <text to be sent>
180191

181-
privmsg(Id, Recv, Text) -> privmsg(Id, Recv, Text, {truncate, ?DEFAULT_TRUNC}).
192+
privmsg(Id, Recv, Text) -> privmsg(Id, Recv, Text, #{mode => truncate}).
182193

183194

184-
privmsg(Id, Recv, Text, {truncate, Ellipsis}) ->
185-
MaxSize = privmsg_max_size(Id, Recv),
186-
TruncText = irc_text:truncate(clean_up(Text), MaxSize, Ellipsis),
195+
privmsg(Id, Recv, Text, #{mode := truncate} = Opts) ->
196+
Ellipsis = maps:get(ellipsis, Opts, ?DEFAULT_TRUNC),
197+
Max = privmsg_max_size(Id, Recv),
198+
Out = irc_text:truncate(clean_up(Text), Max, Ellipsis),
187199
{message, #{command => privmsg,
188200
receiver => Recv,
189-
message => irc_command:privmsg(Recv, TruncText)}};
190-
privmsg(Id, Recv, Text, divide) ->
191-
MaxSize = privmsg_max_size(Id, Recv),
192-
TextList = irc_text:divide(clean_up(Text), MaxSize),
201+
message => irc_command:privmsg(Recv, Out)}};
202+
203+
privmsg(Id, Recv, Texts, #{mode := fractional} = Opts) ->
204+
Ellipsis = maps:get(ellipsis, Opts, ?DEFAULT_TRUNC),
205+
Max = privmsg_max_size(Id, Recv),
206+
Ts = [{F, clean_up(T)} || {F, T} <- Texts],
207+
Out = irc_text:fractional_truncate(Ts, Max, Ellipsis),
208+
{message, #{command => privmsg,
209+
receiver => Recv,
210+
message => irc_command:privmsg(Recv, Out)}};
211+
212+
privmsg(Id, Recv, Text, #{mode := divide}) ->
213+
Max = privmsg_max_size(Id, Recv),
214+
TextList = irc_text:divide(clean_up(Text), Max),
193215
F = fun (X) -> {message, #{command => privmsg,
194216
receiver => Recv,
195217
message => irc_command:privmsg(Recv, X)}}
@@ -198,8 +220,8 @@ privmsg(Id, Recv, Text, divide) ->
198220

199221

200222
ctcp_action(Id, Target, Text) ->
201-
MaxSize = privmsg_max_size(Id, Target) - 9,
202-
TruncText = irc_text:truncate(clean_up(Text), MaxSize, ?DEFAULT_TRUNC),
223+
Max = privmsg_max_size(Id, Target) - 9,
224+
Out = irc_text:truncate(clean_up(Text), Max, ?DEFAULT_TRUNC),
203225
{message, #{command => privmsg,
204226
receiver => Target,
205-
message => irc_command:ctcp_action(Target, TruncText)}}.
227+
message => irc_command:ctcp_action(Target, Out)}}.

src/lib/irc_text.erl

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
-module(irc_text).
22

33

4-
-export([divide/2, truncate/2, truncate/3]).
4+
-export([divide/2,
5+
truncate/2, truncate/3,
6+
fractional_truncate/2, fractional_truncate/3]).
57

68

79
divide(Text, Limit) -> divide(string:to_graphemes(Text), Limit, 0, [], []).
@@ -43,3 +45,55 @@ truncate(Text, Limit, Ellipsis, Size, Acc) ->
4345
{error, _} ->
4446
lists:reverse([[Ellipsis] | Acc])
4547
end.
48+
49+
50+
%%--------------------------------------------------------------------
51+
%% Fractionally truncate a list of strings.
52+
%%
53+
%% The caller assigns to each string a fraction. This fraction describes how
54+
%% much of the final output each string will take.
55+
%%
56+
%% Assigning 1 instead of a fraction means that the string should not be
57+
%% truncated. In that case the whole string will be used and its byte size will
58+
%% be subtracted from the Limit available to fractional texts.
59+
%%
60+
%% Each string from the list is truncated so that it doesn't use more than
61+
%% (Fraction * Limit) bytes. All the fractions should add up to 1.
62+
%%
63+
%% @param Texts A list of tuples in the following format: [{0.0..1.0, iodata()}]
64+
%%
65+
%% Example: [{1, "Text 1"},
66+
%% {2/3, "Text 2"},
67+
%% {1/3, "Text 3"}]
68+
%%
69+
%% @param Limit The maximum number of bytes allowed in the result.
70+
%% @param Ellipsis A string to append to any truncated text.
71+
%% @returns A single text string that can fit within the given Limit.
72+
%%--------------------------------------------------------------------
73+
74+
-spec fractional_truncate(Texts :: [{number(), iodata()}],
75+
Limit :: integer())
76+
-> iodata().
77+
78+
fractional_truncate(Texts, Limit) -> fractional_truncate(Texts, Limit, <<>>).
79+
80+
81+
-spec fractional_truncate(Texts :: [{number(), iodata()}],
82+
Limit :: integer(),
83+
Ellipsis :: iodata())
84+
-> iodata().
85+
86+
fractional_truncate(Texts, Limit, Ellipsis) ->
87+
Ones = unicode:characters_to_binary([T || {F, T} <- Texts, F =:= 1]),
88+
Avail = Limit - byte_size(Ones),
89+
90+
F = fun ({1, T}, Acc) ->
91+
[T | Acc];
92+
({F, T}, Acc) ->
93+
Max = case floor(Avail * F) of
94+
Size when Size =< Avail -> Size;
95+
_Else -> Avail
96+
end,
97+
[truncate(T, Max, Ellipsis) | Acc]
98+
end,
99+
lists:reverse(lists:foldl(F, [], Texts)).

0 commit comments

Comments
 (0)