Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion plugin/core/edit.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,22 @@
from .logging import debug
from .promise import Promise
from .protocol import UINT_MAX
from typing import Dict, List, Optional, Tuple, Union
from typing import Dict, List, Optional, Tuple, TypedDict, Union
from typing_extensions import NotRequired
import sublime


WorkspaceChanges = Dict[str, Tuple[List[Union[TextEdit, AnnotatedTextEdit]], Optional[str], Optional[int]]]


class WorkspaceEditSummary(TypedDict):
total_changes: int
edited_files: int
created_files: NotRequired[int]
renamed_files: NotRequired[int]
deleted_files: NotRequired[int]


def parse_workspace_edit(workspace_edit: WorkspaceEdit, label: str | None = None) -> WorkspaceChanges:
changes: WorkspaceChanges = {}
document_changes = workspace_edit.get('documentChanges')
Expand Down
25 changes: 17 additions & 8 deletions plugin/core/sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
from .edit import apply_text_edits
from .edit import parse_workspace_edit
from .edit import WorkspaceChanges
from .edit import WorkspaceEditSummary
from .file_watcher import DEFAULT_WATCH_KIND
from .file_watcher import file_watcher_event_type_to_lsp_file_change_type
from .file_watcher import FileWatcher
Expand Down Expand Up @@ -1710,7 +1711,7 @@ def _template_variables(self) -> dict[str, str]:
def execute_command(
self, command: ExecuteCommandParams, *, progress: bool = False, view: sublime.View | None = None,
is_refactoring: bool = False,
) -> Promise:
) -> Promise[None]:
"""Run a command from any thread. Your .then() continuations will run in Sublime's worker thread."""
if self._plugin:
task: PackagedTask[None] = Promise.packaged_task()
Expand Down Expand Up @@ -1915,8 +1916,8 @@ def _apply_code_action_async(
title = code_action['title']
edit = code_action.get("edit")
is_refactoring = kind_contains_other_kind(CodeActionKind.Refactor, code_action.get('kind', ''))
promise = self.apply_workspace_edit_async(edit, label=title, is_refactoring=is_refactoring) if edit else \
Promise.resolve(None)
promise = self.apply_workspace_edit_async(edit, label=title, is_refactoring=is_refactoring) \
.then(lambda _: None) if edit else Promise.resolve(None)
command = code_action.get("command")
if command is not None:
execute_command: ExecuteCommandParams = {
Expand All @@ -1931,15 +1932,18 @@ def _apply_code_action_async(

def apply_workspace_edit_async(
self, edit: WorkspaceEdit, *, label: str | None = None, is_refactoring: bool = False
) -> Promise[None]:
) -> Promise[WorkspaceEditSummary]:
"""
Apply workspace edits, and return a promise that resolves on the async thread again after the edits have been
applied.
Apply a WorkspaceEdit, and return a promise that resolves on the async thread again after the edits have been
applied. The resolved promise contains a summary of the changes in the WorkspaceEdit.
"""
is_refactoring = self._is_executing_refactoring_command or is_refactoring
return self.apply_parsed_workspace_edits(parse_workspace_edit(edit, label), is_refactoring)

def apply_parsed_workspace_edits(self, changes: WorkspaceChanges, is_refactoring: bool = False) -> Promise[None]:
def apply_parsed_workspace_edits(
self, changes: WorkspaceChanges, is_refactoring: bool = False
) -> Promise[WorkspaceEditSummary]:

def handle_view(
edits: list[TextEdit],
label: str | None,
Expand All @@ -1958,6 +1962,10 @@ def handle_view(
selected_sheets = self.window.selected_sheets()
promises: list[Promise[None]] = []
auto_save = userprefs().refactoring_auto_save if is_refactoring else 'never'
summary: WorkspaceEditSummary = {
'total_changes': sum(len(value[0]) for value in changes.values()),
'edited_files': len(changes)
}
for uri, (edits, label, view_version) in changes.items():
view_state_actions = self._get_view_state_actions(uri, auto_save)
promises.append(
Expand All @@ -1966,7 +1974,8 @@ def handle_view(
)
return Promise.all(promises) \
.then(lambda _: self._set_selected_sheets(selected_sheets)) \
.then(lambda _: self._set_focused_sheet(active_sheet))
.then(lambda _: self._set_focused_sheet(active_sheet)) \
.then(lambda _: summary)

def _get_view_state_actions(self, uri: DocumentUri, auto_save: str) -> ViewStateActions:
"""
Expand Down
4 changes: 2 additions & 2 deletions plugin/rename.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,11 +196,11 @@ def _on_rename_result_async(self, session: Session, label: str, response: Worksp
if not response:
return session.window.status_message('Nothing to rename')
changes = parse_workspace_edit(response, label)
file_count = len(changes.keys())
file_count = len(changes)
if file_count == 1:
session.apply_parsed_workspace_edits(changes, True)
return
total_changes = sum(map(len, changes.values()))
total_changes = sum(len(value[0]) for value in changes.values())
message = f"Replace {total_changes} occurrences across {file_count} files?"
choice = sublime.yes_no_cancel_dialog(message, "Replace", "Preview", title="Rename")
if choice == sublime.DialogResult.YES:
Expand Down