-
Notifications
You must be signed in to change notification settings - Fork 187
Add willRename and didRename fileOperations #2498
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?
Changes from 6 commits
f5ec6c5
e26a48e
e6304c2
e5e0722
5c91301
075e50e
814b0bb
fb42ffc
d488b06
d1a10cf
08e3af1
6f65462
c9e8772
e0c9c82
a52b5c4
2acceb6
9ab9dc5
f5c26a6
437659f
3647f92
3389f66
4785d49
2f5af31
890667c
af04c56
178adae
8ef443c
d1342b9
057eaff
cb82086
728c6ea
93b024a
1ff4648
1ae7ec4
6181644
181f17c
18e8549
51962f1
21f1bf7
814cb6b
0e0daa7
51670f9
f530756
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| [ | ||
| { | ||
| "caption": "Lsp: Rename", | ||
predragnikolic marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| "mnemonic": "l", | ||
| "command": "lsp_rename_file", | ||
| "args": {"paths": []} | ||
| } | ||
| ] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| from __future__ import annotations | ||
| from .core.open import open_file_uri | ||
| from .core.protocol import Notification, RenameFilesParams, Request, WorkspaceEdit | ||
| from .core.registry import LspWindowCommand | ||
| from pathlib import Path | ||
| from urllib.parse import urljoin | ||
| import os | ||
| import sublime | ||
| import sublime_plugin | ||
|
|
||
|
|
||
| class RenameFileInputHandler(sublime_plugin.TextInputHandler): | ||
| def want_event(self) -> bool: | ||
| return False | ||
|
|
||
| def __init__(self, file_name: str) -> None: | ||
| self.file_name = file_name | ||
|
|
||
| def name(self) -> str: | ||
| return "new_name" | ||
|
|
||
| def placeholder(self) -> str: | ||
| return self.file_name | ||
|
|
||
| def initial_text(self) -> str: | ||
| return self.placeholder() | ||
|
|
||
| def validate(self, name: str) -> bool: | ||
| return len(name) > 0 | ||
|
|
||
|
|
||
| class LspRenameFileCommand(LspWindowCommand): | ||
| capability = 'workspace.fileOperations.willRename' | ||
|
|
||
| def is_enabled(self): | ||
| return True | ||
|
|
||
| def want_event(self) -> bool: | ||
| return False | ||
|
|
||
| def input(self, args: dict) -> sublime_plugin.TextInputHandler | None: | ||
| if "new_name" in args: | ||
| return None | ||
| old_path = self.get_old_path(args.get('paths'), self.window.active_view()) | ||
| return RenameFileInputHandler(Path(old_path).name) | ||
|
|
||
| def run( | ||
| self, | ||
| new_name: str, # new_name can be: FILE_NAME.xy OR ./FILE_NAME.xy OR ../../FILE_NAME.xy | ||
| paths: list[str] | None = None, # exist when invoked from the sidebar with "LSP: Rename" | ||
predragnikolic marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ) -> None: | ||
| session = self.session() | ||
| old_path = self.get_old_path(paths, self.window.active_view()) | ||
| new_path = os.path.normpath(Path(old_path).parent / new_name) | ||
| if os.path.exists(new_path): | ||
| self.window.status_message('Unable to Rename. Already exists') | ||
| return | ||
| rename_file_params: RenameFilesParams = { | ||
| "files": [{ | ||
| "newUri": urljoin("file:", new_path), | ||
| "oldUri": urljoin("file:", old_path), | ||
| }] | ||
| } | ||
| if not session: | ||
| self.rename_path(old_path, new_path) | ||
| self.notify_did_rename(rename_file_params) | ||
| return | ||
| request = Request.willRenameFiles(rename_file_params) | ||
| session.send_request( | ||
| request, | ||
| lambda res: self.handle(res, session.config.name, old_path, new_path, rename_file_params) | ||
| ) | ||
|
|
||
| def get_old_path(self, paths: list[str] | None, view: sublime.View | None) -> str: | ||
| if paths: | ||
| return paths[0] | ||
| if view: | ||
| return view.file_name() or "" | ||
| return "" | ||
|
|
||
| def handle(self, res: WorkspaceEdit | None, session_name: str, | ||
| old_path: str, new_path: str, rename_file_params: RenameFilesParams) -> None: | ||
| session = self.session_by_name(session_name) | ||
| if session: | ||
| # LSP spec - Apply WorkspaceEdit before the files are renamed | ||
| if res: | ||
| session.apply_workspace_edit_async(res, is_refactoring=True) | ||
| self.rename_path(old_path, new_path) | ||
| self.notify_did_rename(rename_file_params) | ||
|
|
||
| def rename_path(self, old_path: str, new_path: str) -> None: | ||
| old_regions: list[sublime.Region] = [] | ||
| view = self.window.find_open_file(old_path) | ||
| if view: | ||
| old_regions = [region for region in view.sel()] | ||
| view.close() # LSP spec - send didClose for the old file | ||
| # actally rename the file, this will create a new file | ||
| os.rename(old_path, new_path) | ||
| if os.path.isfile(new_path): | ||
| def restore_regions(v: sublime.View | None) -> None: | ||
| if not v: | ||
| return | ||
| v.sel().clear() | ||
| v.sel().add_all(old_regions) | ||
|
|
||
| # LSP spec - send didOpen for the new file | ||
| open_file_uri(self.window, new_path).then(restore_regions) | ||
|
|
||
| def notify_did_rename(self, rename_file_params: RenameFilesParams): | ||
| sessions = [s for s in self.sessions() if s.has_capability('workspace.fileOperations.didRename')] | ||
|
||
| for s in sessions: | ||
| s.send_notification(Notification.didRenameFiles(rename_file_params)) | ||
Uh oh!
There was an error while loading. Please reload this page.