forked from SublimeLinter/SublimeLinter
-
Notifications
You must be signed in to change notification settings - Fork 0
/
quick_actions.py
113 lines (94 loc) · 3.42 KB
/
quick_actions.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import sublime
import sublime_plugin
from .lint import persist
from .lint import quick_fix
from .lint import util
MYPY = False
if MYPY:
from typing import Callable, List, Optional
from mypy_extensions import TypedDict
LintError = persist.LintError
QuickAction = quick_fix.QuickAction
Event = TypedDict("Event", {"x": float, "y": float})
class sublime_linter_quick_actions(sublime_plugin.TextCommand):
def want_event(self):
return True
def is_visible(self, event=None, prefer_panel=False):
# type: (Event, bool) -> bool
if event:
return bool(self.available_actions(self.view, event))
else:
return len(self.view.sel()) == 1
def run(self, edit, event=None, prefer_panel=False):
# type: (sublime.Edit, Event, bool) -> None
view = self.view
window = view.window()
assert window
# We currently only allow multiple selections for the
# context menu where we can select *one* of the selections
# using the click event data.
if event is None and len(self.view.sel()) != 1:
window.status_message("Quick actions don't support multiple selections")
return
def on_done(idx):
# type: (int) -> None
if idx < 0:
return
action = actions[idx]
quick_fix.apply_fix(action.fn, view)
actions = self.available_actions(view, event)
if not actions:
if prefer_panel:
window.show_quick_panel(
["No quick action available."],
lambda x: None
)
else:
window.status_message("No quick action available")
elif len(actions) == 1 and not prefer_panel:
on_done(0)
else:
window.show_quick_panel(
[action.description for action in actions],
on_done
)
def available_actions(self, view, event):
# type: (sublime.View, Optional[Event]) -> List[QuickAction]
errors = self.affected_errors(view, event)
return sorted(
list(quick_fix.actions_for_errors(errors, view)),
key=lambda action: (-len(action.solves), action.description)
)
def affected_errors(self, view, event):
# type: (sublime.View, Optional[Event]) -> List[LintError]
if event:
vector = (event['x'], event['y'])
point = view.window_to_text(vector)
for selection in view.sel():
if selection.contains(point):
sel = selection
break
else:
sel = sublime.Region(point)
else:
sel = view.sel()[0]
filename = util.canonical_filename(view)
if sel.empty():
char_selection = sublime.Region(sel.a, sel.a + 1)
errors = get_errors_where(
filename,
lambda region: region.intersects(char_selection)
)
if errors:
return errors
sel = view.full_line(sel.a)
return get_errors_where(
filename,
lambda region: region.intersects(sel)
)
def get_errors_where(filename, fn):
# type: (str, Callable[[sublime.Region], bool]) -> List[LintError]
return [
error for error in persist.file_errors[filename]
if fn(error['region'])
]