Skip to content

Commit ee75709

Browse files
dkukuclaude
andcommitted
Filter modules during collection in IEx autocomplete
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) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent ae79f84 commit ee75709

1 file changed

Lines changed: 25 additions & 19 deletions

File tree

lib/iex/lib/iex/autocomplete.ex

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -609,31 +609,37 @@ 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
617-
618-
defp get_modules(true) do
619-
["Elixir.Elixir"] ++ get_modules(false)
620-
end
612+
modules =
613+
if elixir_root? do
614+
acc = for mod <- :erlang.loaded(),
615+
str = Atom.to_string(mod),
616+
String.starts_with?(str, hint),
617+
do: str
618+
619+
if String.starts_with?("Elixir.Elixir", hint), do: ["Elixir.Elixir" | acc], else: acc
620+
else
621+
for mod <- :erlang.loaded(),
622+
str = Atom.to_string(mod),
623+
String.starts_with?(str, hint),
624+
do: str
625+
end
621626

622-
defp get_modules(false) do
623-
modules = Enum.map(:erlang.loaded(), &Atom.to_string/1)
627+
modules =
628+
case :code.get_mode() do
629+
:interactive -> modules ++ match_modules_from_applications(hint)
630+
_otherwise -> modules
631+
end
624632

625-
case :code.get_mode() do
626-
:interactive -> modules ++ get_modules_from_applications()
627-
_otherwise -> modules
628-
end
633+
:lists.usort(modules)
629634
end
630635

631-
defp get_modules_from_applications do
636+
defp match_modules_from_applications(hint) do
632637
for [app] <- loaded_applications(),
633638
{:ok, modules} = :application.get_key(app, :modules),
634-
module <- modules do
635-
Atom.to_string(module)
636-
end
639+
module <- modules,
640+
str = Atom.to_string(module),
641+
String.starts_with?(str, hint),
642+
do: str
637643
end
638644

639645
defp loaded_applications do

0 commit comments

Comments
 (0)