Repository: sublimelsp/LSP

Issue:
Does not cache diagnostics when switching between files
**Describe the bug**
Sublime LSP does not cache diagnostics that are reported from the server for a folder/file.

**To Reproduce**
Steps to reproduce the behavior:
1. Language Server sends diagnostics on saving a file and on adding a workspace folder via initialization or config update.
2. The Open/Close capability is not reported, nor implemented
3. When switching between `fileA` to `fileB` and then back to `fileA` the diagnostics that are previously displayed in `fileA` are lost.

**Expected behavior**
Reported diagnostics are only cleared, when the server clears them. According to the spec, diagnostics are owned by the server and must be explicitly cleared by it.

From the spec: `Diagnostics are “owned” by the server so it is the server’s responsibility to clear them if necessary.`

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Additional context**
Implementing Open/Close mitigates that issue, but actually on File open, most likely pull diagnostics should be called on the LS if it has that capability.


Discussion:

Resolving patch:
diff --git a/plugin/core/sessions.py b/plugin/core/sessions.py
--- a/plugin/core/sessions.py
+++ b/plugin/core/sessions.py
@@ -490,7 +490,7 @@ def listener(self) -> 'weakref.ref[AbstractViewListener]':
     def session_buffer(self) -> 'SessionBufferProtocol':
         ...
 
-    def get_uri(self) -> Optional[str]:
+    def get_uri(self) -> Optional[DocumentUri]:
         ...
 
     def get_language_id(self) -> Optional[str]:
@@ -678,7 +678,7 @@ def get_language_id(self) -> str:
         raise NotImplementedError()
 
     @abstractmethod
-    def get_uri(self) -> str:
+    def get_uri(self) -> DocumentUri:
         raise NotImplementedError()
 
     @abstractmethod
@@ -1255,6 +1255,17 @@ def register_session_buffer_async(self, sb: SessionBufferProtocol) -> None:
         self._session_buffers.add(sb)
         for data in self._registrations.values():
             data.check_applicable(sb)
+        uri = sb.get_uri()
+        if uri:
+            diagnostics = self.diagnostics.diagnostics_by_document_uri(uri)
+            if diagnostics:
+                self._publish_diagnostics_to_session_buffer_async(sb, diagnostics, version=None)
+
+    def _publish_diagnostics_to_session_buffer_async(
+        self, sb: SessionBufferProtocol, diagnostics: List[Diagnostic], version: Optional[int]
+    ) -> None:
+        visible_session_views, _ = self.session_views_by_visibility()
+        sb.on_diagnostics_async(diagnostics, version, visible_session_views)
 
     def unregister_session_buffer_async(self, sb: SessionBufferProtocol) -> None:
         self._session_buffers.discard(sb)
@@ -1748,8 +1759,7 @@ def m_textDocument_publishDiagnostics(self, params: PublishDiagnosticsParams) ->
         mgr.on_diagnostics_updated()
         sb = self.get_session_buffer_for_uri_async(uri)
         if sb:
-            visible_session_views, _ = self.session_views_by_visibility()
-            sb.on_diagnostics_async(diagnostics, params.get("version"), visible_session_views)
+            self._publish_diagnostics_to_session_buffer_async(sb, diagnostics, params.get('version'))
 
     def m_client_registerCapability(self, params: RegistrationParams, request_id: Any) -> None:
         """handles the client/registerCapability request"""
diff --git a/plugin/session_buffer.py b/plugin/session_buffer.py
--- a/plugin/session_buffer.py
+++ b/plugin/session_buffer.py
@@ -127,7 +127,6 @@ def __init__(self, session_view: SessionViewProtocol, buffer_id: int, uri: Docum
         self._is_saving = False
         self._has_changed_during_save = False
         self._check_did_open(view)
-        self._session.register_session_buffer_async(self)
 
     @property
     def session(self) -> Session:
@@ -157,7 +156,7 @@ def _check_did_close(self) -> None:
             self.session.send_notification(did_close(uri=self.last_known_uri))
             self.opened = False
 
-    def get_uri(self) -> Optional[str]:
+    def get_uri(self) -> Optional[DocumentUri]:
         for sv in self.session_views:
             return sv.get_uri()
         return None
diff --git a/plugin/session_view.py b/plugin/session_view.py
--- a/plugin/session_view.py
+++ b/plugin/session_view.py
@@ -53,9 +53,11 @@ def __init__(self, listener: AbstractViewListener, session: Session, uri: Docume
         if session_buffer is None:
             session_buffer = SessionBuffer(self, buffer_id, uri)
             self._session_buffers[key] = session_buffer
+            self._session_buffer = session_buffer
+            self._session.register_session_buffer_async(session_buffer)
         else:
+            self._session_buffer = session_buffer
             session_buffer.add_session_view(self)
-        self._session_buffer = session_buffer
         session.register_session_view_async(self)
         session.config.set_view_status(self._view, session.config_status_message)
         if self._session.has_capability(self.HOVER_PROVIDER_KEY):
@@ -219,7 +221,7 @@ def _decrement_hover_count(self) -> None:
                 settings.erase(self.HOVER_PROVIDER_COUNT_KEY)
                 settings.set(self.SHOW_DEFINITIONS_KEY, True)
 
-    def get_uri(self) -> Optional[str]:
+    def get_uri(self) -> Optional[DocumentUri]:
         listener = self.listener()
         return listener.get_uri() if listener else None
 


Test patch:
diff --git a/tests/test_session.py b/tests/test_session.py
--- a/tests/test_session.py
+++ b/tests/test_session.py
@@ -79,7 +79,7 @@ def __init__(self, session: Session, mock_uri: str, mock_language_id: str) -> No
         self.mock_uri = mock_uri
         self.mock_language_id = mock_language_id
 
-    def get_uri(self) -> Optional[str]:
+    def get_uri(self) -> Optional[DocumentUri]:
         return self.mock_uri
 
     def get_language_id(self) -> Optional[str]: