We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Option to disable code actions
Currently code actions can be shown as bulbs or annotations, but there doesn't seem to be a way to completely disable them. Would be nice to get such an option.

I wrote a very simple patch that prevents them from rendering when `"show_code_actions"` is not set to a known value (currently it falls back on `'annotation'` instead). But ended up not submitting it because ideally we shouldn't even calculate the code actions when they should be disabled. Unfortunately, tracking down every code path that invokes code actions has proven too much. Requesting support. 🙂

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `plugin/code_actions.py`
Content:
```
1 from .core.promise import Promise
2 from .core.protocol import CodeAction
3 from .core.protocol import Command
4 from .core.protocol import Diagnostic
5 from .core.protocol import Request
6 from .core.registry import LspTextCommand
7 from .core.registry import sessions_for_view
8 from .core.registry import windows
9 from .core.sessions import SessionBufferProtocol
10 from .core.settings import userprefs
11 from .core.typing import Any, List, Dict, Callable, Optional, Tuple, Union, Sequence
12 from .core.views import entire_content_region
13 from .core.views import text_document_code_action_params
14 from .save_command import LspSaveCommand, SaveTask
15 import sublime
16 
17 CodeActionOrCommand = Union[CodeAction, Command]
18 CodeActionsResponse = Optional[List[CodeActionOrCommand]]
19 CodeActionsByConfigName = Dict[str, List[CodeActionOrCommand]]
20 
21 
22 class CodeActionsCollector:
23     """
24     Collects code action responses from multiple sessions. Calls back the "on_complete_handler" with
25     results when all responses are received.
26 
27     Usage example:
28 
29     with CodeActionsCollector() as collector:
30         actions_manager.request_with_diagnostics(collector.create_collector('test_config'))
31         actions_manager.request_with_diagnostics(collector.create_collector('another_config'))
32 
33     The "create_collector()" must only be called within the "with" context. Once the context is
34     exited, the "on_complete_handler" will be called once all the created collectors receive the
35     response (are called).
36     """
37 
38     def __init__(self, on_complete_handler: Callable[[CodeActionsByConfigName], None]):
39         self._on_complete_handler = on_complete_handler
40         self._commands_by_config = {}  # type: CodeActionsByConfigName
41         self._request_count = 0
42         self._response_count = 0
43         self._all_requested = False
44 
45     def __enter__(self) -> 'CodeActionsCollector':
46         return self
47 
48     def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
49         self._all_requested = True
50         self._notify_if_all_finished()
51 
52     def create_collector(self, config_name: str) -> Callable[[CodeActionsResponse], None]:
53         self._request_count += 1
54         return lambda actions: self._collect_response(config_name, actions)
55 
56     def _collect_response(self, config_name: str, actions: CodeActionsResponse) -> None:
57         self._response_count += 1
58         self._commands_by_config[config_name] = actions or []
59         self._notify_if_all_finished()
60 
61     def _notify_if_all_finished(self) -> None:
62         if self._all_requested and self._request_count == self._response_count:
63             # Call back on Sublime's async thread
64             sublime.set_timeout_async(lambda: self._on_complete_handler(self._commands_by_config))
65 
66     def get_actions(self) -> CodeActionsByConfigName:
67         return self._commands_by_config
68 
69 
70 class CodeActionsManager:
71     """Manager for per-location caching of code action responses."""
72 
73     def __init__(self) -> None:
74         self._response_cache = None  # type: Optional[Tuple[str, CodeActionsCollector]]
75 
76     def request_with_diagnostics_async(
77         self,
78         view: sublime.View,
79         region: sublime.Region,
80         session_buffer_diagnostics: Sequence[Tuple[SessionBufferProtocol, Sequence[Diagnostic]]],
81         actions_handler: Callable[[CodeActionsByConfigName], None]
82     ) -> CodeActionsCollector:
83         """
84         Requests code actions *only* for provided diagnostics. If session has no diagnostics then
85         it will be skipped.
86         """
87         return self._request_async(view, region, session_buffer_diagnostics, True, actions_handler)
88 
89     def request_for_region_async(
90         self,
91         view: sublime.View,
92         region: sublime.Region,
93         session_buffer_diagnostics: Sequence[Tuple[SessionBufferProtocol, Sequence[Diagnostic]]],
94         actions_handler: Callable[[CodeActionsByConfigName], None],
95         only_kinds: Optional[Dict[str, bool]] = None
96     ) -> CodeActionsCollector:
97         """
98         Requests code actions with provided diagnostics and specified region. If there are
99         no diagnostics for given session, the request will be made with empty diagnostics list.
100         """
101         return self._request_async(view, region, session_buffer_diagnostics, False, actions_handler, only_kinds)
102 
103     def request_on_save(
104         self,
105         view: sublime.View,
106         actions_handler: Callable[[CodeActionsByConfigName], None],
107         on_save_actions: Dict[str, bool]
108     ) -> CodeActionsCollector:
109         """
110         Requests code actions on save.
111         """
112         return self._request_async(view, entire_content_region(view), [], False, actions_handler, on_save_actions)
113 
114     def _request_async(
115         self,
116         view: sublime.View,
117         region: sublime.Region,
118         session_buffer_diagnostics: Sequence[Tuple[SessionBufferProtocol, Sequence[Diagnostic]]],
119         only_with_diagnostics: bool,
120         actions_handler: Callable[[CodeActionsByConfigName], None],
121         on_save_actions: Optional[Dict[str, bool]] = None
122     ) -> CodeActionsCollector:
123         use_cache = on_save_actions is None
124         if use_cache:
125             location_cache_key = "{}#{}:{}:{}".format(
126                 view.buffer_id(), view.change_count(), region, only_with_diagnostics)
127             if self._response_cache:
128                 cache_key, cache_collector = self._response_cache
129                 if location_cache_key == cache_key:
130                     sublime.set_timeout(lambda: actions_handler(cache_collector.get_actions()))
131                     return cache_collector
132                 else:
133                     self._response_cache = None
134 
135         collector = CodeActionsCollector(actions_handler)
136         with collector:
137             file_name = view.file_name()
138             if file_name:
139                 for session in sessions_for_view(view, 'codeActionProvider'):
140                     if on_save_actions:
141                         supported_kinds = session.get_capability('codeActionProvider.codeActionKinds')
142                         matching_kinds = get_matching_kinds(on_save_actions, supported_kinds or [])
143                         if matching_kinds:
144                             params = text_document_code_action_params(
145                                 view, file_name, region, [], matching_kinds)
146                             request = Request.codeAction(params, view)
147                             session.send_request_async(
148                                 request, *filtering_collector(session.config.name, matching_kinds, collector))
149                     else:
150                         diagnostics = []  # type: Sequence[Diagnostic]
151                         for sb, diags in session_buffer_diagnostics:
152                             if sb.session == session:
153                                 diagnostics = diags
154                                 break
155                         if only_with_diagnostics and not diagnostics:
156                             continue
157                         params = text_document_code_action_params(view, file_name, region, diagnostics)
158                         request = Request.codeAction(params, view)
159                         session.send_request_async(request, collector.create_collector(session.config.name))
160         if use_cache:
161             self._response_cache = (location_cache_key, collector)
162         return collector
163 
164 
165 def filtering_collector(
166     config_name: str,
167     kinds: List[str],
168     actions_collector: CodeActionsCollector
169 ) -> Tuple[Callable[[CodeActionsResponse], None], Callable[[Any], None]]:
170     """
171     Filters actions returned from the session so that only matching kinds are collected.
172 
173     Since older servers don't support the "context.only" property, these will return all
174     actions that need to be filtered.
175     """
176 
177     def actions_filter(actions: CodeActionsResponse) -> List[CodeActionOrCommand]:
178         return [a for a in (actions or []) if a.get('kind') in kinds]  # type: ignore
179 
180     collector = actions_collector.create_collector(config_name)
181     return (
182         lambda actions: collector(actions_filter(actions)),
183         lambda error: collector([])
184     )
185 
186 
187 actions_manager = CodeActionsManager()
188 
189 
190 def get_matching_kinds(user_actions: Dict[str, bool], session_actions: List[str]) -> List[str]:
191     """
192     Filters user-enabled or disabled actions so that only ones matching the session actions
193     are returned. Returned actions are those that are enabled and are not overridden by more
194     specific, disabled actions.
195 
196     Filtering only returns actions that exactly match the ones supported by given session.
197     If user has enabled a generic action that matches more specific session action
198     (for example user's a.b matching session's a.b.c), then the more specific (a.b.c) must be
199     returned as servers must receive only actions that they advertise support for.
200     """
201     matching_kinds = []
202     for session_action in session_actions:
203         enabled = False
204         action_parts = session_action.split('.')
205         for i in range(len(action_parts)):
206             current_part = '.'.join(action_parts[0:i + 1])
207             user_value = user_actions.get(current_part, None)
208             if isinstance(user_value, bool):
209                 enabled = user_value
210         if enabled:
211             matching_kinds.append(session_action)
212     return matching_kinds
213 
214 
215 class CodeActionOnSaveTask(SaveTask):
216     """
217     The main task that requests code actions from sessions and runs them.
218 
219     The amount of time the task is allowed to run is defined by user-controlled setting. If the task
220     runs longer, the native save will be triggered before waiting for results.
221     """
222     @classmethod
223     def is_applicable(cls, view: sublime.View) -> bool:
224         return bool(view.window()) and bool(cls._get_code_actions_on_save(view))
225 
226     @classmethod
227     def _get_code_actions_on_save(cls, view: sublime.View) -> Dict[str, bool]:
228         view_code_actions = view.settings().get('lsp_code_actions_on_save') or {}
229         code_actions = userprefs().lsp_code_actions_on_save.copy()
230         code_actions.update(view_code_actions)
231         allowed_code_actions = dict()
232         for key, value in code_actions.items():
233             if key.startswith('source.'):
234                 allowed_code_actions[key] = value
235         return allowed_code_actions
236 
237     def get_task_timeout_ms(self) -> int:
238         return userprefs().code_action_on_save_timeout_ms
239 
240     def run_async(self) -> None:
241         super().run_async()
242         self._request_code_actions_async()
243 
244     def _request_code_actions_async(self) -> None:
245         self._purge_changes_async()
246         on_save_actions = self._get_code_actions_on_save(self._view)
247         actions_manager.request_on_save(self._view, self._handle_response_async, on_save_actions)
248 
249     def _handle_response_async(self, responses: CodeActionsByConfigName) -> None:
250         if self._cancelled:
251             return
252         document_version = self._view.change_count()
253         tasks = []  # type: List[Promise]
254         for config_name, code_actions in responses.items():
255             if code_actions:
256                 for session in sessions_for_view(self._view, 'codeActionProvider'):
257                     if session.config.name == config_name:
258                         for code_action in code_actions:
259                             tasks.append(session.run_code_action_async(code_action, progress=False))
260                         break
261         if document_version != self._view.change_count():
262             # Give on_text_changed_async a chance to trigger.
263             Promise.all(tasks).then(lambda _: sublime.set_timeout_async(self._request_code_actions_async))
264         else:
265             Promise.all(tasks).then(lambda _: sublime.set_timeout_async(self._on_complete))
266 
267 
268 LspSaveCommand.register_task(CodeActionOnSaveTask)
269 
270 
271 class LspCodeActionsCommand(LspTextCommand):
272 
273     capability = 'codeActionProvider'
274 
275     def run(self, edit: sublime.Edit, event: Optional[dict] = None, only_kinds: Optional[List[str]] = None) -> None:
276         self.commands = []  # type: List[Tuple[str, str, CodeActionOrCommand]]
277         self.commands_by_config = {}  # type: CodeActionsByConfigName
278         view = self.view
279         try:
280             region = view.sel()[0]
281         except IndexError:
282             return
283         listener = windows.listener_for_view(view)
284         if not listener:
285             return
286         session_buffer_diagnostics, covering = listener.diagnostics_intersecting_async(region)
287         dict_kinds = {kind: True for kind in only_kinds} if only_kinds else None
288         actions_manager.request_for_region_async(
289             view, covering, session_buffer_diagnostics, self.handle_responses_async, dict_kinds)
290 
291     def handle_responses_async(self, responses: CodeActionsByConfigName) -> None:
292         self.commands_by_config = responses
293         self.commands = self.combine_commands()
294         self.show_popup_menu()
295 
296     def combine_commands(self) -> 'List[Tuple[str, str, CodeActionOrCommand]]':
297         results = []
298         for config, commands in self.commands_by_config.items():
299             for command in commands:
300                 results.append((config, command['title'], command))
301         return results
302 
303     def show_popup_menu(self) -> None:
304         if len(self.commands) > 0:
305             self.view.show_popup_menu([command[1] for command in self.commands], self.handle_select)
306         else:
307             self.view.show_popup('No actions available', sublime.HIDE_ON_MOUSE_MOVE_AWAY)
308 
309     def handle_select(self, index: int) -> None:
310         if index > -1:
311 
312             def run_async() -> None:
313                 selected = self.commands[index]
314                 session = self.session_by_name(selected[0])
315                 if session:
316                     session.run_code_action_async(selected[2], progress=True)
317 
318             sublime.set_timeout_async(run_async)
319
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/plugin/code_actions.py b/plugin/code_actions.py
--- a/plugin/code_actions.py
+++ b/plugin/code_actions.py
@@ -79,12 +79,12 @@
         region: sublime.Region,
         session_buffer_diagnostics: Sequence[Tuple[SessionBufferProtocol, Sequence[Diagnostic]]],
         actions_handler: Callable[[CodeActionsByConfigName], None]
-    ) -> CodeActionsCollector:
+    ) -> None:
         """
         Requests code actions *only* for provided diagnostics. If session has no diagnostics then
         it will be skipped.
         """
-        return self._request_async(view, region, session_buffer_diagnostics, True, actions_handler)
+        self._request_async(view, region, session_buffer_diagnostics, True, actions_handler)
 
     def request_for_region_async(
         self,
@@ -93,23 +93,23 @@
         session_buffer_diagnostics: Sequence[Tuple[SessionBufferProtocol, Sequence[Diagnostic]]],
         actions_handler: Callable[[CodeActionsByConfigName], None],
         only_kinds: Optional[Dict[str, bool]] = None
-    ) -> CodeActionsCollector:
+    ) -> None:
         """
         Requests code actions with provided diagnostics and specified region. If there are
         no diagnostics for given session, the request will be made with empty diagnostics list.
         """
-        return self._request_async(view, region, session_buffer_diagnostics, False, actions_handler, only_kinds)
+        self._request_async(view, region, session_buffer_diagnostics, False, actions_handler, only_kinds)
 
     def request_on_save(
         self,
         view: sublime.View,
         actions_handler: Callable[[CodeActionsByConfigName], None],
         on_save_actions: Dict[str, bool]
-    ) -> CodeActionsCollector:
+    ) -> None:
         """
         Requests code actions on save.
         """
-        return self._request_async(view, entire_content_region(view), [], False, actions_handler, on_save_actions)
+        self._request_async(view, entire_content_region(view), [], False, actions_handler, on_save_actions)
 
     def _request_async(
         self,
@@ -119,7 +119,10 @@
         only_with_diagnostics: bool,
         actions_handler: Callable[[CodeActionsByConfigName], None],
         on_save_actions: Optional[Dict[str, bool]] = None
-    ) -> CodeActionsCollector:
+    ) -> None:
+        if 'codeActionProvider' in userprefs().disabled_capabilities:
+            return None
+
         use_cache = on_save_actions is None
         if use_cache:
             location_cache_key = "{}#{}:{}:{}".format(
@@ -128,7 +131,6 @@
                 cache_key, cache_collector = self._response_cache
                 if location_cache_key == cache_key:
                     sublime.set_timeout(lambda: actions_handler(cache_collector.get_actions()))
-                    return cache_collector
                 else:
                     self._response_cache = None
 
@@ -159,7 +161,6 @@
                         session.send_request_async(request, collector.create_collector(session.config.name))
         if use_cache:
             self._response_cache = (location_cache_key, collector)
-        return collector
 
 
 def filtering_collector(

{"golden_diff": "diff --git a/plugin/code_actions.py b/plugin/code_actions.py\n--- a/plugin/code_actions.py\n+++ b/plugin/code_actions.py\n@@ -79,12 +79,12 @@\n         region: sublime.Region,\n         session_buffer_diagnostics: Sequence[Tuple[SessionBufferProtocol, Sequence[Diagnostic]]],\n         actions_handler: Callable[[CodeActionsByConfigName], None]\n-    ) -> CodeActionsCollector:\n+    ) -> None:\n         \"\"\"\n         Requests code actions *only* for provided diagnostics. If session has no diagnostics then\n         it will be skipped.\n         \"\"\"\n-        return self._request_async(view, region, session_buffer_diagnostics, True, actions_handler)\n+        self._request_async(view, region, session_buffer_diagnostics, True, actions_handler)\n \n     def request_for_region_async(\n         self,\n@@ -93,23 +93,23 @@\n         session_buffer_diagnostics: Sequence[Tuple[SessionBufferProtocol, Sequence[Diagnostic]]],\n         actions_handler: Callable[[CodeActionsByConfigName], None],\n         only_kinds: Optional[Dict[str, bool]] = None\n-    ) -> CodeActionsCollector:\n+    ) -> None:\n         \"\"\"\n         Requests code actions with provided diagnostics and specified region. If there are\n         no diagnostics for given session, the request will be made with empty diagnostics list.\n         \"\"\"\n-        return self._request_async(view, region, session_buffer_diagnostics, False, actions_handler, only_kinds)\n+        self._request_async(view, region, session_buffer_diagnostics, False, actions_handler, only_kinds)\n \n     def request_on_save(\n         self,\n         view: sublime.View,\n         actions_handler: Callable[[CodeActionsByConfigName], None],\n         on_save_actions: Dict[str, bool]\n-    ) -> CodeActionsCollector:\n+    ) -> None:\n         \"\"\"\n         Requests code actions on save.\n         \"\"\"\n-        return self._request_async(view, entire_content_region(view), [], False, actions_handler, on_save_actions)\n+        self._request_async(view, entire_content_region(view), [], False, actions_handler, on_save_actions)\n \n     def _request_async(\n         self,\n@@ -119,7 +119,10 @@\n         only_with_diagnostics: bool,\n         actions_handler: Callable[[CodeActionsByConfigName], None],\n         on_save_actions: Optional[Dict[str, bool]] = None\n-    ) -> CodeActionsCollector:\n+    ) -> None:\n+        if 'codeActionProvider' in userprefs().disabled_capabilities:\n+            return None\n+\n         use_cache = on_save_actions is None\n         if use_cache:\n             location_cache_key = \"{}#{}:{}:{}\".format(\n@@ -128,7 +131,6 @@\n                 cache_key, cache_collector = self._response_cache\n                 if location_cache_key == cache_key:\n                     sublime.set_timeout(lambda: actions_handler(cache_collector.get_actions()))\n-                    return cache_collector\n                 else:\n                     self._response_cache = None\n \n@@ -159,7 +161,6 @@\n                         session.send_request_async(request, collector.create_collector(session.config.name))\n         if use_cache:\n             self._response_cache = (location_cache_key, collector)\n-        return collector\n \n \n def filtering_collector(\n", "issue": "Option to disable code actions\nCurrently code actions can be shown as bulbs or annotations, but there doesn't seem to be a way to completely disable them. Would be nice to get such an option.\r\n\r\nI wrote a very simple patch that prevents them from rendering when `\"show_code_actions\"` is not set to a known value (currently it falls back on `'annotation'` instead). But ended up not submitting it because ideally we shouldn't even calculate the code actions when they should be disabled. Unfortunately, tracking down every code path that invokes code actions has proven too much. Requesting support. \ud83d\ude42\n", "before_files": [{"content": "from .core.promise import Promise\nfrom .core.protocol import CodeAction\nfrom .core.protocol import Command\nfrom .core.protocol import Diagnostic\nfrom .core.protocol import Request\nfrom .core.registry import LspTextCommand\nfrom .core.registry import sessions_for_view\nfrom .core.registry import windows\nfrom .core.sessions import SessionBufferProtocol\nfrom .core.settings import userprefs\nfrom .core.typing import Any, List, Dict, Callable, Optional, Tuple, Union, Sequence\nfrom .core.views import entire_content_region\nfrom .core.views import text_document_code_action_params\nfrom .save_command import LspSaveCommand, SaveTask\nimport sublime\n\nCodeActionOrCommand = Union[CodeAction, Command]\nCodeActionsResponse = Optional[List[CodeActionOrCommand]]\nCodeActionsByConfigName = Dict[str, List[CodeActionOrCommand]]\n\n\nclass CodeActionsCollector:\n    \"\"\"\n    Collects code action responses from multiple sessions. Calls back the \"on_complete_handler\" with\n    results when all responses are received.\n\n    Usage example:\n\n    with CodeActionsCollector() as collector:\n        actions_manager.request_with_diagnostics(collector.create_collector('test_config'))\n        actions_manager.request_with_diagnostics(collector.create_collector('another_config'))\n\n    The \"create_collector()\" must only be called within the \"with\" context. Once the context is\n    exited, the \"on_complete_handler\" will be called once all the created collectors receive the\n    response (are called).\n    \"\"\"\n\n    def __init__(self, on_complete_handler: Callable[[CodeActionsByConfigName], None]):\n        self._on_complete_handler = on_complete_handler\n        self._commands_by_config = {}  # type: CodeActionsByConfigName\n        self._request_count = 0\n        self._response_count = 0\n        self._all_requested = False\n\n    def __enter__(self) -> 'CodeActionsCollector':\n        return self\n\n    def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:\n        self._all_requested = True\n        self._notify_if_all_finished()\n\n    def create_collector(self, config_name: str) -> Callable[[CodeActionsResponse], None]:\n        self._request_count += 1\n        return lambda actions: self._collect_response(config_name, actions)\n\n    def _collect_response(self, config_name: str, actions: CodeActionsResponse) -> None:\n        self._response_count += 1\n        self._commands_by_config[config_name] = actions or []\n        self._notify_if_all_finished()\n\n    def _notify_if_all_finished(self) -> None:\n        if self._all_requested and self._request_count == self._response_count:\n            # Call back on Sublime's async thread\n            sublime.set_timeout_async(lambda: self._on_complete_handler(self._commands_by_config))\n\n    def get_actions(self) -> CodeActionsByConfigName:\n        return self._commands_by_config\n\n\nclass CodeActionsManager:\n    \"\"\"Manager for per-location caching of code action responses.\"\"\"\n\n    def __init__(self) -> None:\n        self._response_cache = None  # type: Optional[Tuple[str, CodeActionsCollector]]\n\n    def request_with_diagnostics_async(\n        self,\n        view: sublime.View,\n        region: sublime.Region,\n        session_buffer_diagnostics: Sequence[Tuple[SessionBufferProtocol, Sequence[Diagnostic]]],\n        actions_handler: Callable[[CodeActionsByConfigName], None]\n    ) -> CodeActionsCollector:\n        \"\"\"\n        Requests code actions *only* for provided diagnostics. If session has no diagnostics then\n        it will be skipped.\n        \"\"\"\n        return self._request_async(view, region, session_buffer_diagnostics, True, actions_handler)\n\n    def request_for_region_async(\n        self,\n        view: sublime.View,\n        region: sublime.Region,\n        session_buffer_diagnostics: Sequence[Tuple[SessionBufferProtocol, Sequence[Diagnostic]]],\n        actions_handler: Callable[[CodeActionsByConfigName], None],\n        only_kinds: Optional[Dict[str, bool]] = None\n    ) -> CodeActionsCollector:\n        \"\"\"\n        Requests code actions with provided diagnostics and specified region. If there are\n        no diagnostics for given session, the request will be made with empty diagnostics list.\n        \"\"\"\n        return self._request_async(view, region, session_buffer_diagnostics, False, actions_handler, only_kinds)\n\n    def request_on_save(\n        self,\n        view: sublime.View,\n        actions_handler: Callable[[CodeActionsByConfigName], None],\n        on_save_actions: Dict[str, bool]\n    ) -> CodeActionsCollector:\n        \"\"\"\n        Requests code actions on save.\n        \"\"\"\n        return self._request_async(view, entire_content_region(view), [], False, actions_handler, on_save_actions)\n\n    def _request_async(\n        self,\n        view: sublime.View,\n        region: sublime.Region,\n        session_buffer_diagnostics: Sequence[Tuple[SessionBufferProtocol, Sequence[Diagnostic]]],\n        only_with_diagnostics: bool,\n        actions_handler: Callable[[CodeActionsByConfigName], None],\n        on_save_actions: Optional[Dict[str, bool]] = None\n    ) -> CodeActionsCollector:\n        use_cache = on_save_actions is None\n        if use_cache:\n            location_cache_key = \"{}#{}:{}:{}\".format(\n                view.buffer_id(), view.change_count(), region, only_with_diagnostics)\n            if self._response_cache:\n                cache_key, cache_collector = self._response_cache\n                if location_cache_key == cache_key:\n                    sublime.set_timeout(lambda: actions_handler(cache_collector.get_actions()))\n                    return cache_collector\n                else:\n                    self._response_cache = None\n\n        collector = CodeActionsCollector(actions_handler)\n        with collector:\n            file_name = view.file_name()\n            if file_name:\n                for session in sessions_for_view(view, 'codeActionProvider'):\n                    if on_save_actions:\n                        supported_kinds = session.get_capability('codeActionProvider.codeActionKinds')\n                        matching_kinds = get_matching_kinds(on_save_actions, supported_kinds or [])\n                        if matching_kinds:\n                            params = text_document_code_action_params(\n                                view, file_name, region, [], matching_kinds)\n                            request = Request.codeAction(params, view)\n                            session.send_request_async(\n                                request, *filtering_collector(session.config.name, matching_kinds, collector))\n                    else:\n                        diagnostics = []  # type: Sequence[Diagnostic]\n                        for sb, diags in session_buffer_diagnostics:\n                            if sb.session == session:\n                                diagnostics = diags\n                                break\n                        if only_with_diagnostics and not diagnostics:\n                            continue\n                        params = text_document_code_action_params(view, file_name, region, diagnostics)\n                        request = Request.codeAction(params, view)\n                        session.send_request_async(request, collector.create_collector(session.config.name))\n        if use_cache:\n            self._response_cache = (location_cache_key, collector)\n        return collector\n\n\ndef filtering_collector(\n    config_name: str,\n    kinds: List[str],\n    actions_collector: CodeActionsCollector\n) -> Tuple[Callable[[CodeActionsResponse], None], Callable[[Any], None]]:\n    \"\"\"\n    Filters actions returned from the session so that only matching kinds are collected.\n\n    Since older servers don't support the \"context.only\" property, these will return all\n    actions that need to be filtered.\n    \"\"\"\n\n    def actions_filter(actions: CodeActionsResponse) -> List[CodeActionOrCommand]:\n        return [a for a in (actions or []) if a.get('kind') in kinds]  # type: ignore\n\n    collector = actions_collector.create_collector(config_name)\n    return (\n        lambda actions: collector(actions_filter(actions)),\n        lambda error: collector([])\n    )\n\n\nactions_manager = CodeActionsManager()\n\n\ndef get_matching_kinds(user_actions: Dict[str, bool], session_actions: List[str]) -> List[str]:\n    \"\"\"\n    Filters user-enabled or disabled actions so that only ones matching the session actions\n    are returned. Returned actions are those that are enabled and are not overridden by more\n    specific, disabled actions.\n\n    Filtering only returns actions that exactly match the ones supported by given session.\n    If user has enabled a generic action that matches more specific session action\n    (for example user's a.b matching session's a.b.c), then the more specific (a.b.c) must be\n    returned as servers must receive only actions that they advertise support for.\n    \"\"\"\n    matching_kinds = []\n    for session_action in session_actions:\n        enabled = False\n        action_parts = session_action.split('.')\n        for i in range(len(action_parts)):\n            current_part = '.'.join(action_parts[0:i + 1])\n            user_value = user_actions.get(current_part, None)\n            if isinstance(user_value, bool):\n                enabled = user_value\n        if enabled:\n            matching_kinds.append(session_action)\n    return matching_kinds\n\n\nclass CodeActionOnSaveTask(SaveTask):\n    \"\"\"\n    The main task that requests code actions from sessions and runs them.\n\n    The amount of time the task is allowed to run is defined by user-controlled setting. If the task\n    runs longer, the native save will be triggered before waiting for results.\n    \"\"\"\n    @classmethod\n    def is_applicable(cls, view: sublime.View) -> bool:\n        return bool(view.window()) and bool(cls._get_code_actions_on_save(view))\n\n    @classmethod\n    def _get_code_actions_on_save(cls, view: sublime.View) -> Dict[str, bool]:\n        view_code_actions = view.settings().get('lsp_code_actions_on_save') or {}\n        code_actions = userprefs().lsp_code_actions_on_save.copy()\n        code_actions.update(view_code_actions)\n        allowed_code_actions = dict()\n        for key, value in code_actions.items():\n            if key.startswith('source.'):\n                allowed_code_actions[key] = value\n        return allowed_code_actions\n\n    def get_task_timeout_ms(self) -> int:\n        return userprefs().code_action_on_save_timeout_ms\n\n    def run_async(self) -> None:\n        super().run_async()\n        self._request_code_actions_async()\n\n    def _request_code_actions_async(self) -> None:\n        self._purge_changes_async()\n        on_save_actions = self._get_code_actions_on_save(self._view)\n        actions_manager.request_on_save(self._view, self._handle_response_async, on_save_actions)\n\n    def _handle_response_async(self, responses: CodeActionsByConfigName) -> None:\n        if self._cancelled:\n            return\n        document_version = self._view.change_count()\n        tasks = []  # type: List[Promise]\n        for config_name, code_actions in responses.items():\n            if code_actions:\n                for session in sessions_for_view(self._view, 'codeActionProvider'):\n                    if session.config.name == config_name:\n                        for code_action in code_actions:\n                            tasks.append(session.run_code_action_async(code_action, progress=False))\n                        break\n        if document_version != self._view.change_count():\n            # Give on_text_changed_async a chance to trigger.\n            Promise.all(tasks).then(lambda _: sublime.set_timeout_async(self._request_code_actions_async))\n        else:\n            Promise.all(tasks).then(lambda _: sublime.set_timeout_async(self._on_complete))\n\n\nLspSaveCommand.register_task(CodeActionOnSaveTask)\n\n\nclass LspCodeActionsCommand(LspTextCommand):\n\n    capability = 'codeActionProvider'\n\n    def run(self, edit: sublime.Edit, event: Optional[dict] = None, only_kinds: Optional[List[str]] = None) -> None:\n        self.commands = []  # type: List[Tuple[str, str, CodeActionOrCommand]]\n        self.commands_by_config = {}  # type: CodeActionsByConfigName\n        view = self.view\n        try:\n            region = view.sel()[0]\n        except IndexError:\n            return\n        listener = windows.listener_for_view(view)\n        if not listener:\n            return\n        session_buffer_diagnostics, covering = listener.diagnostics_intersecting_async(region)\n        dict_kinds = {kind: True for kind in only_kinds} if only_kinds else None\n        actions_manager.request_for_region_async(\n            view, covering, session_buffer_diagnostics, self.handle_responses_async, dict_kinds)\n\n    def handle_responses_async(self, responses: CodeActionsByConfigName) -> None:\n        self.commands_by_config = responses\n        self.commands = self.combine_commands()\n        self.show_popup_menu()\n\n    def combine_commands(self) -> 'List[Tuple[str, str, CodeActionOrCommand]]':\n        results = []\n        for config, commands in self.commands_by_config.items():\n            for command in commands:\n                results.append((config, command['title'], command))\n        return results\n\n    def show_popup_menu(self) -> None:\n        if len(self.commands) > 0:\n            self.view.show_popup_menu([command[1] for command in self.commands], self.handle_select)\n        else:\n            self.view.show_popup('No actions available', sublime.HIDE_ON_MOUSE_MOVE_AWAY)\n\n    def handle_select(self, index: int) -> None:\n        if index > -1:\n\n            def run_async() -> None:\n                selected = self.commands[index]\n                session = self.session_by_name(selected[0])\n                if session:\n                    session.run_code_action_async(selected[2], progress=True)\n\n            sublime.set_timeout_async(run_async)\n", "path": "plugin/code_actions.py"}], "after_files": [{"content": "from .core.promise import Promise\nfrom .core.protocol import CodeAction\nfrom .core.protocol import Command\nfrom .core.protocol import Diagnostic\nfrom .core.protocol import Request\nfrom .core.registry import LspTextCommand\nfrom .core.registry import sessions_for_view\nfrom .core.registry import windows\nfrom .core.sessions import SessionBufferProtocol\nfrom .core.settings import userprefs\nfrom .core.typing import Any, List, Dict, Callable, Optional, Tuple, Union, Sequence\nfrom .core.views import entire_content_region\nfrom .core.views import text_document_code_action_params\nfrom .save_command import LspSaveCommand, SaveTask\nimport sublime\n\nCodeActionOrCommand = Union[CodeAction, Command]\nCodeActionsResponse = Optional[List[CodeActionOrCommand]]\nCodeActionsByConfigName = Dict[str, List[CodeActionOrCommand]]\n\n\nclass CodeActionsCollector:\n    \"\"\"\n    Collects code action responses from multiple sessions. Calls back the \"on_complete_handler\" with\n    results when all responses are received.\n\n    Usage example:\n\n    with CodeActionsCollector() as collector:\n        actions_manager.request_with_diagnostics(collector.create_collector('test_config'))\n        actions_manager.request_with_diagnostics(collector.create_collector('another_config'))\n\n    The \"create_collector()\" must only be called within the \"with\" context. Once the context is\n    exited, the \"on_complete_handler\" will be called once all the created collectors receive the\n    response (are called).\n    \"\"\"\n\n    def __init__(self, on_complete_handler: Callable[[CodeActionsByConfigName], None]):\n        self._on_complete_handler = on_complete_handler\n        self._commands_by_config = {}  # type: CodeActionsByConfigName\n        self._request_count = 0\n        self._response_count = 0\n        self._all_requested = False\n\n    def __enter__(self) -> 'CodeActionsCollector':\n        return self\n\n    def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:\n        self._all_requested = True\n        self._notify_if_all_finished()\n\n    def create_collector(self, config_name: str) -> Callable[[CodeActionsResponse], None]:\n        self._request_count += 1\n        return lambda actions: self._collect_response(config_name, actions)\n\n    def _collect_response(self, config_name: str, actions: CodeActionsResponse) -> None:\n        self._response_count += 1\n        self._commands_by_config[config_name] = actions or []\n        self._notify_if_all_finished()\n\n    def _notify_if_all_finished(self) -> None:\n        if self._all_requested and self._request_count == self._response_count:\n            # Call back on Sublime's async thread\n            sublime.set_timeout_async(lambda: self._on_complete_handler(self._commands_by_config))\n\n    def get_actions(self) -> CodeActionsByConfigName:\n        return self._commands_by_config\n\n\nclass CodeActionsManager:\n    \"\"\"Manager for per-location caching of code action responses.\"\"\"\n\n    def __init__(self) -> None:\n        self._response_cache = None  # type: Optional[Tuple[str, CodeActionsCollector]]\n\n    def request_with_diagnostics_async(\n        self,\n        view: sublime.View,\n        region: sublime.Region,\n        session_buffer_diagnostics: Sequence[Tuple[SessionBufferProtocol, Sequence[Diagnostic]]],\n        actions_handler: Callable[[CodeActionsByConfigName], None]\n    ) -> None:\n        \"\"\"\n        Requests code actions *only* for provided diagnostics. If session has no diagnostics then\n        it will be skipped.\n        \"\"\"\n        self._request_async(view, region, session_buffer_diagnostics, True, actions_handler)\n\n    def request_for_region_async(\n        self,\n        view: sublime.View,\n        region: sublime.Region,\n        session_buffer_diagnostics: Sequence[Tuple[SessionBufferProtocol, Sequence[Diagnostic]]],\n        actions_handler: Callable[[CodeActionsByConfigName], None],\n        only_kinds: Optional[Dict[str, bool]] = None\n    ) -> None:\n        \"\"\"\n        Requests code actions with provided diagnostics and specified region. If there are\n        no diagnostics for given session, the request will be made with empty diagnostics list.\n        \"\"\"\n        self._request_async(view, region, session_buffer_diagnostics, False, actions_handler, only_kinds)\n\n    def request_on_save(\n        self,\n        view: sublime.View,\n        actions_handler: Callable[[CodeActionsByConfigName], None],\n        on_save_actions: Dict[str, bool]\n    ) -> None:\n        \"\"\"\n        Requests code actions on save.\n        \"\"\"\n        self._request_async(view, entire_content_region(view), [], False, actions_handler, on_save_actions)\n\n    def _request_async(\n        self,\n        view: sublime.View,\n        region: sublime.Region,\n        session_buffer_diagnostics: Sequence[Tuple[SessionBufferProtocol, Sequence[Diagnostic]]],\n        only_with_diagnostics: bool,\n        actions_handler: Callable[[CodeActionsByConfigName], None],\n        on_save_actions: Optional[Dict[str, bool]] = None\n    ) -> None:\n        if 'codeActionProvider' in userprefs().disabled_capabilities:\n            return None\n\n        use_cache = on_save_actions is None\n        if use_cache:\n            location_cache_key = \"{}#{}:{}:{}\".format(\n                view.buffer_id(), view.change_count(), region, only_with_diagnostics)\n            if self._response_cache:\n                cache_key, cache_collector = self._response_cache\n                if location_cache_key == cache_key:\n                    sublime.set_timeout(lambda: actions_handler(cache_collector.get_actions()))\n                else:\n                    self._response_cache = None\n\n        collector = CodeActionsCollector(actions_handler)\n        with collector:\n            file_name = view.file_name()\n            if file_name:\n                for session in sessions_for_view(view, 'codeActionProvider'):\n                    if on_save_actions:\n                        supported_kinds = session.get_capability('codeActionProvider.codeActionKinds')\n                        matching_kinds = get_matching_kinds(on_save_actions, supported_kinds or [])\n                        if matching_kinds:\n                            params = text_document_code_action_params(\n                                view, file_name, region, [], matching_kinds)\n                            request = Request.codeAction(params, view)\n                            session.send_request_async(\n                                request, *filtering_collector(session.config.name, matching_kinds, collector))\n                    else:\n                        diagnostics = []  # type: Sequence[Diagnostic]\n                        for sb, diags in session_buffer_diagnostics:\n                            if sb.session == session:\n                                diagnostics = diags\n                                break\n                        if only_with_diagnostics and not diagnostics:\n                            continue\n                        params = text_document_code_action_params(view, file_name, region, diagnostics)\n                        request = Request.codeAction(params, view)\n                        session.send_request_async(request, collector.create_collector(session.config.name))\n        if use_cache:\n            self._response_cache = (location_cache_key, collector)\n\n\ndef filtering_collector(\n    config_name: str,\n    kinds: List[str],\n    actions_collector: CodeActionsCollector\n) -> Tuple[Callable[[CodeActionsResponse], None], Callable[[Any], None]]:\n    \"\"\"\n    Filters actions returned from the session so that only matching kinds are collected.\n\n    Since older servers don't support the \"context.only\" property, these will return all\n    actions that need to be filtered.\n    \"\"\"\n\n    def actions_filter(actions: CodeActionsResponse) -> List[CodeActionOrCommand]:\n        return [a for a in (actions or []) if a.get('kind') in kinds]  # type: ignore\n\n    collector = actions_collector.create_collector(config_name)\n    return (\n        lambda actions: collector(actions_filter(actions)),\n        lambda error: collector([])\n    )\n\n\nactions_manager = CodeActionsManager()\n\n\ndef get_matching_kinds(user_actions: Dict[str, bool], session_actions: List[str]) -> List[str]:\n    \"\"\"\n    Filters user-enabled or disabled actions so that only ones matching the session actions\n    are returned. Returned actions are those that are enabled and are not overridden by more\n    specific, disabled actions.\n\n    Filtering only returns actions that exactly match the ones supported by given session.\n    If user has enabled a generic action that matches more specific session action\n    (for example user's a.b matching session's a.b.c), then the more specific (a.b.c) must be\n    returned as servers must receive only actions that they advertise support for.\n    \"\"\"\n    matching_kinds = []\n    for session_action in session_actions:\n        enabled = False\n        action_parts = session_action.split('.')\n        for i in range(len(action_parts)):\n            current_part = '.'.join(action_parts[0:i + 1])\n            user_value = user_actions.get(current_part, None)\n            if isinstance(user_value, bool):\n                enabled = user_value\n        if enabled:\n            matching_kinds.append(session_action)\n    return matching_kinds\n\n\nclass CodeActionOnSaveTask(SaveTask):\n    \"\"\"\n    The main task that requests code actions from sessions and runs them.\n\n    The amount of time the task is allowed to run is defined by user-controlled setting. If the task\n    runs longer, the native save will be triggered before waiting for results.\n    \"\"\"\n    @classmethod\n    def is_applicable(cls, view: sublime.View) -> bool:\n        return bool(view.window()) and bool(cls._get_code_actions_on_save(view))\n\n    @classmethod\n    def _get_code_actions_on_save(cls, view: sublime.View) -> Dict[str, bool]:\n        view_code_actions = view.settings().get('lsp_code_actions_on_save') or {}\n        code_actions = userprefs().lsp_code_actions_on_save.copy()\n        code_actions.update(view_code_actions)\n        allowed_code_actions = dict()\n        for key, value in code_actions.items():\n            if key.startswith('source.'):\n                allowed_code_actions[key] = value\n        return allowed_code_actions\n\n    def get_task_timeout_ms(self) -> int:\n        return userprefs().code_action_on_save_timeout_ms\n\n    def run_async(self) -> None:\n        super().run_async()\n        self._request_code_actions_async()\n\n    def _request_code_actions_async(self) -> None:\n        self._purge_changes_async()\n        on_save_actions = self._get_code_actions_on_save(self._view)\n        actions_manager.request_on_save(self._view, self._handle_response_async, on_save_actions)\n\n    def _handle_response_async(self, responses: CodeActionsByConfigName) -> None:\n        if self._cancelled:\n            return\n        document_version = self._view.change_count()\n        tasks = []  # type: List[Promise]\n        for config_name, code_actions in responses.items():\n            if code_actions:\n                for session in sessions_for_view(self._view, 'codeActionProvider'):\n                    if session.config.name == config_name:\n                        for code_action in code_actions:\n                            tasks.append(session.run_code_action_async(code_action, progress=False))\n                        break\n        if document_version != self._view.change_count():\n            # Give on_text_changed_async a chance to trigger.\n            Promise.all(tasks).then(lambda _: sublime.set_timeout_async(self._request_code_actions_async))\n        else:\n            Promise.all(tasks).then(lambda _: sublime.set_timeout_async(self._on_complete))\n\n\nLspSaveCommand.register_task(CodeActionOnSaveTask)\n\n\nclass LspCodeActionsCommand(LspTextCommand):\n\n    capability = 'codeActionProvider'\n\n    def run(self, edit: sublime.Edit, event: Optional[dict] = None, only_kinds: Optional[List[str]] = None) -> None:\n        self.commands = []  # type: List[Tuple[str, str, CodeActionOrCommand]]\n        self.commands_by_config = {}  # type: CodeActionsByConfigName\n        view = self.view\n        try:\n            region = view.sel()[0]\n        except IndexError:\n            return\n        listener = windows.listener_for_view(view)\n        if not listener:\n            return\n        session_buffer_diagnostics, covering = listener.diagnostics_intersecting_async(region)\n        dict_kinds = {kind: True for kind in only_kinds} if only_kinds else None\n        actions_manager.request_for_region_async(\n            view, covering, session_buffer_diagnostics, self.handle_responses_async, dict_kinds)\n\n    def handle_responses_async(self, responses: CodeActionsByConfigName) -> None:\n        self.commands_by_config = responses\n        self.commands = self.combine_commands()\n        self.show_popup_menu()\n\n    def combine_commands(self) -> 'List[Tuple[str, str, CodeActionOrCommand]]':\n        results = []\n        for config, commands in self.commands_by_config.items():\n            for command in commands:\n                results.append((config, command['title'], command))\n        return results\n\n    def show_popup_menu(self) -> None:\n        if len(self.commands) > 0:\n            self.view.show_popup_menu([command[1] for command in self.commands], self.handle_select)\n        else:\n            self.view.show_popup('No actions available', sublime.HIDE_ON_MOUSE_MOVE_AWAY)\n\n    def handle_select(self, index: int) -> None:\n        if index > -1:\n\n            def run_async() -> None:\n                selected = self.commands[index]\n                session = self.session_by_name(selected[0])\n                if session:\n                    session.run_code_action_async(selected[2], progress=True)\n\n            sublime.set_timeout_async(run_async)\n", "path": "plugin/code_actions.py"}]}