Repository: sublimelsp/LSP

Issue:
Error handling None in Console
**Describe the bug**
Console gets filed with error messages

**To Reproduce**
Steps to reproduce the behavior:
1. Install LSP, LSP-jdtls
2. Open Java file

**Expected behavior**
Nothing

**Screenshots**
none

**Environment (please complete the following information):**
- OS: Manjaro Linux
- Sublime Text version: 4121
- LSP version: 1.13

**Additional context**
I installed LSP-file-watcher-chokidar

**Log**
[log.txt](https://github.com/sublimelsp/LSP/files/7453704/log.txt)




Discussion:
For the record:

```

Error handling None
Traceback (most recent call last):
  File "/.../sublime-text/Installed Packages/LSP.sublime-package/plugin/core/sessions.py", line 1612, in on_payload
    handler(result)
  File "/.../sublime-text/Installed Packages/LSP.sublime-package/plugin/core/sessions.py", line 1546, in <lambda>
    self.send_request_async(request, resolver, lambda x: resolver(Error.from_lsp(x)))
  File "/.../sublime-text/Installed Packages/LSP.sublime-package/plugin/core/promise.py", line 153, in <lambda>
    executor_func(lambda value=None: self._do_resolve(value))
  File "/.../sublime-text/Installed Packages/LSP.sublime-package/plugin/core/promise.py", line 214, in _do_resolve
    callback(new_value)
  File "/.../sublime-text/Installed Packages/LSP.sublime-package/plugin/core/promise.py", line 178, in callback_wrapper
    result = onfullfilled(resolve_value)
  File "/.../sublime-text/Installed Packages/LSP.sublime-package/plugin/code_lens.py", line 60, in resolve
    self.region = range_to_region(Range.from_lsp(code_lens['range']), view)
TypeError: 'Error' object is not subscriptable

Traceback (most recent call last):
  File "/.../sublime-text/Installed Packages/LSP.sublime-package/plugin/code_actions.py", line 65, in <lambda>
  File "/.../sublime-text/Installed Packages/LSP.sublime-package/plugin/documents.py", line 538, in _on_code_actions
KeyError: 'foreground'
```
Are those 2 independent errors?

> ```
> Traceback (most recent call last):
>  File "/.../sublime-text/Installed Packages/LSP.sublime-package/plugin/code_actions.py", line 65, in <lambda>
>  File "/.../sublime-text/Installed Packages/LSP.sublime-package/plugin/documents.py", line 538, in _on_code_actions
> KeyError: 'foreground'
> ```

This error makes no sense to me. `View.style_for_scope()` should always return a dict with a "foreground" key, both according to the API documentation, as well as when I test it in the console. If there is no color scheme rule for the specified scope, then it will be set to the global foreground color. And even if there exists a rule for the scope, but the rule doesn't assign a foreground color, then the returned dict still has the "foreground" key with the default foreground:
with this color scheme rule
```json
        {
            "scope": "this-has-only-background",
            "background": "red"
        },
```
I get
```
>>> view.style_for_scope("this-has-only-background")["foreground"]
'#dddddd'
```
which is the default foreground in my color scheme.

Anyways, a fix for this obscure error could be something like
```python
annotation_color = self.view.style_for_scope("region.bluish markup.accent.codeaction.lsp").get("foreground", "#0000ff")
```
instead of
```python
annotation_color = self.view.style_for_scope("region.bluish markup.accent.codeaction.lsp")["foreground"]
```

---

*Edit*: besides what I wrote above, it is also ensured by the "region.bluish" scope, that there will always be a rule for it in the color scheme. This rule is automatically generated by ST.
Could be possible that these are independent. Though, I never saw the second Traceback without at least one instance of the first one.


Resolving patch:
diff --git a/plugin/code_lens.py b/plugin/code_lens.py
--- a/plugin/code_lens.py
+++ b/plugin/code_lens.py
@@ -1,5 +1,5 @@
-from .core.protocol import CodeLens, Range
-from .core.typing import List, Tuple, Dict, Iterable, Generator
+from .core.protocol import CodeLens, Error, Range
+from .core.typing import List, Tuple, Dict, Iterable, Generator, Union
 from .core.registry import LspTextCommand
 from .core.registry import windows
 from .core.views import make_command_link
@@ -15,6 +15,7 @@ class CodeLensData:
         'region',
         'session_name',
         'annotation',
+        'is_resolve_error',
     )
 
     def __init__(self, data: CodeLens, view: sublime.View, session_name: str) -> None:
