Skip to content

Commit 36d004a

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 7d3863f commit 36d004a

1 file changed

Lines changed: 26 additions & 19 deletions

File tree

lib/iex/lib/iex/autocomplete.ex

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -609,31 +609,38 @@ 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 =
615+
for mod <- :erlang.loaded(),
616+
str = Atom.to_string(mod),
617+
String.starts_with?(str, hint),
618+
do: str
619+
620+
if String.starts_with?("Elixir.Elixir", hint), do: ["Elixir.Elixir" | acc], else: acc
621+
else
622+
for mod <- :erlang.loaded(),
623+
str = Atom.to_string(mod),
624+
String.starts_with?(str, hint),
625+
do: str
626+
end
621627

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

625-
case :code.get_mode() do
626-
:interactive -> modules ++ get_modules_from_applications()
627-
_otherwise -> modules
628-
end
634+
:lists.usort(modules)
629635
end
630636

631-
defp get_modules_from_applications do
637+
defp match_modules_from_applications(hint) do
632638
for [app] <- loaded_applications(),
633639
{:ok, modules} = :application.get_key(app, :modules),
634-
module <- modules do
635-
Atom.to_string(module)
636-
end
640+
module <- modules,
641+
str = Atom.to_string(module),
642+
String.starts_with?(str, hint),
643+
do: str
637644
end
638645

639646
defp loaded_applications do

0 commit comments

Comments
 (0)