We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Provide an optional response handler in LspExecuteCommand
**Is your feature request related to a problem? Please describe.**
I would like to extends `LspExecuteCommand` in order to send a `workspace/executeCommand` but `LspExecuteCommand` simply [logs](https://github.com/sublimelsp/LSP/blob/acfd6406ba4680a0e537dc87a72aa5b410a154e7/plugin/execute_command.py#L47) the response. In my case I have to open a file URI that is in the reponse.

**Describe the solution you'd like**
`LspExecuteCommand` should provide an optional response handler. When missing simply log the response as the case now. Otherwise delegate the response handling. 

**Describe alternatives you've considered**
The current alternative is to copy `LspExecuteCommand` logic.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `boot.py`
Content:
```
1 import os
2 import sublime
3 import sublime_plugin
4 
5 # Please keep this list sorted (Edit -> Sort Lines)
6 from .plugin.code_actions import LspCodeActionsCommand
7 from .plugin.code_lens import LspCodeLensCommand
8 from .plugin.completion import LspResolveDocsCommand
9 from .plugin.completion import LspSelectCompletionItemCommand
10 from .plugin.configuration import LspDisableLanguageServerGloballyCommand
11 from .plugin.configuration import LspDisableLanguageServerInProjectCommand
12 from .plugin.configuration import LspEnableLanguageServerGloballyCommand
13 from .plugin.configuration import LspEnableLanguageServerInProjectCommand
14 from .plugin.core.collections import DottedDict
15 from .plugin.core.css import load as load_css
16 from .plugin.core.logging import exception_log
17 from .plugin.core.open import opening_files
18 from .plugin.core.panels import destroy_output_panels
19 from .plugin.core.panels import LspClearPanelCommand
20 from .plugin.core.panels import LspUpdatePanelCommand
21 from .plugin.core.panels import LspUpdateServerPanelCommand
22 from .plugin.core.panels import WindowPanelListener
23 from .plugin.core.protocol import Location
24 from .plugin.core.registry import LspRecheckSessionsCommand
25 from .plugin.core.registry import LspRestartServerCommand
26 from .plugin.core.registry import windows
27 from .plugin.core.sessions import AbstractPlugin
28 from .plugin.core.sessions import register_plugin
29 from .plugin.core.settings import client_configs
30 from .plugin.core.settings import load_settings
31 from .plugin.core.settings import unload_settings
32 from .plugin.core.signature_help import LspSignatureHelpNavigateCommand
33 from .plugin.core.signature_help import LspSignatureHelpShowCommand
34 from .plugin.core.transports import kill_all_subprocesses
35 from .plugin.core.typing import Any, Optional, List, Type, Dict
36 from .plugin.core.views import get_uri_and_position_from_location
37 from .plugin.core.views import LspRunTextCommandHelperCommand
38 from .plugin.document_link import LspOpenLinkCommand
39 from .plugin.documents import DocumentSyncListener
40 from .plugin.documents import TextChangeListener
41 from .plugin.edit import LspApplyDocumentEditCommand
42 from .plugin.execute_command import LspExecuteCommand
43 from .plugin.formatting import LspFormatDocumentCommand
44 from .plugin.formatting import LspFormatDocumentRangeCommand
45 from .plugin.goto import LspSymbolDeclarationCommand
46 from .plugin.goto import LspSymbolDefinitionCommand
47 from .plugin.goto import LspSymbolImplementationCommand
48 from .plugin.goto import LspSymbolTypeDefinitionCommand
49 from .plugin.goto_diagnostic import LspGotoDiagnosticCommand
50 from .plugin.hover import LspHoverCommand
51 from .plugin.inlay_hint import LspInlayHintClickCommand
52 from .plugin.panels import LspShowDiagnosticsPanelCommand
53 from .plugin.panels import LspToggleServerPanelCommand
54 from .plugin.references import LspSymbolReferencesCommand
55 from .plugin.rename import LspSymbolRenameCommand
56 from .plugin.save_command import LspSaveAllCommand
57 from .plugin.save_command import LspSaveCommand
58 from .plugin.selection_range import LspExpandSelectionCommand
59 from .plugin.semantic_highlighting import LspShowScopeNameCommand
60 from .plugin.symbols import LspDocumentSymbolsCommand
61 from .plugin.symbols import LspSelectionAddCommand
62 from .plugin.symbols import LspSelectionClearCommand
63 from .plugin.symbols import LspSelectionSetCommand
64 from .plugin.symbols import LspWorkspaceSymbolsCommand
65 from .plugin.tooling import LspCopyToClipboardFromBase64Command
66 from .plugin.tooling import LspDumpBufferCapabilities
67 from .plugin.tooling import LspDumpWindowConfigs
68 from .plugin.tooling import LspParseVscodePackageJson
69 from .plugin.tooling import LspTroubleshootServerCommand
70 
71 
72 def _get_final_subclasses(derived: List[Type], results: List[Type]) -> None:
73     for d in derived:
74         d_subclasses = d.__subclasses__()
75         if len(d_subclasses) > 0:
76             _get_final_subclasses(d_subclasses, results)
77         else:
78             results.append(d)
79 
80 
81 def _register_all_plugins() -> None:
82     plugin_classes = []  # type: List[Type[AbstractPlugin]]
83     _get_final_subclasses(AbstractPlugin.__subclasses__(), plugin_classes)
84     for plugin_class in plugin_classes:
85         try:
86             if not plugin_class.name():
87                 continue
88         except NotImplementedError:
89             continue
90         register_plugin(plugin_class, notify_listener=False)
91 
92 
93 def _unregister_all_plugins() -> None:
94     from LSP.plugin.core.sessions import _plugins
95     _plugins.clear()
96     client_configs.external.clear()
97     client_configs.all.clear()
98 
99 
100 def plugin_loaded() -> None:
101     load_settings()
102     load_css()
103     _register_all_plugins()
104     client_configs.update_configs()
105     for window in sublime.windows():
106         windows.lookup(window)
107 
108 
109 def plugin_unloaded() -> None:
110     _unregister_all_plugins()
111     for window in sublime.windows():
112         destroy_output_panels(window)  # references and diagnostics panels
113         try:
114             windows.lookup(window).plugin_unloaded()
115             windows.discard(window)
116         except Exception as ex:
117             exception_log("failed to unload window", ex)
118     unload_settings()
119 
120 
121 class Listener(sublime_plugin.EventListener):
122 
123     def on_exit(self) -> None:
124         kill_all_subprocesses()
125 
126     def on_load_project_async(self, w: sublime.Window) -> None:
127         windows.lookup(w).on_load_project_async()
128 
129     def on_post_save_project_async(self, w: sublime.Window) -> None:
130         windows.lookup(w).on_post_save_project_async()
131 
132     def on_new_window_async(self, w: sublime.Window) -> None:
133         sublime.set_timeout(lambda: windows.lookup(w))
134 
135     def on_pre_close_window(self, w: sublime.Window) -> None:
136         windows.discard(w)
137 
138     # Note: EventListener.on_post_move_async does not fire when a tab is moved out of the current window in such a way
139     # that a new window is created: https://github.com/sublimehq/sublime_text/issues/4630
140     # Hence, as a workaround we use on_pre_move, which still works in that case.
141     def on_pre_move(self, view: sublime.View) -> None:
142         listeners = sublime_plugin.view_event_listeners.get(view.id())
143         if not isinstance(listeners, list):
144             return
145         for listener in listeners:
146             if isinstance(listener, DocumentSyncListener):
147                 # we need a small delay here, so that the DocumentSyncListener will recognize a possible new window
148                 sublime.set_timeout_async(listener.on_post_move_window_async, timeout_ms=1)
149                 return
150 
151     def on_load(self, view: sublime.View) -> None:
152         file_name = view.file_name()
153         if not file_name:
154             return
155         for fn in opening_files.keys():
156             if fn == file_name or os.path.samefile(fn, file_name):
157                 # Remove it from the pending opening files, and resolve the promise.
158                 opening_files.pop(fn)[1](view)
159                 break
160 
161     def on_pre_close(self, view: sublime.View) -> None:
162         file_name = view.file_name()
163         if not file_name:
164             return
165         for fn in opening_files.keys():
166             if fn == file_name or os.path.samefile(fn, file_name):
167                 tup = opening_files.pop(fn, None)
168                 if tup:
169                     # The view got closed before it finished loading. This can happen.
170                     tup[1](None)
171                     break
172 
173     def on_post_window_command(self, window: sublime.Window, command_name: str, args: Optional[Dict[str, Any]]) -> None:
174         if command_name in ("next_result", "prev_result"):
175             view = window.active_view()
176             if view:
177                 view.run_command("lsp_hover", {"only_diagnostics": True})
178 
179 
180 class LspOpenLocationCommand(sublime_plugin.TextCommand):
181     """
182     A command to be used by third-party ST packages that need to open an URI with some abstract scheme.
183     """
184 
185     def run(
186         self,
187         _: sublime.Edit,
188         location: Location,
189         session_name: Optional[str] = None,
190         flags: int = 0,
191         group: int = -1
192     ) -> None:
193         sublime.set_timeout_async(lambda: self._run_async(location, session_name, flags, group))
194 
195     def _run_async(self, location: Location, session_name: Optional[str], flags: int = 0, group: int = -1) -> None:
196         window = self.view.window()
197         if not window:
198             return
199         windows.lookup(window).open_location_async(location, session_name, self.view, flags, group).then(
200             lambda success: self._handle_continuation(location, success))
201 
202     def _handle_continuation(self, location: Location, success: bool) -> None:
203         if not success:
204             uri, _ = get_uri_and_position_from_location(location)
205             message = "Failed to open {}".format(uri)
206             sublime.status_message(message)
207
```

Path: `plugin/execute_command.py`
Content:
```
1 import sublime
2 from .core.protocol import Error
3 from .core.protocol import ExecuteCommandParams
4 from .core.registry import LspTextCommand
5 from .core.registry import windows
6 from .core.typing import List, Optional, Any
7 from .core.views import first_selection_region
8 from .core.views import uri_from_view, offset_to_point, region_to_range, text_document_identifier
9 
10 
11 class LspExecuteCommand(LspTextCommand):
12 
13     def run(self,
14             edit: sublime.Edit,
15             command_name: Optional[str] = None,
16             command_args: Optional[List[Any]] = None,
17             session_name: Optional[str] = None,
18             event: Optional[dict] = None) -> None:
19         # Handle VSCode-specific command for triggering AC/sighelp
20         if command_name == "editor.action.triggerSuggest":
21             # Triggered from set_timeout as suggestions popup doesn't trigger otherwise.
22             return sublime.set_timeout(lambda: self.view.run_command("auto_complete"))
23         if command_name == "editor.action.triggerParameterHints":
24 
25             def run_async() -> None:
26                 listener = windows.listener_for_view(self.view)
27                 if listener:
28                     listener.do_signature_help_async(manual=False)
29 
30             return sublime.set_timeout_async(run_async)
31         session = self.session_by_name(session_name if session_name else self.session_name)
32         if session and command_name:
33             params = {"command": command_name}  # type: ExecuteCommandParams
34             if command_args:
35                 params["arguments"] = self._expand_variables(command_args)
36 
37             def handle_response(response: Any) -> None:
38                 assert command_name
39                 if isinstance(response, Error):
40                     sublime.message_dialog("command {} failed. Reason: {}".format(command_name, str(response)))
41                     return
42                 msg = "command {} completed".format(command_name)
43                 if response:
44                     msg += "with response: {}".format(response)
45                 window = self.view.window()
46                 if window:
47                     window.status_message(msg)
48 
49             session.execute_command(params, progress=True).then(handle_response)
50 
51     def _expand_variables(self, command_args: List[Any]) -> List[Any]:
52         view = self.view  # type: sublime.View
53         region = first_selection_region(view)
54         for i, arg in enumerate(command_args):
55             if arg in ["$document_id", "${document_id}"]:
56                 command_args[i] = text_document_identifier(view)
57             elif arg in ["$file_uri", "${file_uri}"]:
58                 command_args[i] = uri_from_view(view)
59             elif region is not None:
60                 if arg in ["$selection", "${selection}"]:
61                     command_args[i] = view.substr(region)
62                 elif arg in ["$offset", "${offset}"]:
63                     command_args[i] = region.b
64                 elif arg in ["$selection_begin", "${selection_begin}"]:
65                     command_args[i] = region.begin()
66                 elif arg in ["$selection_end", "${selection_end}"]:
67                     command_args[i] = region.end()
68                 elif arg in ["$position", "${position}"]:
69                     command_args[i] = offset_to_point(view, region.b).to_lsp()
70                 elif arg in ["$range", "${range}"]:
71                     command_args[i] = region_to_range(view, region).to_lsp()
72         window = view.window()
73         window_variables = window.extract_variables() if window else {}
74         return sublime.expand_variables(command_args, window_variables)
75
```
--- 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/boot.py b/boot.py
--- a/boot.py
+++ b/boot.py
@@ -20,6 +20,7 @@
 from .plugin.core.panels import LspUpdatePanelCommand
 from .plugin.core.panels import LspUpdateServerPanelCommand
 from .plugin.core.panels import WindowPanelListener
+from .plugin.core.protocol import Error
 from .plugin.core.protocol import Location
 from .plugin.core.registry import LspRecheckSessionsCommand
 from .plugin.core.registry import LspRestartServerCommand
diff --git a/plugin/execute_command.py b/plugin/execute_command.py
--- a/plugin/execute_command.py
+++ b/plugin/execute_command.py
@@ -9,6 +9,9 @@
 
 
 class LspExecuteCommand(LspTextCommand):
+    """
+    Helper command for triggering workspace/executeCommand requests.
+    """
 
     def run(self,
             edit: sublime.Edit,
@@ -37,17 +40,33 @@
             def handle_response(response: Any) -> None:
                 assert command_name
                 if isinstance(response, Error):
-                    sublime.message_dialog("command {} failed. Reason: {}".format(command_name, str(response)))
+                    self.handle_error_async(response, command_name)
                     return
-                msg = "command {} completed".format(command_name)
-                if response:
-                    msg += "with response: {}".format(response)
-                window = self.view.window()
-                if window:
-                    window.status_message(msg)
+                self.handle_success_async(response, command_name)
 
             session.execute_command(params, progress=True).then(handle_response)
 
+    def handle_success_async(self, result: Any, command_name: str) -> None:
+        """
+        Override this method to handle successful response to workspace/executeCommand.
+
+        :param result: The result returned from the server.
+        :param command_name: The name of the command that was executed.
+        """
+        msg = "command {} completed".format(command_name)
+        window = self.view.window()
+        if window:
+            window.status_message(msg)
+
+    def handle_error_async(self, error: Error, command_name: str) -> None:
+        """
+        Override this method to handle failed response to workspace/executeCommand.
+
+        :param error: The Error object.
+        :param command_name: The name of the command that was executed.
+        """
+        sublime.message_dialog("command {} failed. Reason: {}".format(command_name, str(error)))
+
     def _expand_variables(self, command_args: List[Any]) -> List[Any]:
         view = self.view  # type: sublime.View
         region = first_selection_region(view)

{"golden_diff": "diff --git a/boot.py b/boot.py\n--- a/boot.py\n+++ b/boot.py\n@@ -20,6 +20,7 @@\n from .plugin.core.panels import LspUpdatePanelCommand\n from .plugin.core.panels import LspUpdateServerPanelCommand\n from .plugin.core.panels import WindowPanelListener\n+from .plugin.core.protocol import Error\n from .plugin.core.protocol import Location\n from .plugin.core.registry import LspRecheckSessionsCommand\n from .plugin.core.registry import LspRestartServerCommand\ndiff --git a/plugin/execute_command.py b/plugin/execute_command.py\n--- a/plugin/execute_command.py\n+++ b/plugin/execute_command.py\n@@ -9,6 +9,9 @@\n \n \n class LspExecuteCommand(LspTextCommand):\n+    \"\"\"\n+    Helper command for triggering workspace/executeCommand requests.\n+    \"\"\"\n \n     def run(self,\n             edit: sublime.Edit,\n@@ -37,17 +40,33 @@\n             def handle_response(response: Any) -> None:\n                 assert command_name\n                 if isinstance(response, Error):\n-                    sublime.message_dialog(\"command {} failed. Reason: {}\".format(command_name, str(response)))\n+                    self.handle_error_async(response, command_name)\n                     return\n-                msg = \"command {} completed\".format(command_name)\n-                if response:\n-                    msg += \"with response: {}\".format(response)\n-                window = self.view.window()\n-                if window:\n-                    window.status_message(msg)\n+                self.handle_success_async(response, command_name)\n \n             session.execute_command(params, progress=True).then(handle_response)\n \n+    def handle_success_async(self, result: Any, command_name: str) -> None:\n+        \"\"\"\n+        Override this method to handle successful response to workspace/executeCommand.\n+\n+        :param result: The result returned from the server.\n+        :param command_name: The name of the command that was executed.\n+        \"\"\"\n+        msg = \"command {} completed\".format(command_name)\n+        window = self.view.window()\n+        if window:\n+            window.status_message(msg)\n+\n+    def handle_error_async(self, error: Error, command_name: str) -> None:\n+        \"\"\"\n+        Override this method to handle failed response to workspace/executeCommand.\n+\n+        :param error: The Error object.\n+        :param command_name: The name of the command that was executed.\n+        \"\"\"\n+        sublime.message_dialog(\"command {} failed. Reason: {}\".format(command_name, str(error)))\n+\n     def _expand_variables(self, command_args: List[Any]) -> List[Any]:\n         view = self.view  # type: sublime.View\n         region = first_selection_region(view)\n", "issue": "Provide an optional response handler in LspExecuteCommand\n**Is your feature request related to a problem? Please describe.**\r\nI would like to extends `LspExecuteCommand` in order to send a `workspace/executeCommand` but `LspExecuteCommand` simply [logs](https://github.com/sublimelsp/LSP/blob/acfd6406ba4680a0e537dc87a72aa5b410a154e7/plugin/execute_command.py#L47) the response. In my case I have to open a file URI that is in the reponse.\r\n\r\n**Describe the solution you'd like**\r\n`LspExecuteCommand` should provide an optional response handler. When missing simply log the response as the case now. Otherwise delegate the response handling. \r\n\r\n**Describe alternatives you've considered**\r\nThe current alternative is to copy `LspExecuteCommand` logic.\r\n\n", "before_files": [{"content": "import os\nimport sublime\nimport sublime_plugin\n\n# Please keep this list sorted (Edit -> Sort Lines)\nfrom .plugin.code_actions import LspCodeActionsCommand\nfrom .plugin.code_lens import LspCodeLensCommand\nfrom .plugin.completion import LspResolveDocsCommand\nfrom .plugin.completion import LspSelectCompletionItemCommand\nfrom .plugin.configuration import LspDisableLanguageServerGloballyCommand\nfrom .plugin.configuration import LspDisableLanguageServerInProjectCommand\nfrom .plugin.configuration import LspEnableLanguageServerGloballyCommand\nfrom .plugin.configuration import LspEnableLanguageServerInProjectCommand\nfrom .plugin.core.collections import DottedDict\nfrom .plugin.core.css import load as load_css\nfrom .plugin.core.logging import exception_log\nfrom .plugin.core.open import opening_files\nfrom .plugin.core.panels import destroy_output_panels\nfrom .plugin.core.panels import LspClearPanelCommand\nfrom .plugin.core.panels import LspUpdatePanelCommand\nfrom .plugin.core.panels import LspUpdateServerPanelCommand\nfrom .plugin.core.panels import WindowPanelListener\nfrom .plugin.core.protocol import Location\nfrom .plugin.core.registry import LspRecheckSessionsCommand\nfrom .plugin.core.registry import LspRestartServerCommand\nfrom .plugin.core.registry import windows\nfrom .plugin.core.sessions import AbstractPlugin\nfrom .plugin.core.sessions import register_plugin\nfrom .plugin.core.settings import client_configs\nfrom .plugin.core.settings import load_settings\nfrom .plugin.core.settings import unload_settings\nfrom .plugin.core.signature_help import LspSignatureHelpNavigateCommand\nfrom .plugin.core.signature_help import LspSignatureHelpShowCommand\nfrom .plugin.core.transports import kill_all_subprocesses\nfrom .plugin.core.typing import Any, Optional, List, Type, Dict\nfrom .plugin.core.views import get_uri_and_position_from_location\nfrom .plugin.core.views import LspRunTextCommandHelperCommand\nfrom .plugin.document_link import LspOpenLinkCommand\nfrom .plugin.documents import DocumentSyncListener\nfrom .plugin.documents import TextChangeListener\nfrom .plugin.edit import LspApplyDocumentEditCommand\nfrom .plugin.execute_command import LspExecuteCommand\nfrom .plugin.formatting import LspFormatDocumentCommand\nfrom .plugin.formatting import LspFormatDocumentRangeCommand\nfrom .plugin.goto import LspSymbolDeclarationCommand\nfrom .plugin.goto import LspSymbolDefinitionCommand\nfrom .plugin.goto import LspSymbolImplementationCommand\nfrom .plugin.goto import LspSymbolTypeDefinitionCommand\nfrom .plugin.goto_diagnostic import LspGotoDiagnosticCommand\nfrom .plugin.hover import LspHoverCommand\nfrom .plugin.inlay_hint import LspInlayHintClickCommand\nfrom .plugin.panels import LspShowDiagnosticsPanelCommand\nfrom .plugin.panels import LspToggleServerPanelCommand\nfrom .plugin.references import LspSymbolReferencesCommand\nfrom .plugin.rename import LspSymbolRenameCommand\nfrom .plugin.save_command import LspSaveAllCommand\nfrom .plugin.save_command import LspSaveCommand\nfrom .plugin.selection_range import LspExpandSelectionCommand\nfrom .plugin.semantic_highlighting import LspShowScopeNameCommand\nfrom .plugin.symbols import LspDocumentSymbolsCommand\nfrom .plugin.symbols import LspSelectionAddCommand\nfrom .plugin.symbols import LspSelectionClearCommand\nfrom .plugin.symbols import LspSelectionSetCommand\nfrom .plugin.symbols import LspWorkspaceSymbolsCommand\nfrom .plugin.tooling import LspCopyToClipboardFromBase64Command\nfrom .plugin.tooling import LspDumpBufferCapabilities\nfrom .plugin.tooling import LspDumpWindowConfigs\nfrom .plugin.tooling import LspParseVscodePackageJson\nfrom .plugin.tooling import LspTroubleshootServerCommand\n\n\ndef _get_final_subclasses(derived: List[Type], results: List[Type]) -> None:\n    for d in derived:\n        d_subclasses = d.__subclasses__()\n        if len(d_subclasses) > 0:\n            _get_final_subclasses(d_subclasses, results)\n        else:\n            results.append(d)\n\n\ndef _register_all_plugins() -> None:\n    plugin_classes = []  # type: List[Type[AbstractPlugin]]\n    _get_final_subclasses(AbstractPlugin.__subclasses__(), plugin_classes)\n    for plugin_class in plugin_classes:\n        try:\n            if not plugin_class.name():\n                continue\n        except NotImplementedError:\n            continue\n        register_plugin(plugin_class, notify_listener=False)\n\n\ndef _unregister_all_plugins() -> None:\n    from LSP.plugin.core.sessions import _plugins\n    _plugins.clear()\n    client_configs.external.clear()\n    client_configs.all.clear()\n\n\ndef plugin_loaded() -> None:\n    load_settings()\n    load_css()\n    _register_all_plugins()\n    client_configs.update_configs()\n    for window in sublime.windows():\n        windows.lookup(window)\n\n\ndef plugin_unloaded() -> None:\n    _unregister_all_plugins()\n    for window in sublime.windows():\n        destroy_output_panels(window)  # references and diagnostics panels\n        try:\n            windows.lookup(window).plugin_unloaded()\n            windows.discard(window)\n        except Exception as ex:\n            exception_log(\"failed to unload window\", ex)\n    unload_settings()\n\n\nclass Listener(sublime_plugin.EventListener):\n\n    def on_exit(self) -> None:\n        kill_all_subprocesses()\n\n    def on_load_project_async(self, w: sublime.Window) -> None:\n        windows.lookup(w).on_load_project_async()\n\n    def on_post_save_project_async(self, w: sublime.Window) -> None:\n        windows.lookup(w).on_post_save_project_async()\n\n    def on_new_window_async(self, w: sublime.Window) -> None:\n        sublime.set_timeout(lambda: windows.lookup(w))\n\n    def on_pre_close_window(self, w: sublime.Window) -> None:\n        windows.discard(w)\n\n    # Note: EventListener.on_post_move_async does not fire when a tab is moved out of the current window in such a way\n    # that a new window is created: https://github.com/sublimehq/sublime_text/issues/4630\n    # Hence, as a workaround we use on_pre_move, which still works in that case.\n    def on_pre_move(self, view: sublime.View) -> None:\n        listeners = sublime_plugin.view_event_listeners.get(view.id())\n        if not isinstance(listeners, list):\n            return\n        for listener in listeners:\n            if isinstance(listener, DocumentSyncListener):\n                # we need a small delay here, so that the DocumentSyncListener will recognize a possible new window\n                sublime.set_timeout_async(listener.on_post_move_window_async, timeout_ms=1)\n                return\n\n    def on_load(self, view: sublime.View) -> None:\n        file_name = view.file_name()\n        if not file_name:\n            return\n        for fn in opening_files.keys():\n            if fn == file_name or os.path.samefile(fn, file_name):\n                # Remove it from the pending opening files, and resolve the promise.\n                opening_files.pop(fn)[1](view)\n                break\n\n    def on_pre_close(self, view: sublime.View) -> None:\n        file_name = view.file_name()\n        if not file_name:\n            return\n        for fn in opening_files.keys():\n            if fn == file_name or os.path.samefile(fn, file_name):\n                tup = opening_files.pop(fn, None)\n                if tup:\n                    # The view got closed before it finished loading. This can happen.\n                    tup[1](None)\n                    break\n\n    def on_post_window_command(self, window: sublime.Window, command_name: str, args: Optional[Dict[str, Any]]) -> None:\n        if command_name in (\"next_result\", \"prev_result\"):\n            view = window.active_view()\n            if view:\n                view.run_command(\"lsp_hover\", {\"only_diagnostics\": True})\n\n\nclass LspOpenLocationCommand(sublime_plugin.TextCommand):\n    \"\"\"\n    A command to be used by third-party ST packages that need to open an URI with some abstract scheme.\n    \"\"\"\n\n    def run(\n        self,\n        _: sublime.Edit,\n        location: Location,\n        session_name: Optional[str] = None,\n        flags: int = 0,\n        group: int = -1\n    ) -> None:\n        sublime.set_timeout_async(lambda: self._run_async(location, session_name, flags, group))\n\n    def _run_async(self, location: Location, session_name: Optional[str], flags: int = 0, group: int = -1) -> None:\n        window = self.view.window()\n        if not window:\n            return\n        windows.lookup(window).open_location_async(location, session_name, self.view, flags, group).then(\n            lambda success: self._handle_continuation(location, success))\n\n    def _handle_continuation(self, location: Location, success: bool) -> None:\n        if not success:\n            uri, _ = get_uri_and_position_from_location(location)\n            message = \"Failed to open {}\".format(uri)\n            sublime.status_message(message)\n", "path": "boot.py"}, {"content": "import sublime\nfrom .core.protocol import Error\nfrom .core.protocol import ExecuteCommandParams\nfrom .core.registry import LspTextCommand\nfrom .core.registry import windows\nfrom .core.typing import List, Optional, Any\nfrom .core.views import first_selection_region\nfrom .core.views import uri_from_view, offset_to_point, region_to_range, text_document_identifier\n\n\nclass LspExecuteCommand(LspTextCommand):\n\n    def run(self,\n            edit: sublime.Edit,\n            command_name: Optional[str] = None,\n            command_args: Optional[List[Any]] = None,\n            session_name: Optional[str] = None,\n            event: Optional[dict] = None) -> None:\n        # Handle VSCode-specific command for triggering AC/sighelp\n        if command_name == \"editor.action.triggerSuggest\":\n            # Triggered from set_timeout as suggestions popup doesn't trigger otherwise.\n            return sublime.set_timeout(lambda: self.view.run_command(\"auto_complete\"))\n        if command_name == \"editor.action.triggerParameterHints\":\n\n            def run_async() -> None:\n                listener = windows.listener_for_view(self.view)\n                if listener:\n                    listener.do_signature_help_async(manual=False)\n\n            return sublime.set_timeout_async(run_async)\n        session = self.session_by_name(session_name if session_name else self.session_name)\n        if session and command_name:\n            params = {\"command\": command_name}  # type: ExecuteCommandParams\n            if command_args:\n                params[\"arguments\"] = self._expand_variables(command_args)\n\n            def handle_response(response: Any) -> None:\n                assert command_name\n                if isinstance(response, Error):\n                    sublime.message_dialog(\"command {} failed. Reason: {}\".format(command_name, str(response)))\n                    return\n                msg = \"command {} completed\".format(command_name)\n                if response:\n                    msg += \"with response: {}\".format(response)\n                window = self.view.window()\n                if window:\n                    window.status_message(msg)\n\n            session.execute_command(params, progress=True).then(handle_response)\n\n    def _expand_variables(self, command_args: List[Any]) -> List[Any]:\n        view = self.view  # type: sublime.View\n        region = first_selection_region(view)\n        for i, arg in enumerate(command_args):\n            if arg in [\"$document_id\", \"${document_id}\"]:\n                command_args[i] = text_document_identifier(view)\n            elif arg in [\"$file_uri\", \"${file_uri}\"]:\n                command_args[i] = uri_from_view(view)\n            elif region is not None:\n                if arg in [\"$selection\", \"${selection}\"]:\n                    command_args[i] = view.substr(region)\n                elif arg in [\"$offset\", \"${offset}\"]:\n                    command_args[i] = region.b\n                elif arg in [\"$selection_begin\", \"${selection_begin}\"]:\n                    command_args[i] = region.begin()\n                elif arg in [\"$selection_end\", \"${selection_end}\"]:\n                    command_args[i] = region.end()\n                elif arg in [\"$position\", \"${position}\"]:\n                    command_args[i] = offset_to_point(view, region.b).to_lsp()\n                elif arg in [\"$range\", \"${range}\"]:\n                    command_args[i] = region_to_range(view, region).to_lsp()\n        window = view.window()\n        window_variables = window.extract_variables() if window else {}\n        return sublime.expand_variables(command_args, window_variables)\n", "path": "plugin/execute_command.py"}], "after_files": [{"content": "import os\nimport sublime\nimport sublime_plugin\n\n# Please keep this list sorted (Edit -> Sort Lines)\nfrom .plugin.code_actions import LspCodeActionsCommand\nfrom .plugin.code_lens import LspCodeLensCommand\nfrom .plugin.completion import LspResolveDocsCommand\nfrom .plugin.completion import LspSelectCompletionItemCommand\nfrom .plugin.configuration import LspDisableLanguageServerGloballyCommand\nfrom .plugin.configuration import LspDisableLanguageServerInProjectCommand\nfrom .plugin.configuration import LspEnableLanguageServerGloballyCommand\nfrom .plugin.configuration import LspEnableLanguageServerInProjectCommand\nfrom .plugin.core.collections import DottedDict\nfrom .plugin.core.css import load as load_css\nfrom .plugin.core.logging import exception_log\nfrom .plugin.core.open import opening_files\nfrom .plugin.core.panels import destroy_output_panels\nfrom .plugin.core.panels import LspClearPanelCommand\nfrom .plugin.core.panels import LspUpdatePanelCommand\nfrom .plugin.core.panels import LspUpdateServerPanelCommand\nfrom .plugin.core.panels import WindowPanelListener\nfrom .plugin.core.protocol import Error\nfrom .plugin.core.protocol import Location\nfrom .plugin.core.registry import LspRecheckSessionsCommand\nfrom .plugin.core.registry import LspRestartServerCommand\nfrom .plugin.core.registry import windows\nfrom .plugin.core.sessions import AbstractPlugin\nfrom .plugin.core.sessions import register_plugin\nfrom .plugin.core.settings import client_configs\nfrom .plugin.core.settings import load_settings\nfrom .plugin.core.settings import unload_settings\nfrom .plugin.core.signature_help import LspSignatureHelpNavigateCommand\nfrom .plugin.core.signature_help import LspSignatureHelpShowCommand\nfrom .plugin.core.transports import kill_all_subprocesses\nfrom .plugin.core.typing import Any, Optional, List, Type, Dict\nfrom .plugin.core.views import get_uri_and_position_from_location\nfrom .plugin.core.views import LspRunTextCommandHelperCommand\nfrom .plugin.document_link import LspOpenLinkCommand\nfrom .plugin.documents import DocumentSyncListener\nfrom .plugin.documents import TextChangeListener\nfrom .plugin.edit import LspApplyDocumentEditCommand\nfrom .plugin.execute_command import LspExecuteCommand\nfrom .plugin.formatting import LspFormatDocumentCommand\nfrom .plugin.formatting import LspFormatDocumentRangeCommand\nfrom .plugin.goto import LspSymbolDeclarationCommand\nfrom .plugin.goto import LspSymbolDefinitionCommand\nfrom .plugin.goto import LspSymbolImplementationCommand\nfrom .plugin.goto import LspSymbolTypeDefinitionCommand\nfrom .plugin.goto_diagnostic import LspGotoDiagnosticCommand\nfrom .plugin.hover import LspHoverCommand\nfrom .plugin.inlay_hint import LspInlayHintClickCommand\nfrom .plugin.panels import LspShowDiagnosticsPanelCommand\nfrom .plugin.panels import LspToggleServerPanelCommand\nfrom .plugin.references import LspSymbolReferencesCommand\nfrom .plugin.rename import LspSymbolRenameCommand\nfrom .plugin.save_command import LspSaveAllCommand\nfrom .plugin.save_command import LspSaveCommand\nfrom .plugin.selection_range import LspExpandSelectionCommand\nfrom .plugin.semantic_highlighting import LspShowScopeNameCommand\nfrom .plugin.symbols import LspDocumentSymbolsCommand\nfrom .plugin.symbols import LspSelectionAddCommand\nfrom .plugin.symbols import LspSelectionClearCommand\nfrom .plugin.symbols import LspSelectionSetCommand\nfrom .plugin.symbols import LspWorkspaceSymbolsCommand\nfrom .plugin.tooling import LspCopyToClipboardFromBase64Command\nfrom .plugin.tooling import LspDumpBufferCapabilities\nfrom .plugin.tooling import LspDumpWindowConfigs\nfrom .plugin.tooling import LspParseVscodePackageJson\nfrom .plugin.tooling import LspTroubleshootServerCommand\n\n\ndef _get_final_subclasses(derived: List[Type], results: List[Type]) -> None:\n    for d in derived:\n        d_subclasses = d.__subclasses__()\n        if len(d_subclasses) > 0:\n            _get_final_subclasses(d_subclasses, results)\n        else:\n            results.append(d)\n\n\ndef _register_all_plugins() -> None:\n    plugin_classes = []  # type: List[Type[AbstractPlugin]]\n    _get_final_subclasses(AbstractPlugin.__subclasses__(), plugin_classes)\n    for plugin_class in plugin_classes:\n        try:\n            if not plugin_class.name():\n                continue\n        except NotImplementedError:\n            continue\n        register_plugin(plugin_class, notify_listener=False)\n\n\ndef _unregister_all_plugins() -> None:\n    from LSP.plugin.core.sessions import _plugins\n    _plugins.clear()\n    client_configs.external.clear()\n    client_configs.all.clear()\n\n\ndef plugin_loaded() -> None:\n    load_settings()\n    load_css()\n    _register_all_plugins()\n    client_configs.update_configs()\n    for window in sublime.windows():\n        windows.lookup(window)\n\n\ndef plugin_unloaded() -> None:\n    _unregister_all_plugins()\n    for window in sublime.windows():\n        destroy_output_panels(window)  # references and diagnostics panels\n        try:\n            windows.lookup(window).plugin_unloaded()\n            windows.discard(window)\n        except Exception as ex:\n            exception_log(\"failed to unload window\", ex)\n    unload_settings()\n\n\nclass Listener(sublime_plugin.EventListener):\n\n    def on_exit(self) -> None:\n        kill_all_subprocesses()\n\n    def on_load_project_async(self, w: sublime.Window) -> None:\n        windows.lookup(w).on_load_project_async()\n\n    def on_post_save_project_async(self, w: sublime.Window) -> None:\n        windows.lookup(w).on_post_save_project_async()\n\n    def on_new_window_async(self, w: sublime.Window) -> None:\n        sublime.set_timeout(lambda: windows.lookup(w))\n\n    def on_pre_close_window(self, w: sublime.Window) -> None:\n        windows.discard(w)\n\n    # Note: EventListener.on_post_move_async does not fire when a tab is moved out of the current window in such a way\n    # that a new window is created: https://github.com/sublimehq/sublime_text/issues/4630\n    # Hence, as a workaround we use on_pre_move, which still works in that case.\n    def on_pre_move(self, view: sublime.View) -> None:\n        listeners = sublime_plugin.view_event_listeners.get(view.id())\n        if not isinstance(listeners, list):\n            return\n        for listener in listeners:\n            if isinstance(listener, DocumentSyncListener):\n                # we need a small delay here, so that the DocumentSyncListener will recognize a possible new window\n                sublime.set_timeout_async(listener.on_post_move_window_async, timeout_ms=1)\n                return\n\n    def on_load(self, view: sublime.View) -> None:\n        file_name = view.file_name()\n        if not file_name:\n            return\n        for fn in opening_files.keys():\n            if fn == file_name or os.path.samefile(fn, file_name):\n                # Remove it from the pending opening files, and resolve the promise.\n                opening_files.pop(fn)[1](view)\n                break\n\n    def on_pre_close(self, view: sublime.View) -> None:\n        file_name = view.file_name()\n        if not file_name:\n            return\n        for fn in opening_files.keys():\n            if fn == file_name or os.path.samefile(fn, file_name):\n                tup = opening_files.pop(fn, None)\n                if tup:\n                    # The view got closed before it finished loading. This can happen.\n                    tup[1](None)\n                    break\n\n    def on_post_window_command(self, window: sublime.Window, command_name: str, args: Optional[Dict[str, Any]]) -> None:\n        if command_name in (\"next_result\", \"prev_result\"):\n            view = window.active_view()\n            if view:\n                view.run_command(\"lsp_hover\", {\"only_diagnostics\": True})\n\n\nclass LspOpenLocationCommand(sublime_plugin.TextCommand):\n    \"\"\"\n    A command to be used by third-party ST packages that need to open an URI with some abstract scheme.\n    \"\"\"\n\n    def run(\n        self,\n        _: sublime.Edit,\n        location: Location,\n        session_name: Optional[str] = None,\n        flags: int = 0,\n        group: int = -1\n    ) -> None:\n        sublime.set_timeout_async(lambda: self._run_async(location, session_name, flags, group))\n\n    def _run_async(self, location: Location, session_name: Optional[str], flags: int = 0, group: int = -1) -> None:\n        window = self.view.window()\n        if not window:\n            return\n        windows.lookup(window).open_location_async(location, session_name, self.view, flags, group).then(\n            lambda success: self._handle_continuation(location, success))\n\n    def _handle_continuation(self, location: Location, success: bool) -> None:\n        if not success:\n            uri, _ = get_uri_and_position_from_location(location)\n            message = \"Failed to open {}\".format(uri)\n            sublime.status_message(message)\n", "path": "boot.py"}, {"content": "import sublime\nfrom .core.protocol import Error\nfrom .core.protocol import ExecuteCommandParams\nfrom .core.registry import LspTextCommand\nfrom .core.registry import windows\nfrom .core.typing import List, Optional, Any\nfrom .core.views import first_selection_region\nfrom .core.views import uri_from_view, offset_to_point, region_to_range, text_document_identifier\n\n\nclass LspExecuteCommand(LspTextCommand):\n    \"\"\"\n    Helper command for triggering workspace/executeCommand requests.\n    \"\"\"\n\n    def run(self,\n            edit: sublime.Edit,\n            command_name: Optional[str] = None,\n            command_args: Optional[List[Any]] = None,\n            session_name: Optional[str] = None,\n            event: Optional[dict] = None) -> None:\n        # Handle VSCode-specific command for triggering AC/sighelp\n        if command_name == \"editor.action.triggerSuggest\":\n            # Triggered from set_timeout as suggestions popup doesn't trigger otherwise.\n            return sublime.set_timeout(lambda: self.view.run_command(\"auto_complete\"))\n        if command_name == \"editor.action.triggerParameterHints\":\n\n            def run_async() -> None:\n                listener = windows.listener_for_view(self.view)\n                if listener:\n                    listener.do_signature_help_async(manual=False)\n\n            return sublime.set_timeout_async(run_async)\n        session = self.session_by_name(session_name if session_name else self.session_name)\n        if session and command_name:\n            params = {\"command\": command_name}  # type: ExecuteCommandParams\n            if command_args:\n                params[\"arguments\"] = self._expand_variables(command_args)\n\n            def handle_response(response: Any) -> None:\n                assert command_name\n                if isinstance(response, Error):\n                    self.handle_error_async(response, command_name)\n                    return\n                self.handle_success_async(response, command_name)\n\n            session.execute_command(params, progress=True).then(handle_response)\n\n    def handle_success_async(self, result: Any, command_name: str) -> None:\n        \"\"\"\n        Override this method to handle successful response to workspace/executeCommand.\n\n        :param result: The result returned from the server.\n        :param command_name: The name of the command that was executed.\n        \"\"\"\n        msg = \"command {} completed\".format(command_name)\n        window = self.view.window()\n        if window:\n            window.status_message(msg)\n\n    def handle_error_async(self, error: Error, command_name: str) -> None:\n        \"\"\"\n        Override this method to handle failed response to workspace/executeCommand.\n\n        :param error: The Error object.\n        :param command_name: The name of the command that was executed.\n        \"\"\"\n        sublime.message_dialog(\"command {} failed. Reason: {}\".format(command_name, str(error)))\n\n    def _expand_variables(self, command_args: List[Any]) -> List[Any]:\n        view = self.view  # type: sublime.View\n        region = first_selection_region(view)\n        for i, arg in enumerate(command_args):\n            if arg in [\"$document_id\", \"${document_id}\"]:\n                command_args[i] = text_document_identifier(view)\n            elif arg in [\"$file_uri\", \"${file_uri}\"]:\n                command_args[i] = uri_from_view(view)\n            elif region is not None:\n                if arg in [\"$selection\", \"${selection}\"]:\n                    command_args[i] = view.substr(region)\n                elif arg in [\"$offset\", \"${offset}\"]:\n                    command_args[i] = region.b\n                elif arg in [\"$selection_begin\", \"${selection_begin}\"]:\n                    command_args[i] = region.begin()\n                elif arg in [\"$selection_end\", \"${selection_end}\"]:\n                    command_args[i] = region.end()\n                elif arg in [\"$position\", \"${position}\"]:\n                    command_args[i] = offset_to_point(view, region.b).to_lsp()\n                elif arg in [\"$range\", \"${range}\"]:\n                    command_args[i] = region_to_range(view, region).to_lsp()\n        window = view.window()\n        window_variables = window.extract_variables() if window else {}\n        return sublime.expand_variables(command_args, window_variables)\n", "path": "plugin/execute_command.py"}]}