diff --git a/LSP.sublime-settings b/LSP.sublime-settings index b9b6704d1..56d576b58 100644 --- a/LSP.sublime-settings +++ b/LSP.sublime-settings @@ -2,12 +2,7 @@ // Show permanent language server status in the status bar. "show_view_status": true, - // Open and close the diagnostics panel automatically, - // depending on available diagnostics. - // Valid values are "never", "always" and "saved" - "auto_show_diagnostics_panel": "saved", - - // Run the server's formatProvider (if supported) on a document before saving. + // Run the server's formatProvider (if supported) on a file before saving. // This option is also supported in syntax-specific settings and/or in the // "settings" section of project files. "lsp_format_on_save": false, @@ -32,8 +27,9 @@ // The amount of time the code actions on save are allowed to run for. "code_action_on_save_timeout_ms": 2000, - // Open the diagnostics panel automatically - // when diagnostics level is equal to or less than: + // Open the diagnostics panel automatically on save when diagnostics level is + // equal to or less than: + // none: 0 (never open the panel automatically) // error: 1 // warning: 2 // info: 3 @@ -49,7 +45,7 @@ // Show highlights and gutter markers in the file views for diagnostics // with level equal to or less than: - // none: 0 + // none: 0 (never show) // error: 1 // warning: 2 // info: 3 diff --git a/Syntaxes/Diagnostics.sublime-syntax b/Syntaxes/Diagnostics.sublime-syntax index 9b071f506..40a8cd98a 100644 --- a/Syntaxes/Diagnostics.sublime-syntax +++ b/Syntaxes/Diagnostics.sublime-syntax @@ -7,6 +7,8 @@ scope: output.lsp.diagnostics contexts: main: + - match: ^ No diagnostics. Well done!$ + scope: comment.line.placeholder.lsp - include: file - include: line diff --git a/plugin/core/sessions.py b/plugin/core/sessions.py index 502464094..bd30f70b0 100644 --- a/plugin/core/sessions.py +++ b/plugin/core/sessions.py @@ -97,10 +97,6 @@ def update_diagnostics_panel_async(self) -> None: def show_diagnostics_panel_async(self) -> None: pass - @abstractmethod - def hide_diagnostics_panel_async(self) -> None: - pass - # Event callbacks @abstractmethod diff --git a/plugin/core/types.py b/plugin/core/types.py index c46b2988a..0ef6fab06 100644 --- a/plugin/core/types.py +++ b/plugin/core/types.py @@ -144,7 +144,6 @@ def read_list_setting(settings_obj: sublime.Settings, key: str, default: list) - class Settings: # This is only for mypy - auto_show_diagnostics_panel = None # type: str auto_show_diagnostics_panel_level = None # type: int code_action_on_save_timeout_ms = None # type: int diagnostics_additional_delay_auto_complete_ms = None # type: int @@ -181,7 +180,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("auto_show_diagnostics_panel", "always") r("auto_show_diagnostics_panel_level", 2) r("code_action_on_save_timeout_ms", 2000) r("diagnostics_additional_delay_auto_complete_ms", 0) @@ -219,11 +217,11 @@ def r(name: str, default: Union[bool, int, str, list, dict]) -> None: # Backwards-compatible with the bool setting auto_show_diagnostics_panel = s.get("auto_show_diagnostics_panel") if isinstance(auto_show_diagnostics_panel, bool): - self.auto_show_diagnostics_panel = "always" if auto_show_diagnostics_panel else "never" + if not auto_show_diagnostics_panel: + self.auto_show_diagnostics_panel_level = 0 elif isinstance(auto_show_diagnostics_panel, str): - self.auto_show_diagnostics_panel = auto_show_diagnostics_panel - else: - self.auto_show_diagnostics_panel = "always" + if auto_show_diagnostics_panel == "never": + self.auto_show_diagnostics_panel_level = 0 # Backwards-compatible with "only_show_lsp_completions" only_show_lsp_completions = s.get("only_show_lsp_completions") @@ -236,12 +234,6 @@ def r(name: str, default: Union[bool, int, str, list, dict]) -> None: set_debug_logging(self.log_debug) - def show_diagnostics_panel_always(self) -> bool: - return self.auto_show_diagnostics_panel == "always" - - def show_diagnostics_panel_on_save(self) -> bool: - return self.auto_show_diagnostics_panel == "saved" - def document_highlight_style_to_add_regions_flags(self) -> int: return _settings_style_to_add_regions_flag(self.document_highlight_style) diff --git a/plugin/core/windows.py b/plugin/core/windows.py index f0b39f18b..2b9848fe1 100644 --- a/plugin/core/windows.py +++ b/plugin/core/windows.py @@ -11,11 +11,11 @@ from .protocol import Diagnostic from .protocol import Error from .protocol import Point +from .sessions import get_plugin from .sessions import Logger from .sessions import Manager from .sessions import Session from .sessions import SessionBufferProtocol -from .sessions import get_plugin from .sessions import SessionViewProtocol from .settings import userprefs from .transports import create_transport @@ -35,12 +35,16 @@ from time import time from weakref import ref from weakref import WeakSet +import functools import json import os import sublime import threading +_NO_DIAGNOSTICS_PLACEHOLDER = " No diagnostics. Well done!" + + class AbstractViewListener(metaclass=ABCMeta): TOTAL_ERRORS_AND_WARNINGS_STATUS_KEY = "lsp_total_errors_and_warnings" @@ -127,6 +131,7 @@ def __init__( self._panel_code_phantoms = None # type: Optional[sublime.PhantomSet] self.total_error_count = 0 self.total_warning_count = 0 + sublime.set_timeout(functools.partial(self._update_panel_main_thread, None, _NO_DIAGNOSTICS_PLACEHOLDER, [])) def get_config_manager(self) -> WindowConfigManager: return self._configs @@ -437,42 +442,33 @@ def update_diagnostics_panel_async(self) -> None: for listener in listeners: set_diagnostics_count(listener.view, self.total_error_count, self.total_warning_count) characters = "\n".join(to_render) - - def update() -> None: - panel = ensure_diagnostics_panel(self._window) - if not panel or not panel.is_valid(): - return - if isinstance(base_dir, str): - panel.settings().set("result_base_dir", base_dir) - else: - panel.settings().erase("result_base_dir") - panel.run_command("lsp_update_panel", {"characters": characters}) - if self._panel_code_phantoms is None: - self._panel_code_phantoms = sublime.PhantomSet(panel, "hrefs") - phantoms = [] # type: List[sublime.Phantom] - for row, col, code, href in prephantoms: - point = panel.text_point(row, col) - region = sublime.Region(point, point) - phantoms.append(sublime.Phantom(region, make_link(href, code), sublime.LAYOUT_INLINE)) - self._panel_code_phantoms.update(phantoms) - - sublime.set_timeout(update) - - def _can_manipulate_diagnostics_panel(self) -> bool: - active_panel = self._window.active_panel() - if active_panel is not None: - return active_panel == "output.diagnostics" - return True + if not characters: + characters = _NO_DIAGNOSTICS_PLACEHOLDER + sublime.set_timeout(functools.partial(self._update_panel_main_thread, base_dir, characters, prephantoms)) + + def _update_panel_main_thread(self, base_dir: Optional[str], characters: str, + prephantoms: List[Tuple[int, int, str, str]]) -> None: + panel = ensure_diagnostics_panel(self._window) + if not panel or not panel.is_valid(): + return + if isinstance(base_dir, str): + panel.settings().set("result_base_dir", base_dir) + else: + panel.settings().erase("result_base_dir") + panel.run_command("lsp_update_panel", {"characters": characters}) + if self._panel_code_phantoms is None: + self._panel_code_phantoms = sublime.PhantomSet(panel, "hrefs") + phantoms = [] # type: List[sublime.Phantom] + for row, col, code, href in prephantoms: + point = panel.text_point(row, col) + region = sublime.Region(point, point) + phantoms.append(sublime.Phantom(region, make_link(href, code), sublime.LAYOUT_INLINE)) + self._panel_code_phantoms.update(phantoms) def show_diagnostics_panel_async(self) -> None: - if self._can_manipulate_diagnostics_panel(): + if self._window.active_panel() is None: self._window.run_command("show_panel", {"panel": "output.diagnostics"}) - def hide_diagnostics_panel_async(self) -> None: - # prevent flickering on-save - if self._can_manipulate_diagnostics_panel() and userprefs().auto_show_diagnostics_panel != "saved": - self._window.run_command("hide_panel", {"panel": "output.diagnostics"}) - def select_next_diagnostic_async(self) -> None: self._select_diagnostic_async(1) diff --git a/plugin/session_buffer.py b/plugin/session_buffer.py index e3eaecaf6..3e88b759f 100644 --- a/plugin/session_buffer.py +++ b/plugin/session_buffer.py @@ -229,11 +229,10 @@ def on_post_save_async(self, view: sublime.View) -> None: self.purge_changes_async(view) # mypy: expected sublime.View, got ViewLike self.session.send_notification(did_save(view, include_text, self.file_name)) - if userprefs().show_diagnostics_panel_on_save(): - if self.should_show_diagnostics_panel: - mgr = self.session.manager() - if mgr: - mgr.show_diagnostics_panel_async() + if self.should_show_diagnostics_panel: + mgr = self.session.manager() + if mgr: + mgr.show_diagnostics_panel_async() def some_view(self) -> Optional[sublime.View]: for sv in self.session_views: @@ -346,10 +345,6 @@ def _present_diagnostics_async( mgr = self.session.manager() if mgr: mgr.update_diagnostics_panel_async() - if not self.should_show_diagnostics_panel: - mgr.hide_diagnostics_panel_async() - elif userprefs().show_diagnostics_panel_always(): - mgr.show_diagnostics_panel_async() def __str__(self) -> str: return '{}:{}:{}'.format(self.session.config.name, self.id, self.file_name) diff --git a/sublime-package.json b/sublime-package.json index 4033996ea..a429b2908 100644 --- a/sublime-package.json +++ b/sublime-package.json @@ -173,7 +173,7 @@ } ], "default": "saved", - "markdownDescription": "Open and close the diagnostics panel automatically, depending on available diagnostics. For backward-compatibility, this can also be a boolean. In that case, if set to `false`, don't show the diagnostics panel, and when set to `true`, always show the diagnostics panel." + "deprecationMessage": "Use the \"auto_show_diagnostics_panel_level\" setting instead." }, "code_action_on_save_timeout_ms": { "type": "integer", @@ -182,10 +182,10 @@ }, "auto_show_diagnostics_panel_level": { "type": "integer", - "minimum": 1, + "minimum": 0, "maximum": 4, "default": 2, - "markdownDescription": "Open the diagnostics panel automatically when diagnostics level is equal to or less than:\n\n- _error_: `1`,\n- _warning_: `2`,\n- _info_: `3`,\n- _hint_: `4`" + "markdownDescription": "Open the diagnostics panel automatically **on save** when diagnostics level is equal to or less than:\n\n- _none_: `0` (this means never show the panel automatically),\n- _error_: `1`,\n- _warning_: `2`,\n- _info_: `3`,\n- _hint_: `4`\n\nThe panel is not shown when there is already another panel open. The panel is never _closed_ automatically. To close the panel, press the Esc key." }, "show_diagnostics_count_in_view_status": { "type": "boolean", diff --git a/tests/test_session.py b/tests/test_session.py index f87f16fc6..755b33495 100644 --- a/tests/test_session.py +++ b/tests/test_session.py @@ -40,9 +40,6 @@ def update_diagnostics_panel_async(self) -> None: def show_diagnostics_panel_async(self) -> None: pass - def hide_diagnostics_panel_async(self) -> None: - pass - class MockLogger(Logger):