LSP
LSP copied to clipboard
Add willRename and didRename fileOperations
closes #2199
Here is a example video:
https://github.com/sublimelsp/LSP/assets/22029477/441972ba-939c-40e0-899d-13629034a838
Notice the import changing in file a.ts when we rename the b.ts file.
I will highlight things implemented from the LSP spec.
Renaming a document
Document renames should be signaled to a server sending a document close notification with the document’s old name followed by an open notification using the document’s new name.
That part of the spec can be seen on these two lines:
- send didClose notification https://github.com/sublimelsp/LSP/blob/6f654623cbedfd7f4dada7269783861d68c5b344/plugin/rename_file.py#L106
- send didOpen notification https://github.com/sublimelsp/LSP/blob/6f654623cbedfd7f4dada7269783861d68c5b344/plugin/rename_file.py#L119-L120
[!NOTE] The user could rename
main.pytomain.ts. It is much easer to just close the view and open it, than to keep the file open and try modify the view to switch the syntax, language id, and a few more things... which I initially did, but concluded that requires more code, so I switched to just closing and opening the view.
WillRenameFiles Request
The will rename files request is sent from the client to the server before files are actually renamed as long as the rename is triggered from within the client either by a user action or by applying a workspace edit. The request can return a WorkspaceEdit which will be applied to the workspace before the files are renamed.
That can be seen here: https://github.com/sublimelsp/LSP/blob/6f654623cbedfd7f4dada7269783861d68c5b344/plugin/rename_file.py#L95-L98
Please note that clients might drop results if computing the edit took too long or if a server constantly fails on this request. This is done to keep renames fast and reliable.
I didn't implement this.
DidRenameFiles Notification
When a rename happened, all sessions who have the workspace.fileOperations.didRename capability will get notified.
Here is what to expect from this PR.
- There is a
LSP: Rename Filecommand in the command palette and ~LSP: Rename~LSP: Rename FileandLSP: Rename Folderin the sidebar. - Uses can rename file and folders. (folders can only be renamed from the sidebar).
- When remaining a file user can rename a file
example.pytohello.py, or to./hello.py, or to../../hello.pyor to./newDir/hello.pyor to./existingDir/hello.py. And it will work as expected. - The
LSP: Rename Fileis always enabled, even if a session(with a'workspace.fileOperations.willRename') doesn't exist. https://github.com/sublimelsp/LSP/blob/6f654623cbedfd7f4dada7269783861d68c5b344/plugin/rename_file.py#L41-L42
For session that don't support the 'workspace.fileOperations.willRename',
we will still rename the file and notify all sessions that have 'workspace.fileOperations.didRename'
The built-in rename_file and rename_path commands are both implemented in Python in Default/rename.py and Default/side_bar.py. I wonder wouldn't it be better to just replace these commands, like LSP already does with show_scope_name? Here we could add on_window_command in https://github.com/sublimelsp/LSP/blob/293f4a4340cca5ab1ad065643e4f20d9b270b2b1/boot.py#L209 to retarget the commands if a language server is running.
While for other features like document symbols or goto symbol, the similar built-in commands are not overridden because they can return different results as the LSP commands, so it might be useful to have both variants. But I think for the rename this is not necessary and to add two more LSP variants into the menus would not be optimal for usability. What do you think?
@jwortmann I tried to implement your suggestion on a different branch,
but I hit a bug with ST in which ST never emits a rename_file to on_window_command, although rename_file is a window command. It works fine for the rename_path command. My assumption is maybe because rename_file requires a TextInputHandler, but only ST core code can say whats missing.
You can see my attempt here
I will try a workaround https://github.com/sublimehq/sublime_text/issues/2234#issuecomment-411973845 EDIT: I can't apply the workaround, because the workaround needs to be added to Default/rename.py.
@jwortmann I liked the idea, that way we do not introducing new commands, instead relying on existing ones.
But because the on_window_command approach is buggy and needs a fix on ST side, I will quit from that idea now and stick with the approach in this PR.
I've subscribed to the ST issue, so once that is fixed I could rethink the approach.
Renaming a directory still shows LSP: Rename File in the command palette
Will this allow functionality like described in https://github.com/sublimelsp/LSP-intelephense/issues/112 that works in Vscode, where a symbol is mapped to a file name, so the file name would be automatically changed if the symbol is renamed?
I believe no, this PR would only work in the other direction, i.e. if you rename a file, then the corresponding class name would be updated in that file and in other files.
For the functionality from the linked issue, we need to add support for WorkspaceEditClientCapabilities.resourceOperations.
https://github.com/sublimelsp/LSP/blob/f98334571229215ffed9d7a02b8a9ccfd9d4093a/plugin/core/edit.py#L19-L22
@jwortmann thanks for that info.
Deploy Preview for sublime-lsp ready!
| Name | Link |
|---|---|
| Latest commit | 21f1bf7a10dc3bddc2f2a8c28fdde36f605fd666 |
| Latest deploy log | https://app.netlify.com/sites/sublime-lsp/deploys/66c4bad9a398f30008528d6a |
| Deploy Preview | https://deploy-preview-2498--sublime-lsp.netlify.app |
| Preview on mobile | Toggle QR Code...Use your smartphone camera to open QR code link. |
To edit notification comments on pull requests, go to your Netlify site configuration.
I've noticed that renaming unsaved file is a bit broken because it triggers a dialog to either save or not the changes but at this point the file is already renamed. Then pressing save tries to save the file to the old location and not saving changes leaves the old view open.
I suppose that's related to not using view.retarget API.
Another difference compared to native behavior is that if you try to rename a file that is not "fully open" (only previewed on right clicking in the sidebar) then native behavior will keep the renamed one in preview mode while LSP will open the file in non-preview mode.
That doesn't seem like much of an issue but there might be it might create some extra issues that I'm not seeing right now.
Rafal thanks for catching this.
Currently the code closes and opens the file after rename. That will cause the save popup to appear if the view has unsaved changes. Trying to not close the view requires more complex logic, in order to handle renaming hello.ts -> hello.py or something else.
🙈
Will this get implemented then? 😄
@predragnikolic is the last discussed issue something that you would consider the remaining blocker?
I no longer have clear recollection of the issues here but if something is not currently possible due to ST limitations then perhaps it would be good idea to make an upstream issue for what's missing.
Will this get implemented then? 😄
I'm not sure :)
@predragnikolic is the last discussed issue something that you would consider the remaining blocker?
Yes.
It is possible to implement this, there are no ST blockers.
I've noticed that renaming unsaved file is a bit broken because it triggers a dialog to either save or not the changes but at this point the file is already renamed.
The easy way to solve the issues you reported, would be to save the file before closing the view. https://github.com/sublimelsp/LSP/pull/2498/files#diff-06bad17710895021d007aba395accf463493660accc8165970646eb9dbde7e0fR101
I don't know if it is expected that a file gets saved before the rename.
I haven't test if that would work in all 3 cases. Lets say a user has 2 language servers set up. (for Python and TypeScript) A user can rename:
a.py->b.py- Python ls should be still active, after the rename.a.py->b.ts- Python should shut down, and TypeScript ls should start.a.py->b.some-extension-where-lsp-is-not-runningPython should shut down and no new LSP server should start.
The reason why I wanted to close and open the view is to avoid thinking if when to shutdown a LS and when to start a new one. I still think that is the easier way to do it, but I am not sure if it is the proper way to do it.
The easy way to solve the issues you reported, would be to save the file before closing the view.
Sounds like a reasonable requirement to me. It may be lifted later when dedicated logic is added, but for the first implementation I would be fine with this.
The view is saved before closing 0e0daa7
I did made some changes -> Introduce "LSP: Rename Path" and rename "LSP: Rename" to "LSP: Rename Symbol" to make things more explicit.