diff --git a/lib/stdlib/src/edlin_expand.erl b/lib/stdlib/src/edlin_expand.erl index 70c41fe8d21..d13b5870ceb 100644 --- a/lib/stdlib/src/edlin_expand.erl +++ b/lib/stdlib/src/edlin_expand.erl @@ -941,48 +941,54 @@ get_exports(Mod) -> [] end end. - -expand_function_name(ModStr, FuncPrefix, CompleteChar, FT) -> +pp(String) when is_binary(String) -> + binary_to_list(string:titlecase(string:trim(String))); +pp(String) when is_list(String) -> + string:titlecase(string:trim(String)). +expand_name(ModStr, Type, Prefix, CompleteChar, FT) -> case to_atom(ModStr) of {ok, Mod} -> - Extra = case Mod of - shell_default -> [{Name, Arity}||{{function, {_, Name, Arity}}, _} <- FT]; - _ -> [] - end, - Exports = get_exports(Mod) ++ Extra, - {Res, Expansion, Matches}=Result = match(FuncPrefix, Exports, CompleteChar), - case Matches of - [] -> Result; - _ -> {Res, Expansion, [#{title=>"functions", elems=>Matches, options=>[highlight_all]}]} - end; - error -> - {no, [], []} - end. - -get_module_types(Mod) -> - case code:get_doc(Mod, #{sources => [debug_info]}) of - {ok, #docs_v1{ docs = Docs } } -> - [{T, A} || {{type, T, A},_Anno,_Sig,_Doc,_Meta} <- Docs]; - _ -> {no, [], []} - end. - -expand_type_name(ModStr, TypePrefix, CompleteChar) -> - case to_atom(ModStr) of - {ok, Mod} -> - case get_module_types(Mod) of - {no, [], []} -> - {no, [], []}; - Types -> - {Res, Expansion, Matches}=Result = match(TypePrefix, Types, CompleteChar), + case Mod =:= shell_default of + true -> ShellDefaultStr = pp("shell defined "++atom_to_list(Type)++"s"), + Groups = #{ShellDefaultStr=>[{Name, Arity}||{{Type1, {_, Name, Arity}}, _} <- FT, Type1 =:= Type]}; + false -> + TypeStr = pp(atom_to_list(Type)++"s"), + case code:get_doc(Mod) of + {ok, #docs_v1{ docs = Docs } } -> + case Type of + function -> + Exports = get_exports(Mod), + Grouped = [{pp(G),{Name,Arity}} || {{Type1,Name,Arity},_,_,_,#{group := G}}<-Docs, Type1 =:= Type, lists:member({Name,Arity},Exports)], + Ungrouped = [{TypeStr,{Name,Arity}} || {{Type1,Name,Arity},_,_,_,MD}<-Docs, Type1 =:= Type, maps:is_key(group, MD) =:= false, lists:member({Name,Arity},Exports)]; + type -> + Grouped = [{pp(G),{Name,Arity}} || {{Type1,Name,Arity},_,_,_,#{exported := true, group := G}}<-Docs, Type1 =:= Type, lists ], + Ungrouped = [{TypeStr,{Name,Arity}} || {{Type1,Name,Arity},_,_,_,#{exported := true}=MD}<-Docs, Type1 =:= Type, maps:is_key(group, MD) =:= false] + end, + Groups = maps:groups_from_list(fun (T)->element(1,T) end, + fun(T)->element(2,T) end, + Grouped ++ Ungrouped); + _ when Type =:= function -> + Groups = #{TypeStr => get_exports(Mod)}; + _ -> %% No docs? + Groups = #{} + end + end, + fold_results( + [begin + {Res, Expansion, Matches}=Result = match(Prefix, maps:get(Title, Groups), CompleteChar), case Matches of [] -> Result; - _ -> {Res, Expansion, [#{title=>"types", elems=>Matches, options=>[highlight_all]}]} + _ -> + {Res, Expansion, [#{title=>Title, elems=>Matches, options=>[highlight_all]}]} end - end; + end || Title <- maps:keys(Groups)]); error -> {no, [], []} end. - +expand_function_name(ModStr, FuncPrefix, CompleteChar, FT) -> + expand_name(ModStr, function, FuncPrefix, CompleteChar, FT). +expand_type_name(ModStr, TypePrefix, CompleteChar) -> + expand_name(ModStr, type, TypePrefix, CompleteChar, []). to_atom(Str) -> case erl_scan:string(Str) of {ok, [{atom,_,A}], _} -> diff --git a/lib/stdlib/test/edlin_expand_SUITE.erl b/lib/stdlib/test/edlin_expand_SUITE.erl index 15abaaa7f07..52074500043 100644 --- a/lib/stdlib/test/edlin_expand_SUITE.erl +++ b/lib/stdlib/test/edlin_expand_SUITE.erl @@ -85,16 +85,17 @@ normal(Config) when is_list(Config) -> {yes,"test:",[]} = do_expand("expand_"), {no, [], []} = do_expand("expandXX_"), {no,[],[#{ - title:="functions", + title:="Functions", elems:=[{"a_fun_name",[{ending,"("}]}, {"a_less_fun_name",_}, {"b_comes_after_a",_}, {"expand0arity_entirely",_}, {"module_info",_}] }]} = do_expand("expand_test:"), - {yes,[],[#{title:="functions", + {yes,[],[#{title:="Functions", elems:=[{"a_fun_name",_},{"a_less_fun_name",_}]}]} = do_expand("expand_test:a_"), {yes,"arity_entirely()",[]} = do_expand("expand_test:expand0"), + {no, [], [#{title:="Functions"}, #{title:="Obsolete API functions"}]} = do_expand("string:"), ok. to_atom(Str) -> @@ -524,7 +525,7 @@ get_coverage(Config) -> lists:flatten(edlin_expand:format_matches(M10, 20)), %% Test that we are not filtering duplicates bit with different case or different string lengths {yes,"e", M11} = do_expand("complete_function_parameter:cas"), - "\e[;1;4mfunctions\e[0m\ncaseSensitiveFunction( casesensitivefunction( \ncaseSensitiveFunctionName(\n" = do_format(M11), + "\e[;1;4mFunctions\e[0m\ncaseSensitiveFunction( casesensitivefunction( \ncaseSensitiveFunctionName(\n" = do_format(M11), ok. %% Normal module name, some function names using quoted atoms. @@ -534,7 +535,7 @@ quoted_fun(Config) when is_list(Config) -> %% should be no colon after test this time {yes, "test", [#{title:="modules", elems:=[{"expand_test",[{ending, ":"}]},{"expand_test1",_}]}]} = do_expand("expand_"), {no, [], []} = do_expand("expandXX_"), - {no,[],[#{title:="functions", + {no,[],[#{title:="Functions", elems:=[{"'#weird-fun-name'",_}, {"'Quoted_fun_name'",_}, {"'Quoted_fun_too'",_}, @@ -567,7 +568,7 @@ quoted_module(Config) when is_list(Config) -> {"a_less_fun_name",_}, {"b_comes_after_a",_}, {"module_info",_}]}]} = do_expand("'ExpandTestCaps':"), - {yes,[],[#{title:="functions", elems:=[{"a_fun_name",_}, + {yes,[],[#{title:="Functions", elems:=[{"a_fun_name",_}, {"a_less_fun_name",_}]}]} = do_expand("'ExpandTestCaps':a_"), ok.