Skip to content

Commit 2973af6

Browse files
authored
Filter modules during collection in IEx autocomplete (#15143)
Instead of collecting all modules as strings, sorting the full list, and then linearly scanning for matching prefixes, filter modules during collection and only sort the (much smaller) set of matches. Benchmarked with 261 loaded modules, compared against the original code (before the previous two optimizations) and the current code: match_modules("Elixir.Enum"): before PR: 333 µs, 13.6 KB heap current: 91 µs, 1.6 KB heap proposed: 30 µs, 0.5 KB heap (11x faster, 26x less heap) match_modules("er"): before PR: 345 µs, 13.8 KB heap current: 97 µs, 2.9 KB heap proposed: 39 µs, 0.4 KB heap (9x faster, 33x less heap)
1 parent 47d72d9 commit 2973af6

1 file changed

Lines changed: 20 additions & 18 deletions

File tree

lib/iex/lib/iex/autocomplete.ex

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -609,31 +609,33 @@ defmodule IEx.Autocomplete do
609609
end
610610

611611
defp match_modules(hint, elixir_root?) do
612-
get_modules(elixir_root?)
613-
|> :lists.usort()
614-
|> Enum.drop_while(&(not String.starts_with?(&1, hint)))
615-
|> Enum.take_while(&String.starts_with?(&1, hint))
616-
end
612+
modules =
613+
for mod <- :erlang.loaded(),
614+
str = Atom.to_string(mod),
615+
String.starts_with?(str, hint),
616+
do: str
617617

618-
defp get_modules(true) do
619-
["Elixir.Elixir"] ++ get_modules(false)
620-
end
618+
modules =
619+
if elixir_root? and String.starts_with?("Elixir.Elixir", hint),
620+
do: ["Elixir.Elixir" | modules],
621+
else: modules
621622

622-
defp get_modules(false) do
623-
modules = Enum.map(:erlang.loaded(), &Atom.to_string/1)
623+
modules =
624+
case :code.get_mode() do
625+
:interactive -> modules ++ match_modules_from_applications(hint)
626+
_otherwise -> modules
627+
end
624628

625-
case :code.get_mode() do
626-
:interactive -> modules ++ get_modules_from_applications()
627-
_otherwise -> modules
628-
end
629+
:lists.usort(modules)
629630
end
630631

631-
defp get_modules_from_applications do
632+
defp match_modules_from_applications(hint) do
632633
for [app] <- loaded_applications(),
633634
{:ok, modules} = :application.get_key(app, :modules),
634-
module <- modules do
635-
Atom.to_string(module)
636-
end
635+
module <- modules,
636+
str = Atom.to_string(module),
637+
String.starts_with?(str, hint),
638+
do: str
637639
end
638640

639641
defp loaded_applications do

0 commit comments

Comments
 (0)