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
1 change: 1 addition & 0 deletions TypeScript.sublime-commands
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
{ "caption" : "TypeScript: Find References", "command": "typescript_find_references" },
{ "caption" : "TypeScript: Navigate To Symbol", "command": "typescript_nav_to" },
{ "caption" : "TypeScript: Rename", "command": "typescript_rename" },
{ "caption" : "TypeScript: Refactor", "command": "typescript_get_applicable_refactors" },
{ "caption" : "TypeScript: Paste And Format", "command": "typescript_paste_and_format" },
{ "caption" : "TypeScript: Format Line", "command": "typescript_format_line" },
{ "caption" : "TypeScript: Format Block", "command": "typescript_format_brackets" },
Expand Down
6 changes: 6 additions & 0 deletions typescript/commands/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
TypescriptFinishRenameCommand,
TypescriptRenameCommand
)
from .refactor import (
TypescriptGetApplicableRefactorsCommand,
TypescriptApplyRefactorCommand
)
from .build import TypescriptBuildCommand
from .settings import (
TypescriptOpenPluginDefaultSettingFile,
Expand Down Expand Up @@ -63,6 +67,8 @@
"TypescriptFinishRenameCommand",
"TypescriptRenameCommand",
"TypescriptOrganizeImportsCommand",
"TypescriptGetApplicableRefactorsCommand",
"TypescriptApplyRefactorCommand",
"TypescriptSave",
"TypescriptShowDoc",
"TypescriptSignaturePanel",
Expand Down
75 changes: 75 additions & 0 deletions typescript/commands/refactor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import sublime_plugin

from ..libs import *
from ..libs.view_helpers import *
from ..libs.reference import *
from .base_command import TypeScriptBaseTextCommand

class RefactorAction:
def __init__(self, refactor_name, action_name, description):
self.refactor_name = refactor_name
self.action_name = action_name
self.description = description

class TypescriptGetApplicableRefactorsCommand(TypeScriptBaseTextCommand):
"""Get refactors applicable to a specific region"""
def run(self, text):
check_update_view(self.view)
file_name = self.view.file_name()
(start_loc, end_loc) = get_start_and_end_from_view(self.view)
refactors_resp = cli.service.get_applicable_refactors(file_name, start_loc, end_loc)

if not refactors_resp["success"]:
return

actions = []
for refactor in refactors_resp["body"]:
refactor_name = refactor["name"]
if "inlineable" in refactor and not refactor["inlineable"]:
actions.append(RefactorAction(refactor_name, refactor_name, refactor["description"]))
else:
actions.extend(map(lambda action: RefactorAction(refactor_name, action["name"], action["description"]), refactor["actions"]))

refactoring_names = list(map(lambda action: action.description, actions))

def choose(index):
self.choose_refactor(file_name, start_loc, end_loc, actions, index)

# Somehow there's a blocking bug with `show_popup_menu`
# that leads to issues on certain platforms.
# https://github.com/SublimeTextIssues/Core/issues/1282
# self.view.show_popup_menu(refactoring_names, delayed_choose)
# So instead we can use `show_quick_panel` which looks great anyway.
active_window().show_quick_panel(refactoring_names, choose)

def choose_refactor(self, file_name, start_loc, end_loc, actions, index):
if index < 0:
return
action = actions[index]

def on_completed(edits_response):
self.view.run_command("typescript_apply_refactor", { "edits_response": edits_response })

def request_edits():
cli.service.get_edits_for_refactor_async(
path = file_name,
refactor_name = action.refactor_name,
action_name = action.action_name,
start_loc = start_loc, end_loc = end_loc,
on_completed = on_completed)
request_edits()

class TypescriptApplyRefactorCommand(TypeScriptBaseTextCommand):
def run(self, text, edits_response):
if not edits_response["success"]:
return

for edit in edits_response["body"]["edits"]:
file_name = edit["fileName"]
file_view = active_window().find_open_file(file_name)
if not file_view:
client_info = cli.get_or_add_file(file_name)
client_info.refactors_on_load = { "textChanges": edit["textChanges"] }
active_window().open_file(file_name)
else:
apply_formatting_changes(text, self.view, edit["textChanges"])
17 changes: 17 additions & 0 deletions typescript/libs/service_proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,23 @@ def rename(self, path, location=Location(1, 1)):
self.__worker_comm.sendCmdSync(json_str, req_dict["seq"])
return response_dict

def get_edits_for_refactor_async(self, path, refactor_name, action_name, start_loc, end_loc, on_completed):
args = {
"file": path,
"startLine": start_loc.line,
"startOffset": start_loc.offset,
"endLine": end_loc.line,
"endOffset": end_loc.offset,
"refactor": refactor_name,
"action": action_name,
}
req_dict = self.create_req_dict("getEditsForRefactor", args)
json_str = json_helpers.encode(req_dict)
response_dict = self.__comm.sendCmd(json_str, on_completed, req_dict["seq"])
#on_completed(response_dict)
#return response_dict


def request_get_err(self, delay=0, pathList=[]):
args = {"files": pathList, "delay": delay}
req_dict = self.create_req_dict("geterr", args)
Expand Down
7 changes: 5 additions & 2 deletions typescript/libs/view_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,16 +123,19 @@ def is_special_view(view):


def get_location_from_view(view):
"""Returns the Location tuple of the beginning of the first selected region in the view"""
"""Returns a Location representing the beginning of the first selected region in the view"""
region = view.sel()[0]
return get_location_from_region(view, region)


def get_location_from_region(view, region):
"""Returns the Location tuple of the beginning of the given region"""
position = region.begin()
return get_location_from_position(view, position)

def get_start_and_end_from_view(view):
"""Returns a tuple of Location objects representing the (start, end) of a region."""
region = view.sel()[0]
return map(lambda p: get_location_from_position(view, p), (region.begin(), region.end()))

def get_location_from_position(view, position):
"""Returns the LineOffset object of the given text position"""
Expand Down