summaryrefslogtreecommitdiff
path: root/src/ejabberd_config.erl
diff options
context:
space:
mode:
authorEvgeny Khramtsov <ekhramtsov@process-one.net>2019-04-29 20:57:59 +0300
committerEvgeny Khramtsov <ekhramtsov@process-one.net>2019-04-29 20:57:59 +0300
commit39bbc7cad862a71b4da9f02b86f8af6f1be55c4a (patch)
treecfa01419e3ba719ad3468d81af1720734048f41e /src/ejabberd_config.erl
parentDisable offline_from_mam tests on riak since it doesn't support mam (diff)
Provide a suggestion when unknown option is detected
Diffstat (limited to 'src/ejabberd_config.erl')
-rw-r--r--src/ejabberd_config.erl35
1 files changed, 33 insertions, 2 deletions
diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl
index b9b0f8ee..00120fcb 100644
--- a/src/ejabberd_config.erl
+++ b/src/ejabberd_config.erl
@@ -38,7 +38,8 @@
default_db/1, default_db/2, default_ram_db/1, default_ram_db/2,
default_queue_type/1, queue_dir/0, fsm_limit_opts/1,
use_cache/1, cache_size/1, cache_missed/1, cache_life_time/1,
- codec_options/1, get_plain_terms_file/2, negotiation_timeout/0]).
+ codec_options/1, get_plain_terms_file/2, negotiation_timeout/0,
+ similar_option/2]).
-export([start/2]).
@@ -1099,7 +1100,9 @@ validate_opts(#state{opts = Opts} = State, ModOpts) ->
erlang:error(invalid_option)
end;
_ ->
- ?ERROR_MSG("Unknown option '~s'", [Opt]),
+ KnownOpts = dict:fetch_keys(ModOpts),
+ ?ERROR_MSG("Unknown option '~s', did you mean '~s'?",
+ [Opt, similar_option(Opt, KnownOpts)]),
erlang:error(unknown_option)
end
end, Opts),
@@ -1123,6 +1126,34 @@ is_file_readable(Path) ->
false
end.
+-spec similar_option(atom(), [atom()]) -> atom().
+similar_option(Pattern, [_|_] = Opts) ->
+ String = atom_to_list(Pattern),
+ {Ds, _} = lists:mapfoldl(
+ fun(Opt, Cache) ->
+ {Distance, Cache1} = ld(String, atom_to_list(Opt), Cache),
+ {{Distance, Opt}, Cache1}
+ end, #{}, Opts),
+ element(2, lists:min(Ds)).
+
+%% Levenshtein distance
+-spec ld(string(), string(), map()) -> {non_neg_integer(), map()}.
+ld([] = S, T, Cache) ->
+ {length(T), maps:put({S, T}, length(T), Cache)};
+ld(S, [] = T, Cache) ->
+ {length(S), maps:put({S, T}, length(S), Cache)};
+ld([X|S], [X|T], Cache) ->
+ ld(S, T, Cache);
+ld([_|ST] = S, [_|TT] = T, Cache) ->
+ try {maps:get({S, T}, Cache), Cache}
+ catch _:{badkey, _} ->
+ {L1, C1} = ld(S, TT, Cache),
+ {L2, C2} = ld(ST, T, C1),
+ {L3, C3} = ld(ST, TT, C2),
+ L = 1 + lists:min([L1, L2, L3]),
+ {L, maps:put({S, T}, L, C3)}
+ end.
+
get_version() ->
case application:get_env(ejabberd, custom_vsn) of
{ok, Vsn0} when is_list(Vsn0) ->