@@ -23,13 +24,14 @@ def __init__(self, data: CodeLens, view: sublime.View, session_name: str) -> Non
         self.session_name = session_name
         self.annotation = '...'
         self.resolve_annotation()
+        self.is_resolve_error = False
 
     def __repr__(self) -> str:
         return 'CodeLensData(resolved={0}, region={1!r})'.format(self.is_resolved(), self.region)
 
     def is_resolved(self) -> bool:
         """A code lens is considered resolved if the inner data contains the 'command' key."""
-        return 'command' in self.data
+        return 'command' in self.data or self.is_resolve_error
 
     def to_lsp(self) -> CodeLens:
         copy = self.data.copy()
@@ -55,9 +57,13 @@ def resolve_annotation(self) -> None:
         else:
             self.annotation = '...'
 
-    def resolve(self, view: sublime.View, code_lens: CodeLens) -> None:
-        self.data = code_lens
-        self.region = range_to_region(Range.from_lsp(code_lens['range']), view)
+    def resolve(self, view: sublime.View, code_lens_or_error: Union[CodeLens, Error]) -> None:
+        if isinstance(code_lens_or_error, Error):
+            self.is_resolve_error = True
+            self.annotation = html_escape(str(code_lens_or_error))
+            return
+        self.data = code_lens_or_error
+        self.region = range_to_region(Range.from_lsp(code_lens_or_error['range']), view)
         self.resolve_annotation()
 
 
diff --git a/plugin/session_view.py b/plugin/session_view.py
--- a/plugin/session_view.py
+++ b/plugin/session_view.py
@@ -78,6 +78,9 @@ def __del__(self) -> None:
             self.view.erase_regions(self.diagnostics_key(severity, False))
             self.view.erase_regions(self.diagnostics_key(severity, True))
 
+    def _is_listener_alive(self) -> bool:
+        return bool(self.listener())
+
     def _clear_auto_complete_triggers(self, settings: sublime.Settings) -> None:
         '''Remove all of our modifications to the view's "auto_complete_triggers"'''
         triggers = settings.get(self.AC_TRIGGERS_KEY)
@@ -295,7 +298,7 @@ def start_code_lenses_async(self) -> None:
         self.session.send_request_async(Request("textDocument/codeLens", params, self.view), self._on_code_lenses_async)
 
     def _on_code_lenses_async(self, response: Optional[List[CodeLens]]) -> None:
-        if not isinstance(response, list):
+        if not self._is_listener_alive() or not isinstance(response, list):
             return
         self._code_lenses.handle_response(self.session.config.name, response)
         self.resolve_visible_code_lenses_async()
@@ -306,16 +309,19 @@ def resolve_visible_code_lenses_async(self) -> None:
             return
         if self._code_lenses.is_empty():
             return
-        promises = []  # type: List[Promise[None]]
-        for code_lens in self._code_lenses.unresolved_visible_code_lenses(self.view.visible_region()):
-            callback = functools.partial(code_lens.resolve, self.view)
-            promise = self.session.send_request_task(
-                Request("codeLens/resolve", code_lens.data, self.view)
-            ).then(callback)
-            promises.append(promise)
+        promises = [Promise.resolve(None)]  # type: List[Promise[None]]
+        if self.session.get_capability('codeLensProvider.resolveProvider'):
+            for code_lens in self._code_lenses.unresolved_visible_code_lenses(self.view.visible_region()):
+                request = Request("codeLens/resolve", code_lens.data, self.view)
+                callback = functools.partial(code_lens.resolve, self.view)
+                promise = self.session.send_request_task(request).then(callback)
+                promises.append(promise)
         mode = userprefs().show_code_lens
-        render = functools.partial(self._code_lenses.render, mode)
-        Promise.all(promises).then(lambda _: sublime.set_timeout(render))
+        Promise.all(promises).then(lambda _: self._on_code_lenses_resolved_async(mode))
+
+    def _on_code_lenses_resolved_async(self, mode: str) -> None:
+        if self._is_listener_alive():
+            sublime.set_timeout(lambda: self._code_lenses.render(mode))
 
     def get_resolved_code_lenses_for_region(self, region: sublime.Region) -> Generator[CodeLens, None, None]:
         yield from self._code_lenses.get_resolved_code_lenses_for_region(region)


Test patch: