Skip to content

Commit 94b4067

Browse files
improved copy, move and delete refactor command (now they are safe)
1 parent afcfb20 commit 94b4067

9 files changed

+869
-146
lines changed

Context.sublime-menu

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,17 +74,24 @@
7474
"id": "refactor",
7575
"children": [
7676
{
77-
"caption": "Copy",
77+
"caption": "Safe Copy",
7878
"command": "refactor",
7979
"args": {
80-
"case": "copy"
80+
"case": "safe_copy"
8181
}
8282
},
8383
{
84-
"caption": "Move",
84+
"caption": "Safe Move",
8585
"command": "refactor",
8686
"args": {
87-
"case": "move"
87+
"case": "safe_move"
88+
}
89+
},
90+
{
91+
"caption": "Safe Delete",
92+
"command": "refactor",
93+
"args": {
94+
"case": "safe_delete"
8895
}
8996
},
9097
{

_generated_2018_02_03_at_21_46_10.py renamed to _generated_2018_02_04_at_03_59_09.py

Lines changed: 402 additions & 45 deletions
Large diffs are not rendered by default.

changelog/0.14.0.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ v0.14.0
1212

1313
- Show hint_parameters tooltip on commit_completion and on insert_snippet "()"
1414
- Added Refactor command:
15-
* Copy
16-
* Move
15+
* Safe Copy
16+
* Safe Move
17+
* Safe Delete
1718
* Extract Method (global scope, current scope, class method)
1819
* Extract Parameter
1920
* Extract Variable

helper/refactor/main.py

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,44 @@ def run(self, edit, **args):
66
case = args.get("case")
77
scope = view.scope_name(view.sel()[0].begin())
88

9-
if case == "move" :
10-
windowView = WindowView(title="Refactor - Move", use_compare_layout=True)
11-
windowView.addTitle(text="Refactor - Move")
9+
if case == "safe_move" :
10+
windowView = WindowView(title="Refactor - Safe Move", use_compare_layout=True)
11+
windowView.addTitle(text="Refactor - Safe Move")
1212
windowView.add(text="\n\n")
1313
windowView.addInput(value=view.file_name(), label="Move to: ", region_id="new_path")
1414
windowView.add(text="\n\n")
15-
windowView.addButton(text="PREVIEW", scope="javascriptenhancements.button_preview", callback=lambda view: self.view.run_command("refactor_move", args={"inputs": windowView.getInputs(), "preview": True}))
15+
windowView.addButton(text="PREVIEW", scope="javascriptenhancements.button_preview", callback=lambda view: self.view.run_command("refactor_safe_move", args={"inputs": windowView.getInputs(), "preview": True}))
1616
windowView.add(text=" ")
17-
windowView.addButton(text="MOVE", scope="javascriptenhancements.button_ok", callback=lambda view: self.view.run_command("refactor_move", args={"inputs": windowView.getInputs(), "preview": False, "view_id_caller": self.view.id()}))
17+
windowView.addButton(text="MOVE", scope="javascriptenhancements.button_ok", callback=lambda view: self.view.run_command("refactor_safe_move", args={"inputs": windowView.getInputs(), "preview": False, "view_id_caller": self.view.id()}))
1818
windowView.add(text=" ")
1919
windowView.addCloseButton(text="CANCEL", scope="javascriptenhancements.button_cancel")
2020
windowView.add(text=" \n")
2121

22-
elif case == "copy" :
23-
self.view.run_command("refactor_copy")
22+
elif case == "safe_copy" :
23+
windowView = WindowView(title="Refactor - Safe Copy", use_compare_layout=True)
24+
windowView.addTitle(text="Refactor - Safe Copy")
25+
windowView.add(text="\n\n")
26+
windowView.addInput(value=view.file_name(), label="Copy to: ", region_id="new_path")
27+
windowView.add(text="\n\n")
28+
windowView.addButton(text="PREVIEW", scope="javascriptenhancements.button_preview", callback=lambda view: self.view.run_command("refactor_safe_copy", args={"inputs": windowView.getInputs(), "preview": True}))
29+
windowView.add(text=" ")
30+
windowView.addButton(text="COPY", scope="javascriptenhancements.button_ok", callback=lambda view: self.view.run_command("refactor_safe_copy", args={"inputs": windowView.getInputs(), "preview": False, "view_id_caller": self.view.id()}))
31+
windowView.add(text=" ")
32+
windowView.addCloseButton(text="CANCEL", scope="javascriptenhancements.button_cancel")
33+
windowView.add(text=" \n")
34+
35+
if case == "safe_delete" :
36+
windowView = WindowView(title="Refactor - Safe Delete", use_compare_layout=True)
37+
windowView.addTitle(text="Refactor - Safe Delete")
38+
windowView.add(text="\n\n")
39+
windowView.add(text="File to delete: " + view.file_name())
40+
windowView.add(text="\n\n")
41+
windowView.addButton(text="PREVIEW", scope="javascriptenhancements.button_preview", callback=lambda view: self.view.run_command("refactor_safe_delete", args={"preview": True}))
42+
windowView.add(text=" ")
43+
windowView.addButton(text="DELETE", scope="javascriptenhancements.button_ok", callback=lambda view: self.view.run_command("refactor_safe_delete", args={"preview": False, "view_id_caller": self.view.id()}))
44+
windowView.add(text=" ")
45+
windowView.addCloseButton(text="CANCEL", scope="javascriptenhancements.button_cancel")
46+
windowView.add(text=" \n")
2447

2548
elif case == "extract_method" :
2649

@@ -62,9 +85,11 @@ def is_visible(self, **args) :
6285
view = self.view
6386
return Util.selection_in_js_scope(view)
6487

65-
${include refactor_move_command.py}
88+
${include refactor_safe_move_command.py}
89+
90+
${include refactor_safe_copy_command.py}
6691

67-
${include refactor_copy_command.py}
92+
${include refactor_safe_delete_command.py}
6893

6994
${include refactor_extract_method_command.py}
7095

helper/refactor/refactor_copy_command.py

Lines changed: 0 additions & 40 deletions
This file was deleted.

helper/refactor/refactor_extract_variable_command.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ def run(self, edit, **args):
8282
if r.contains(selection):
8383
region = r
8484
break
85-
85+
8686
if region:
8787
prev_line_is_empty = Util.prev_line_is_empty(view, region)
8888

@@ -107,6 +107,9 @@ def run(self, edit, **args):
107107

108108
])
109109

110+
variable_kind = ["let", "const", "var"]
111+
view.window().show_quick_panel(variable_kind, None, 0, 0, lambda index: self.view.run_command("replace_text_view", args={"start": region.begin(), "end": region.begin() + len(view.substr(view.word(region.begin()))) , "text": variable_kind[index]}))
112+
110113
else:
111114
sublime.error_message("Cannot introduce variable. Some problems occured.")
112115

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
import sublime, sublime_plugin
2+
import os, shutil
3+
4+
class RefactorSafeCopyCommand(sublime_plugin.TextCommand):
5+
def run(self, edit, **args):
6+
view = self.view
7+
window = view.window()
8+
file_name = view.file_name()
9+
inputs = args.get("inputs")
10+
view_id_caller = args.get("view_id_caller") if "view_id_caller" in args else None
11+
new_path = inputs["new_path"].strip()
12+
settings = get_project_settings()
13+
14+
if not file_name:
15+
sublime.error_message("Cannot copy this file. File name is empty.")
16+
return
17+
18+
if new_path == file_name:
19+
sublime.message_dialog("The file path is the same as before.")
20+
return
21+
22+
if settings:
23+
24+
if not args.get("preview"):
25+
26+
if os.path.isfile(new_path):
27+
if not sublime.ok_cancel_dialog(new_path + " already exists.", "Copy anyway"):
28+
return
29+
30+
if not os.path.isdir(os.path.dirname(new_path)):
31+
os.makedirs(os.path.dirname(new_path))
32+
33+
else:
34+
preview_view = None
35+
for v in window.views():
36+
if v.name() == "Refactor - Copy Preview":
37+
preview_view = v
38+
preview_view.erase(edit, sublime.Region(0, preview_view.size()))
39+
window.focus_view(preview_view)
40+
break
41+
42+
if not preview_view:
43+
preview_view = window.new_file()
44+
preview_view.set_name("Refactor - Copy Preview")
45+
preview_view.set_syntax_file('Packages/Default/Find Results.hidden-tmLanguage')
46+
preview_view.set_scratch(True)
47+
48+
preview_view.run_command("append_text_view", args={"text": "Refactor - Copy Preview\n\nList of files that will be updated\n\n"})
49+
50+
imports = self.get_imports(settings, [file_name])
51+
52+
if imports[file_name]["requirements"]:
53+
content = ""
54+
55+
with open(file_name, "r") as file:
56+
content = file.read()
57+
preview_content = ""
58+
59+
for req in imports[file_name]["requirements"]:
60+
start_offset = int(req["loc"]["start"]["offset"]) + 1
61+
end_offset = int(req["loc"]["end"]["offset"]) - 1
62+
63+
req_new_path = req["import"] if os.path.isabs(req["import"]) else os.path.abspath(os.path.dirname(file_name) + os.path.sep + req["import"])
64+
65+
if os.path.dirname(new_path) == os.path.dirname(req_new_path):
66+
rel_new_path = "./" + os.path.basename(req_new_path)
67+
else:
68+
rel_new_path = os.path.relpath(req_new_path, start=os.path.dirname(new_path))
69+
if not rel_new_path.startswith(".."):
70+
rel_new_path = "./" + rel_new_path
71+
content = content [:start_offset] + rel_new_path + content[end_offset:]
72+
73+
if args.get("preview"):
74+
splitted_content = content.splitlines()
75+
76+
if not preview_content:
77+
preview_content = "- From:\n" + file_name + "\n\n"
78+
preview_content += "- To:\n" + new_path + "\n\n"
79+
80+
line = int(req["line"]) - 1
81+
range_start = max(0, line - 2)
82+
range_end = min(line + 2, len(splitted_content))
83+
while range_start <= range_end:
84+
preview_content += " " + str(range_start + 1) + (": " if line == range_start else " ") + splitted_content[range_start] + "\n"
85+
range_start += 1
86+
preview_content += "\n\n"
87+
88+
if args.get("preview"):
89+
preview_view.run_command("append_text_view", args={"text": preview_content})
90+
91+
if not args.get("preview"):
92+
with open(new_path, "w+") as file:
93+
file.seek(0)
94+
file.write(content)
95+
file.truncate()
96+
97+
if not args.get("preview"):
98+
99+
for v in window.views():
100+
if v.name() == "Refactor - Copy Preview":
101+
v.close()
102+
break
103+
104+
if view_id_caller:
105+
windowViewManager.get(view_id_caller).close()
106+
107+
else:
108+
sublime.error_message("Error: can't get project settings")
109+
110+
def get_imports(self, settings, javascript_files):
111+
112+
view = self.view
113+
114+
flow_cli = "flow"
115+
is_from_bin = True
116+
chdir = settings["project_dir_name"]
117+
use_node = True
118+
bin_path = ""
119+
120+
if settings and settings["project_settings"]["flow_cli_custom_path"]:
121+
flow_cli = os.path.basename(settings["project_settings"]["flow_cli_custom_path"])
122+
bin_path = os.path.dirname(settings["project_settings"]["flow_cli_custom_path"])
123+
is_from_bin = False
124+
chdir = settings["project_dir_name"]
125+
use_node = False
126+
127+
deps = flow_parse_cli_dependencies(view)
128+
129+
node = NodeJS(check_local=True)
130+
131+
result = node.execute_check_output(
132+
flow_cli,
133+
[
134+
'get-imports',
135+
'--from', 'sublime_text',
136+
'--root', deps.project_root,
137+
'--json'
138+
] + javascript_files,
139+
is_from_bin=is_from_bin,
140+
use_fp_temp=True,
141+
is_output_json=True,
142+
chdir=chdir,
143+
bin_path=bin_path,
144+
use_node=use_node
145+
)
146+
147+
if result[0]:
148+
return result[1]
149+
150+
return {}
151+
152+
def is_enabled(self, **args) :
153+
view = self.view
154+
if not view.file_name():
155+
return False
156+
settings = get_project_settings()
157+
if not settings or not Util.selection_in_js_scope(view):
158+
return False
159+
return True
160+
161+
def is_visible(self, **args) :
162+
view = self.view
163+
if not view.file_name():
164+
return False
165+
settings = get_project_settings()
166+
if not settings or not Util.selection_in_js_scope(view):
167+
return False
168+
return True
169+

0 commit comments

Comments
 (0)