-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcode_actions_on_save.py
100 lines (88 loc) · 4.65 KB
/
code_actions_on_save.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
from __future__ import annotations
from asyncio import Future
import asyncio
from .libs.lsp.pull_diagnostics import pull_diagnostics
from .libs.lsp.mir import mir
from .libs.lsp.manage_servers import server_for_view, servers_for_view
from .libs.lsp.types import CodeActionOptions, CodeActionTriggerKind, Diagnostic
from .libs.lsp.view_to_lsp import get_view_uri, region_to_range
from .libs.event_loop import run_future
import sublime_plugin
import sublime
class MirCompletionListener(sublime_plugin.EventListener):
def on_pre_save(self, view: sublime.View):
if MirCodeActionsOnSaveCommand.running_code_actions_on_save:
return
view.run_command('mir_code_actions_on_save')
class MirCodeActionsOnSaveCommand(sublime_plugin.TextCommand):
running_code_actions_on_save = False
def run(self, edit: sublime.Edit):
run_future(self.run_code_actions_on_save())
async def run_code_actions_on_save(self):
MirCodeActionsOnSaveCommand.running_code_actions_on_save = True
diagnostics_results = await mir.get_diagnostics(self.view)
all_diagnostics: list[Diagnostic] = []
for _, diagnostics in diagnostics_results:
all_diagnostics.extend(diagnostics)
servers = servers_for_view(self.view, 'codeActionProvider')
view_settings = self.view.settings()
settings: list[str] = view_settings.get('mir.on_save', [])
format_with_provider: str | None = None
for server in servers:
await pull_diagnostics(server, get_view_uri(self.view))
code_action_provider: bool | CodeActionOptions = server.capabilities.get('codeActionProvider')
matching_kinds = []
for user_setting in settings:
if user_setting.startswith('format'): # `format.biome` or `format.vtsls`
format_with_provider = user_setting.replace('format.', '')
continue
if isinstance(code_action_provider, bool):
# This can be tested with the biome LSP
# if we uncomment this, biome will return some irrelevant code action fixes to suppress some linter rules, even if the linter is not enabled... which is a bug
# matching_kinds.append(user_setting)
continue
else:
code_action_kinds = code_action_provider.get('codeActionKinds')
if code_action_kinds and user_setting in code_action_kinds:
matching_kinds.append(user_setting)
if not matching_kinds: # don't send code actions if no matching code actions kinds are found
continue
future = server.send.code_action({
'textDocument': {'uri': get_view_uri(self.view)},
'range': region_to_range(self.view, sublime.Region(0, self.view.size())),
'context': {
'only': matching_kinds,
'diagnostics': all_diagnostics,
'triggerKind': CodeActionTriggerKind.Automatic
}
})
# for code action on save we will not do asyncio.gather
# to prevent servers to return edits that can clash with other servers
# instead request CodeAction's from one server, apply edits, then request CodeAction's from the other server, apply edits and so on
result = await future.result
if not result:
continue
for maybe_code_action in result:
edit = maybe_code_action.get('edit')
if edit:
self.view.run_command('mir_apply_workspace_edit', {
'workspace_edit': edit
})
if format_with_provider and (formatting_server := server_for_view(format_with_provider,self.view)) and formatting_server.capabilities.has('documentFormattingProvider'):
future = formatting_server.send.formatting({
'textDocument': {'uri': get_view_uri(self.view)},
'options': {
'tabSize': int(view_settings.get("tab_size", 4)),
'insertSpaces': bool(view_settings.get("translate_tabs_to_spaces", False)),
'trimTrailingWhitespace': True,
'insertFinalNewline': False,
'trimFinalNewlines': False
}
})
result = await future.result
if result:
self.view.run_command('mir_apply_text_edits', {
'text_edits': result
})
self.view.run_command('save')
MirCodeActionsOnSaveCommand.running_code_actions_on_save = False