Current section

Files

Jump to
grisp_tools src grisp_tools_io.erl
Raw

src/grisp_tools_io.erl

-module(grisp_tools_io).
-export([
ask/3,
ask/4,
ask/5
]).
%--- API -----------------------------------------------------------------------
ask(State, Prompt, Type) ->
ask_convert(State, Prompt, fun get/2, Type, none, "").
ask(State, Prompt, Type, Default) ->
ask_convert(State, Prompt, fun get/2, Type, Default, "").
ask(State, Prompt, Type, Default, Hint) ->
ask_convert(State, Prompt, fun get/2, Type, Default, Hint).
%--- Internal ------------------------------------------------------------------
ask_convert(State0, Prompt, TransFun, Type, Default, Hint) ->
DefaultPrompt = erlang:iolist_to_binary(
["\n", hint(Hint), Prompt, default(Default), "> "]
),
NewPrompt = erlang:binary_to_list(DefaultPrompt),
Event = {ask, NewPrompt},
{RawUserInput, State1} = grisp_tools_util:event_with_result(State0, Event),
Data = trim(trim(RawUserInput), both, [$\n]),
case TransFun(Type, Data) of
no_data ->
maybe_continue(State1, Prompt, TransFun, Type, Default, Hint);
no_clue ->
continue(State1, Prompt, TransFun, Type, Default, Hint);
Ret ->
Ret
end.
maybe_continue(State, Prompt, TransFun, Type, Default, Hint) ->
case Default of
none ->
continue(State, Prompt, TransFun, Type, Default, Hint);
_ ->
TransFun(Type, Default)
end.
continue(State, Prompt, TransFun, Type, Default, Hint) ->
Text = io_lib:format("Wrong input type. A ~p is expected", [Type]),
say(State, color(208, Text)),
ask_convert(State, Prompt, TransFun, Type, Default, Hint).
default(none) ->
[];
default(false) ->
color(51, " (y/N)");
default(true) ->
color(51, " (Y/n)");
default(Default) when is_list(Default) ->
DefaultText = io_lib:format(" (default: ~s)", [Default]),
color(51, DefaultText);
default(Default) ->
color(51, io_lib:format("(~s)", [Default])).
hint("") ->
"";
hint(Hint) ->
[color(242, "# " ++ Hint), "\n"].
get(boolean, []) ->
no_data;
get(boolean, [In | _]) when In =:= $Y orelse In =:= $y ->
true;
get(boolean, [In | _]) when In =:= $N orelse In =:= $n ->
false;
get(boolean, true) ->
true;
get(boolean, false) ->
false;
get(boolean, _) ->
no_clue;
get(integer, []) ->
no_data;
get(number, String) ->
get(integer, String);
get(integer, String) ->
case (catch list_to_integer(String)) of
{'Exit', _} ->
no_clue;
Integer ->
Integer
end;
get(latin1, []) ->
no_data;
get(latin1, Data) ->
case io_lib:latin1_char_list(Data) of
true ->
Data;
false ->
no_clue
end;
get(trim_string, []) ->
no_data;
get(trim_string, String) ->
case is_list(String) of
true ->
Whitespace = unicode_util:whitespace(),
Trimmed = string:trim(String, both, Whitespace ++ [$"]),
unicode:characters_to_binary(Trimmed);
false ->
no_clue
end;
get(string, []) ->
no_data;
get(string, String) ->
case is_list(String) of
true ->
unicode:characters_to_binary(String);
false ->
no_clue
end.
-ifdef(unicode_str).
trim(Str, right, Chars) -> string:trim(Str, trailing, Chars);
trim(Str, left, Chars) -> string:trim(Str, leading, Chars);
trim(Str, both, Chars) -> string:trim(Str, both, Chars).
-else.
trim(Str) -> string:strip(rebar_utils:to_list(Str)).
trim(Str, Dir, [Chars|_]) -> string:strip(rebar_utils:to_list(Str), Dir, Chars).
-endif.
say(State, Say) ->
Event = {say, Say},
grisp_tools_util:event(State, Event).
% @doc Add foreground coloring to the given text using ANSI ecape code
% See: https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit
% @end
-spec color(Code, Text) -> string() when
Code :: 0..255,
Text :: string().
color(Code, Text) ->
io_lib:format("\033[38;5;~pm~s\033[m", [Code, Text]).