Recommended workflow for "rename symbol" across an Elixir repository?

I’d like to:

  1. rename functions (do_thing() → do_other_thing())
  2. rename modules (MyModule → MyOtherModule)
  3. rename variables (var1 → var2)
  4. rename namespaces of modules (CoolModules.MyModule → BoringModules.MyModule)

among other things…

Will ElixirLS ever support this (VSCode use case)?

Are there any recommended tools I can use?

Do I have to resign myself to Find/Replace (I use VSCode)?

What are folks doing here? The lack of tooling makes refactoring difficult. Maybe there’s a tool I missed :slight_smile:

I haven’t used the LSP tools myself, but can you expound further on the specific problems you’re encountering?

The specific chores you mentioned all seem relatively straightforward because of Elixir’s scoping rules (vs a more-dynamic language like Ruby):

  • functions called locally (foo(x,y,z) vs SomeModule.foo(x,y,z)) can only be in the current file, unless you’re doing an explicit import SomeModule
  • modules are usually either named explicitly or aliased, but as: for aliases is generally discouraged
  • variables are local to a single function, so pain when renaming them likely indicates your functions are much too large
  • namespaces are likely the trickiest and involve touching the most files, but still they’re either explicitly named or aliased
2 Likes

When I’m coding Python, I have a shortcut setup CapsLock+r, which allows me to rename the symbol under my cursor. It’s a huge time saver when I’ve named something imprecisely.

Having the same for Elixir would be fantastic, but unfortunately ElixirLS isn’t there yet.

It’s one of those things you really miss when you’ve experienced it once and then don’t have access to it. Sure, I could use find/replace, but at least with a refactor tool I can be more confident I didn’t miss anything.

With things such as modules this is not really possible with strong guarrantees. Module names in elixir are just atoms. I could do the following:

my_module = fetch_module_name_from_db()

# As long as this is an atom, you can try to call functions from it
my_module.test_function()

This kind of pattern is widely used in declarative programming and since the actual values are only determined at runtime, there is no way any LSP or other refactoring tooling can determine how to refactor module/function names at project-level.

This dynamic nature opens a lot of possibilities, but at the same time makes creation of tooling around it extremely difficult or impossible.

1 Like

I haven’t tried it yet but igniter has a mix igniter.refactor.rename_function tasks that renames functions:

2 Likes