-module(mls).
-export([text/1, text/2]).
text(T) when is_list(T) ->
text([], T).
%% Erlang multi-line strings like support
%% based on the ideas from Elixir multi-line strings
%%
%% example:
%%
%% > text(list,
%% > "
%% > {
%% > 'a': 1,
%% > 'b': 2
%% > }
%% > ").
%% "{\n \"a\": 1,\n \"b\": 2\n}\n"
%%
%% OR
%% > text(list,
%% > """
%% > {
%% > 'a': 1,
%% > 'b': 2
%% > }
%% > """).
%% "{\n \"a\": 1,\n \"b\": 2\n}\n"
text(Options, T) when is_list(T) ->
{Type, Is_flat, Is_escaped} = parse_options(Options),
text_parse(Type, Is_flat, Is_escaped, T).
% Thpe, Is_flat, Is_escaped
text_parse(list, false, false, T) ->
text(list, false, false, T);
text_parse(list, false, true, T) ->
text(list, false, true, T);
text_parse(list, true, false, T) ->
%% remove the end of line space
re:replace(text(list, true, false, T), "\\s$", "", [{return,list}]);
text_parse(list, true, true, T) ->
%% remove the end of line space
re:replace(text(list, true, true, T), "\\s$", "", [{return,list}]);
text_parse(binary, false, false, T) when is_list(T) ->
list_to_binary(text(list, false, false, T));
text_parse(binary, false, true, T) when is_list(T) ->
list_to_binary(text(list, false, true, T));
text_parse(binary, true, false, T) when is_list(T) ->
list_to_binary(text(list, true, false, T));
text_parse(binary, true, true, T) when is_list(T) ->
list_to_binary(text(list, true, true, T)).
%% specify End_line: "\n" or " "
text(list, Is_flat, Is_escaped, T) when is_list(T) ->
%% split the lines
%% [[]," {"," 'a': 1,"," 'b': 2"," }"," "]
[Head|Lines] = re:split(T, "\n", [{return, list}]),
case Head of
[] -> %% after " there is a new line then skip the first element
%% Lines = [" {"," 'a': 1,"," 'b': 2"," }"," "]
%% reverse
%% [" "," }"," 'b': 2"," 'a': 1,"," {"]
Reversed_lines = lists:reverse(Lines),
%% get the Last line ... now the first in the list after reverse to count the
%% empty spaces and to strip them from the rest of the lines
[Last|Rest] = Reversed_lines,
Strip_length = length(Last),
%% skip the empty line and strip the first characters from the other lines
%% ["}"," \"b\": 2"," \"a\": 1,","{"]
Strip_list = lists:map(fun(S) -> string:slice(S,Strip_length) end, Rest),
Strip_list2 = case Is_flat of
false ->
%% fold and add new line (end of line character)
%% "{\n \"a\": 1,\n \"b\": 2\n}\n"
lists:foldl(fun(S, AccIn) ->
string:concat(string:concat(S, "\n"), AccIn)
end,
"", Strip_list);
true ->
lists:foldl(fun(S, AccIn) ->
string:concat(
string:concat(
re:replace(S, "^\\s+", "", [{return, list}]), " "),
AccIn)
end,
"", Strip_list)
end,
case Is_escaped of
true ->
%% replace \ with \\
Replace_1 = re:replace(Strip_list2, "\\'", "\\\"", [{return,list}, global]),
%% replace ' with \"
re:replace(Replace_1, "'", "\\\"", [{return,list}, global]);
false ->
Strip_list2
end
end.
%% parse the options
%% options can be one or more of binary | list, flat, escaped
%% [binary]
%% [binary, flat, escaped]
%%
parse_options(Options) when is_list(Options) ->
Is_binary = lists:member(binary, Options),
Is_list = lists:member(list, Options),
Is_flat = lists:member(flat, Options),
Is_escaped = lists:member(escaped, Options),
case {Is_binary, Is_list, Is_flat, Is_escaped} of
{true, _, _, _} -> {binary, Is_flat, Is_escaped}; %% if binary set, ignore list option
{false, true, _, _} -> {list, Is_flat, Is_escaped};
{false, false, _, _} -> {binary, Is_flat, Is_escaped} %% default binary if nothing set
end.