-
-
Notifications
You must be signed in to change notification settings - Fork 74
feat: add module rename support #284
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- engine: add CodeMod.Rename module for module renaming with file rename support - expert: add prepareRename and rename LSP handlers - forge: extend Document.Changes to support RenameFile operations
- Refactor test descriptions to be concise - Replace generic Foo/Bar/Baz with domain names (Users, Accounts, etc.) - Add tests for references, descendants, structs, edge cases, and file renaming
Without reindexing after a rename operation, the search index still contains old module names. This causes subsequent renames to fail - e.g., renaming `Dummy.Accounts` to `Dummy.Accounts2` works, but renaming back to `Dummy.Accounts` fails to update `Dummy.Accounts2.User` because the index doesn't know about the new module names. Add Commands.Rename GenServer to track file_changed/file_saved events and trigger reindexing once all rename operations complete.
…name After a file rename, the new file URI may not be open in Document.Store when reindexing is triggered. This caused "not_open" errors and the index was never updated, breaking references and go-to-definition for renamed modules. Add ensure_open/1 to temporarily open the file from disk if needed.
f08fd15 to
2879e00
Compare
dba3fa9 to
8d72473
Compare
…uring batch rename During batch renames, didClose and didSave notifications can arrive nearly simultaneously. If didClose is processed first, the file is removed from Document.Store, causing didSave to fail with :not_open error. This is a follow-up fix to 2879e00 which only addressed the reindex flow. Now didSave gracefully handles :not_open by still updating rename progress tracking, ensuring the rename operation completes successfully.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some notes(I'm testing on a brand new mix phx.new rename_test project:
-
If I am on module
RenameTestWeb.Routerand I rename it toExpertRenameTestWebthen- No other module prefixed with
RenameTestWebis renamed - The
use RenameTestWeb, :routerisn't renamed either
- No other module prefixed with
-
If I create
lib/rename_test/nested/foo.exdefiningRenameTest.Nested.Fooand I renameRenameTestinlib/rename_test.ex, then the child modules are renamed and the files are renamed too, but I end up with an emptylib/rename_test/nestedfolder -
When I try to rename a function(I know this is not supported by this PR, but still) I get this error:
2026-01-14 16:34:27.690 [info] [Error - 4:34:27 PM] ** (UndefinedFunctionError) function XPGenLSP.ErrorResponse.fetch/2 is undefined (XPGenLSP.ErrorResponse does not implement the Access behaviour
You can use the "struct.field" syntax to access struct fields. You can also use Access.key!/1 to access struct fields dynamically inside get_in/put_in/update_in)
(xp_gen_lsp 0.11.2) XPGenLSP.ErrorResponse.fetch(%XPGenLSP.ErrorResponse{message: "Failed to handle textDocument/prepareRename, {:error, :request_failed, \"Renaming :call is not supported for now\"}", code: -32603, data: nil}, :placeholder)
(elixir 1.17.2) lib/access.ex:322: Access.get/3
(xp_schematic 0.2.1) lib/schematic.ex:608: anonymous fn/5 in XPSchematic.map/1
(elixir 1.17.2) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
(xp_schematic 0.2.1) lib/schematic.ex:583: anonymous fn/3 in XPSchematic.map/1
(xp_schematic 0.2.1) lib/schematic.ex:1001: anonymous fn/4 in XPSchematic.telemetry_wrap/3
(xp_telemetry 1.3.0) /Users/dorgan/dev/expert/apps/expert/deps/telemetry/src/telemetry.erl:324: :xp_telemetry.span/3
(xp_schematic 0.2.1) lib/schematic.ex:947: anonymous fn/3 in XPSchematic.oneof/1Also we should have some progress reported, I'm testing on VSCode(it's easier for me to trigger these actions from this editor) and I don't see progress reported there, neither in the status bar nor in the Expert logs there
Context
While AI-assisted renaming is convenient, it's still slower than a native Language Server implementation. This PR ports the module rename feature from Lexical PR #636, which I've been using reliably for almost two years. Given that the Lexical repository is now archived, I wanted to bring this practical and well-tested feature to Expert.
Changes
Core Implementation (engine)
Engine.CodeMod.Renamemodule with submodules:Prepare,Module,Entry,File, andDiffEngine.Commands.RenameGenServer for tracking rename progress and triggering reindexEngine.Commands.RenameSupervisorfor managing rename command lifecycleLSP Integration (expert)
PrepareRenameandRenamehandlers for LSP protocolExpert.EngineApiwithprepare_rename/3andrename/5APIsrename_providerwithprepare_provider: truein server capabilitiesInfrastructure (forge)
RenameFilestruct toForge.Document.Changesfor file rename operationsfile_changedandfile_savedmessage types toForge.EngineApi.MessagesKey Differences from Lexical
:erpc.callviaExpert.EngineApi.call/4instead ofRemoteControl.callLexical.RemoteControl.*→Engine.*,Lexical.Server.*→Expert.*Why These Changes
Progress tracking & reindex (
59953157): Without reindexing after rename, the search index retains old module names. This causes subsequent renames to fail - e.g., renamingAccounts→Accounts2works, but renaming back fails because the index doesn't reflect the new names.Temporary document opening (
f08fd155): After a file rename, the new URI may not exist inDocument.Store, causing "not_open" errors during reindex. Addedensure_open/1to temporarily open files from disk when needed.Expanded test coverage (
a38652ef): Added comprehensive tests covering references, descendants, structs, edge cases, and file renaming with realistic module names.Extra
A demo video is attached showing the smooth rename workflow - renaming a module and then renaming it back. Tested successfully in both VSCode and Neovim.
CleanShot.2026-01-04.at.15.43.19.mp4