diff --git a/lib/iex/lib/iex/autocomplete.ex b/lib/iex/lib/iex/autocomplete.ex index 425fce13866..b48489dcde6 100644 --- a/lib/iex/lib/iex/autocomplete.ex +++ b/lib/iex/lib/iex/autocomplete.ex @@ -9,6 +9,7 @@ defmodule IEx.Autocomplete do defprotocol Entry do @moduledoc false def to_entries(entry) + def to_uniq_entries(entry) def to_hint(entry, hint) end @@ -19,6 +20,10 @@ defmodule IEx.Autocomplete do [mod.name] end + def to_uniq_entries(_fun) do + [] + end + def to_hint(Mod[name: name], hint) do :lists.nthtail(length(hint), name) ++ '.' end @@ -31,6 +36,10 @@ defmodule IEx.Autocomplete do lc a inlist fun.arities, do: '#{fun.name}/#{a}' end + def to_uniq_entries(fun) do + to_entries(fun) + end + def to_hint(Fun[name: name], hint) do :lists.nthtail(length(hint), name) end @@ -48,7 +57,7 @@ defmodule IEx.Autocomplete do expand_dot reduce(t) h === ?: -> expand_erlang_modules - (h in ?a..?z) or (h in ?A..?Z) or h === ?_ -> + (h in ?a..?z) or (h in ?A..?Z) or h in [?_, ??, ?!] -> expand_expr reduce(expr) h in '(+[' -> expand '' @@ -60,7 +69,7 @@ defmodule IEx.Autocomplete do defp expand_dot(expr) do case Code.string_to_ast expr do {:ok, atom} when is_atom(atom) -> - expand_module_funs atom + expand_call atom, '' {:ok, {:__aliases__,_,list}} -> expand_elixir_modules list _ -> @@ -73,7 +82,7 @@ defmodule IEx.Autocomplete do {:ok, atom} when is_atom(atom) -> expand_erlang_modules atom_to_list(atom) {:ok, { atom, _, nil }} when is_atom(atom) -> - expand_module_funs Kernel, atom_to_list(atom) + expand_call Kernel, atom_to_list(atom) {:ok, {:__aliases__,_,[root]}} -> expand_elixir_modules [], atom_to_list(root) {:ok, {:__aliases__,_,[h|_] = list}} when is_atom(h) -> @@ -109,7 +118,9 @@ defmodule IEx.Autocomplete do end defp format_expansion([uniq], hint) do - { :yes, Entry.to_hint(uniq, hint), [] } + hint = Entry.to_hint(uniq, hint) + uniq = if hint == '', do: Entry.to_uniq_entries(uniq), else: [] + { :yes, hint, uniq } end defp format_expansion([first|_]=entries, hint) do @@ -159,6 +170,10 @@ defmodule IEx.Autocomplete do no_match end + defp expand_module_funs(mod, hint) do + format_expansion module_funs(mod, hint), hint + end + ## Erlang modules defp expand_erlang_modules(hint // '') do @@ -208,11 +223,7 @@ defmodule IEx.Autocomplete do Enum.map(:code.all_loaded, fn({ m, _ }) -> atom_to_list(m) end) end - ## Functions - - defp expand_module_funs(mod, hint // '') do - format_expansion module_funs(mod, hint), hint - end + ## Helpers defp module_funs(mod, hint // '') do case ensure_loaded(mod) do @@ -234,8 +245,6 @@ defmodule IEx.Autocomplete do end end - ## Generic Helpers - defp get_funs(mod) do if function_exported?(mod, :__info__, 1) do if docs = mod.__info__(:docs) do diff --git a/lib/iex/test/iex/autocomplete_test.exs b/lib/iex/test/iex/autocomplete_test.exs index b421e8c92b3..69d9cd564c0 100644 --- a/lib/iex/test/iex/autocomplete_test.exs +++ b/lib/iex/test/iex/autocomplete_test.exs @@ -54,6 +54,10 @@ defmodule IEx.AutocompleteTest do assert expand('System.ve') == {:yes, 'rsion', []} end + test :elixir_function_completion_with_arity do + assert expand('Enum.all?') == {:yes, '', ['all?/2']} + end + test :elixir_macro_completion do {:yes, '', list} = expand('Kernel.is_') assert is_list(list)