Repository: sublimelsp/LSP

Issue:
Setting to increase timeout
**Is your feature request related to a problem? Please describe.**
I have `"lsp_format_on_save"` enabled for **LSP-pylsp** where I use `black`. This works great in most cases but from time to time I'm working on larger/more complex codes that take a little longer to format and so the formatting hits the 1000ms default timeout here:

https://github.com/sublimelsp/LSP/blob/5611169a5b4e004b9b1722758ca856ca98d1927f/plugin/save_command.py#L33-L37

And as seen here in the status bar:
<img width="542" alt="Screen Shot 2021-06-03 at 6 25 47 PM" src="https://user-images.githubusercontent.com/4546435/120725445-94c75b00-c49b-11eb-8866-2c66ff8166eb.png">

**Describe the solution you'd like**
Add a setting allowing us to customize the timeout value.

**Describe alternatives you've considered**
A working alternative is to force the formatting via context menu > LSP > Format File but for obvious reasons this can become annoying.

**Additional context**
N/A


Discussion:
I see that there is a `"code_action_on_save_timeout_ms"` setting but this does not appear to apply to formatting on save? I would assume a similar implementation is needed?
True, the other save tasks have hard-coded 1s limit.

Maybe best would be to rename the setting to `on_save_task_timeout_ms`

Resolving patch:
diff --git a/plugin/code_actions.py b/plugin/code_actions.py
--- a/plugin/code_actions.py
+++ b/plugin/code_actions.py
@@ -235,9 +235,6 @@ def _get_code_actions_on_save(cls, view: sublime.View) -> Dict[str, bool]:
                 allowed_code_actions[key] = value
         return allowed_code_actions
 
-    def get_task_timeout_ms(self) -> int:
-        return userprefs().code_action_on_save_timeout_ms
-
     def run_async(self) -> None:
         super().run_async()
         self._request_code_actions_async()
diff --git a/plugin/core/types.py b/plugin/core/types.py
--- a/plugin/core/types.py
+++ b/plugin/core/types.py
@@ -130,7 +130,6 @@ def read_list_setting(settings_obj: sublime.Settings, key: str, default: list) -
 class Settings:
 
     # This is only for mypy
-    code_action_on_save_timeout_ms = None  # type: int
     diagnostics_additional_delay_auto_complete_ms = None  # type: int
     diagnostics_delay_ms = None  # type: int
     diagnostics_gutter_marker = None  # type: str
@@ -144,6 +143,7 @@ class Settings:
     log_server = None  # type: List[str]
     lsp_code_actions_on_save = None  # type: Dict[str, bool]
     lsp_format_on_save = None  # type: bool
+    on_save_task_timeout_ms = None  # type: int
     only_show_lsp_completions = None  # type: bool
     popup_max_characters_height = None  # type: int
     popup_max_characters_width = None  # type: int
@@ -167,7 +167,6 @@ def r(name: str, default: Union[bool, int, str, list, dict]) -> None:
             val = s.get(name)
             setattr(self, name, val if isinstance(val, default.__class__) else default)
 
-        r("code_action_on_save_timeout_ms", 2000)
         r("diagnostics_additional_delay_auto_complete_ms", 0)
         r("diagnostics_delay_ms", 0)
         r("diagnostics_gutter_marker", "dot")
@@ -178,6 +177,7 @@ def r(name: str, default: Union[bool, int, str, list, dict]) -> None:
         r("log_max_size", 8 * 1024)
         r("lsp_code_actions_on_save", {})
         r("lsp_format_on_save", False)
+        r("on_save_task_timeout_ms", 2000)
         r("only_show_lsp_completions", False)
         r("popup_max_characters_height", 1000)
         r("popup_max_characters_width", 120)
@@ -225,6 +225,11 @@ def r(name: str, default: Union[bool, int, str, list, dict]) -> None:
             if not diagnostics_highlight_style:
                 self.show_diagnostics_highlights = False
 
+        # Backwards-compatible with "code_action_on_save_timeout_ms"
+        code_action_on_save_timeout_ms = s.get("code_action_on_save_timeout_ms")
+        if isinstance(code_action_on_save_timeout_ms, int):
+            self.on_save_task_timeout_ms = code_action_on_save_timeout_ms
+
         set_debug_logging(self.log_debug)
 
     def document_highlight_style_region_flags(self) -> Tuple[int, int]:
diff --git a/plugin/save_command.py b/plugin/save_command.py
--- a/plugin/save_command.py
+++ b/plugin/save_command.py
@@ -1,4 +1,5 @@
 from .core.registry import LspTextCommand
+from .core.settings import userprefs
 from .core.typing import Callable, List, Type
 from abc import ABCMeta, abstractmethod
 import sublime
@@ -12,8 +13,6 @@ class SaveTask(metaclass=ABCMeta):
     Note: The whole task runs on the async thread.
     """
 
-    DEFAULT_TASK_TIMEOUT = 1000
-
     @classmethod
     @abstractmethod
     def is_applicable(cls, view: sublime.View) -> bool:
@@ -28,7 +27,7 @@ def __init__(self, task_runner: LspTextCommand, on_done: Callable[[], None]):
 
     def run_async(self) -> None:
         self._erase_view_status()
-        sublime.set_timeout_async(self._on_timeout, self.get_task_timeout_ms())
+        sublime.set_timeout_async(self._on_timeout, userprefs().on_save_task_timeout_ms)
 
     def _on_timeout(self) -> None:
         if not self._completed and not self._cancelled:
@@ -36,9 +35,6 @@ def _on_timeout(self) -> None:
             self._cancelled = True
             self._on_done()
 
-    def get_task_timeout_ms(self) -> int:
-        return self.DEFAULT_TASK_TIMEOUT
-
     def cancel(self) -> None:
         self._cancelled = True
 


Test patch: