Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refine diagnostics presentation #1710

Merged
merged 12 commits into from
Jun 5, 2021
10 changes: 5 additions & 5 deletions LSP.sublime-settings
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,6 @@
// See also: "diagnostics_delay_ms".
"diagnostics_additional_delay_auto_complete_ms": 0,

// Highlighting style of code diagnostics.
// Valid values are "fill", "box", "underline", "stippled", "squiggly" or "".
// When set to the empty string (""), no diagnostics are shown in-line.
"diagnostics_highlight_style": "squiggly",
rwols marked this conversation as resolved.
Show resolved Hide resolved

// Highlighting style of "highlights": accentuating nearby text entities that
// are related to the one under your cursor.
// Valid values are "fill", "underline", or "".
Expand All @@ -104,6 +99,11 @@
// Show code actions in hover popup if available
"show_code_actions_in_hover": true,

// Show diagnostics (error/warning squigglies) in the view. When disabled,
// gutter markers are still drawn, unless "diagnostics_gutter_marker" is
// set to "".
"show_diagnostics_highlights": true,

// Show symbol action links in hover popup if available
"show_symbol_action_links": true,

Expand Down
47 changes: 21 additions & 26 deletions docs/src/customization.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,14 @@ The following tables give an overview about the scope names used by LSP.

### Diagnostics

| scope | DiagnosticSeverity | description |
| ----- | ------------------ | ----------- |
| `markup.error.lsp` | Error | Reports an error |
| `markup.warning.lsp` | Warning | Reports a warning |
| `markup.info.lsp` | Information | Reports an information |
| `markup.info.hint.lsp` | Hint | Reports a hint |
| scope | DiagnosticSeverity | description | drawn as
| ----- | ------------------ | ----------- | --------
| `markup.error.lsp` | Error | Reports an error | Squiggly underlines
| `markup.warning.lsp` | Warning | Reports a warning | Squiggly underlines
| `markup.info.lsp` | Information | Reports an information | Stippled underlines
| `markup.info.hint.lsp` | Hint | Reports a hint | Stippled underlines

!!! note
If `diagnostics_highlight_style` is set to "fill" in the LSP settings, the highlighting color can be controlled via the "background" color from a color scheme rule for the listed scopes.
When the region of the diagnostic spans more than one line, the diagnostic is always drawn as a box.

Diagnostics will also optionally include the following scopes:

Expand All @@ -54,27 +53,23 @@ Diagnostics will also optionally include the following scopes:
| `markup.unnecessary.lsp` | Unnecessary | Unused or unnecessary code |
| `markup.deprecated.lsp` | Deprecated | Deprecated or obsolete code |

!!! note
Regions created for those scopes don't follow the `diagnostics_highlight_style` setting and instead always use the "fill" style.

Those scopes can be used to, for example, gray-out the text color of unused code, if the server supports that.
Those scopes can be used to, for example, gray-out the text color of unused code, if the server supports that.

For example, to add a custom rule for `Mariana` color scheme, select `UI: Customize Color Scheme` from the Command Palette and add the following rule:
For example, to add a custom rule for `Mariana` color scheme, select `UI: Customize Color Scheme` from the Command Palette and add the following rule:

```json
{
"rules": [
{
"scope": "markup.unnecessary.lsp",
"foreground": "color(rgb(255, 255, 255) alpha(0.4))",
"background": "color(var(blue3) alpha(0.9))"
}
]
}
```

The color scheme rule only works if the "background" color is different from the global background of the scheme. So for other color schemes, ideally pick a background color that is as close as possible, but marginally different from the original background.
```json
{
"rules": [
{
"scope": "markup.unnecessary.lsp",
"foreground": "color(rgb(255, 255, 255) alpha(0.4))",
"background": "color(var(blue3) alpha(0.9))"
}
]
}
```

The color scheme rule only works if the "background" color is different from the global background of the scheme. So for other color schemes, ideally pick a background color that is as close as possible, but marginally different from the original background.

### Signature Help

Expand Down
4 changes: 2 additions & 2 deletions plugin/core/sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ def has_capability_async(self, capability_path: str) -> bool:
def shutdown_async(self) -> None:
...

def present_diagnostics_async(self, flags: int) -> None:
def present_diagnostics_async(self) -> None:
...

def on_request_started_async(self, request_id: int, request: Request) -> None:
Expand Down Expand Up @@ -365,7 +365,7 @@ def unregister_capability_async(
) -> None:
...

def on_diagnostics_async(self, diagnostics: List[Diagnostic], version: Optional[int]) -> None:
def on_diagnostics_async(self, raw_diagnostics: List[Diagnostic], version: Optional[int]) -> None:
...


Expand Down
32 changes: 10 additions & 22 deletions plugin/core/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,23 +69,6 @@ def run() -> None:
runner(run, timeout_ms)


def _settings_style_to_add_regions_flag(style: str) -> int:
flags = 0
if style == "fill":
flags = sublime.DRAW_NO_OUTLINE
elif style == "box":
flags = sublime.DRAW_NO_FILL
else:
flags = sublime.DRAW_NO_FILL | sublime.DRAW_NO_OUTLINE
if style == "underline":
flags |= sublime.DRAW_SOLID_UNDERLINE
elif style == "stippled":
flags |= sublime.DRAW_STIPPLED_UNDERLINE
elif style == "squiggly":
flags |= sublime.DRAW_SQUIGGLY_UNDERLINE
return flags


class SettingsRegistration:
__slots__ = ("_settings",)

Expand Down Expand Up @@ -151,7 +134,6 @@ class Settings:
diagnostics_additional_delay_auto_complete_ms = None # type: int
diagnostics_delay_ms = None # type: int
diagnostics_gutter_marker = None # type: str
diagnostics_highlight_style = None # type: str
diagnostics_panel_include_severity_level = None # type: int
disabled_capabilities = None # type: List[str]
document_highlight_style = None # type: str
Expand All @@ -168,6 +150,7 @@ class Settings:
show_code_actions = None # type: bool
show_code_actions_in_hover = None # type: bool
show_diagnostics_count_in_view_status = None # type: bool
show_diagnostics_highlights = None # type: bool
show_diagnostics_in_view_status = None # type: bool
show_diagnostics_panel_on_save = None # type: int
show_diagnostics_severity_level = None # type: int
Expand All @@ -188,7 +171,6 @@ def r(name: str, default: Union[bool, int, str, list, dict]) -> None:
r("diagnostics_additional_delay_auto_complete_ms", 0)
r("diagnostics_delay_ms", 0)
r("diagnostics_gutter_marker", "dot")
r("diagnostics_highlight_style", "underline")
r("diagnostics_panel_include_severity_level", 4)
r("disabled_capabilities", [])
r("document_highlight_style", "underline")
Expand All @@ -203,6 +185,7 @@ def r(name: str, default: Union[bool, int, str, list, dict]) -> None:
r("show_code_actions_in_hover", True)
r("show_diagnostics_count_in_view_status", False)
r("show_diagnostics_in_view_status", True)
r("show_diagnostics_highlights", True)
r("show_diagnostics_panel_on_save", 2)
r("show_diagnostics_severity_level", 2)
r("show_references_in_quick_panel", False)
Expand Down Expand Up @@ -236,6 +219,14 @@ def r(name: str, default: Union[bool, int, str, list, dict]) -> None:
r("inhibit_snippet_completions", False)
r("inhibit_word_completions", True)

# Backwards-compatible with "diagnostics_highlight_style"
diagnostics_highlight_style = s.get("diagnostics_highlight_style")
if isinstance(diagnostics_highlight_style, str) and not s.has("show_diagnostics_highlights"):
if diagnostics_highlight_style:
self.show_diagnostics_highlights = True
rchl marked this conversation as resolved.
Show resolved Hide resolved
else:
self.show_diagnostics_highlights = False
rwols marked this conversation as resolved.
Show resolved Hide resolved

set_debug_logging(self.log_debug)

def document_highlight_style_region_flags(self) -> Tuple[int, int]:
Expand All @@ -244,9 +235,6 @@ def document_highlight_style_region_flags(self) -> Tuple[int, int]:
else:
return sublime.DRAW_NO_FILL, sublime.DRAW_NO_FILL | sublime.DRAW_NO_OUTLINE | sublime.DRAW_SOLID_UNDERLINE

def diagnostics_highlight_style_to_add_regions_flag(self) -> int:
return _settings_style_to_add_regions_flag(self.diagnostics_highlight_style)


class ClientStates:
STARTING = 0
Expand Down
12 changes: 6 additions & 6 deletions plugin/core/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@
import tempfile

DIAGNOSTIC_SEVERITY = [
# Kind CSS class Scope for color Icon resource
("error", "errors", "region.redish markup.error.lsp", "Packages/LSP/icons/error.png"),
("warning", "warnings", "region.yellowish markup.warning.lsp", "Packages/LSP/icons/warning.png"),
("info", "info", "region.bluish markup.info.lsp", "Packages/LSP/icons/info.png"),
("hint", "hints", "region.bluish markup.info.hint.lsp", "Packages/LSP/icons/info.png"),
]
# Kind CSS class Scope for color Icon resource add_regions flags for single-line diagnostic multi-line diagnostic # noqa: E501
("error", "errors", "region.redish markup.error.lsp", "Packages/LSP/icons/error.png", sublime.DRAW_NO_FILL | sublime.DRAW_NO_OUTLINE | sublime.DRAW_SQUIGGLY_UNDERLINE, sublime.DRAW_NO_FILL), # noqa: E501
("warning", "warnings", "region.yellowish markup.warning.lsp", "Packages/LSP/icons/warning.png", sublime.DRAW_NO_FILL | sublime.DRAW_NO_OUTLINE | sublime.DRAW_SQUIGGLY_UNDERLINE, sublime.DRAW_NO_FILL), # noqa: E501
("info", "info", "region.bluish markup.info.lsp", "Packages/LSP/icons/info.png", sublime.DRAW_NO_FILL | sublime.DRAW_NO_OUTLINE | sublime.DRAW_STIPPLED_UNDERLINE, sublime.DRAW_NO_FILL), # noqa: E501
("hint", "hints", "region.bluish markup.info.hint.lsp", "Packages/LSP/icons/info.png", sublime.DRAW_NO_FILL | sublime.DRAW_NO_OUTLINE | sublime.DRAW_STIPPLED_UNDERLINE, sublime.DRAW_NO_FILL), # noqa: E501
] # type: List[Tuple[str, str, str, str, int, int]]

# The scope names mainly come from http://www.sublimetext.com/docs/3/scope_naming.html
SYMBOL_KINDS = [
Expand Down
5 changes: 4 additions & 1 deletion plugin/documents.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,10 @@ def diagnostics_panel_contribution_async(self) -> List[Tuple[str, Optional[int],
# Sort by severity
for severity in range(1, len(DIAGNOSTIC_SEVERITY) + 1):
for sb in self.session_buffers_async():
data = sb.data_per_severity.get(severity)
data = sb.data_per_severity.get((severity, False))
if data:
result.extend(data.panel_contribution)
data = sb.data_per_severity.get((severity, True))
if data:
result.extend(data.panel_contribution)
# sort the result by asc line number
Expand Down
20 changes: 10 additions & 10 deletions plugin/session_buffer.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def __init__(self, severity: int) -> None:
self.regions_with_tag = {} # type: Dict[int, List[sublime.Region]]
self.annotations = [] # type: List[str]
self.panel_contribution = [] # type: List[Tuple[str, Optional[int], Optional[str], Optional[str]]]
_, _, self.scope, self.icon = DIAGNOSTIC_SEVERITY[severity - 1]
_, _, self.scope, self.icon, _, _ = DIAGNOSTIC_SEVERITY[severity - 1]
if userprefs().diagnostics_gutter_marker != "sign":
self.icon = userprefs().diagnostics_gutter_marker

Expand Down Expand Up @@ -76,7 +76,7 @@ def __init__(self, session_view: SessionViewProtocol, buffer_id: int, language_i
self.id = buffer_id
self.pending_changes = None # type: Optional[PendingChanges]
self.diagnostics = [] # type: List[Tuple[Diagnostic, sublime.Region]]
self.data_per_severity = {} # type: Dict[int, DiagnosticSeverityData]
self.data_per_severity = {} # type: Dict[Tuple[int, bool], DiagnosticSeverityData]
self.diagnostics_version = -1
self.diagnostics_flags = 0
self.diagnostics_are_visible = False
Expand Down Expand Up @@ -245,7 +245,7 @@ def some_view(self) -> Optional[sublime.View]:
return None

def on_diagnostics_async(self, raw_diagnostics: List[Diagnostic], version: Optional[int]) -> None:
data_per_severity = {} # type: Dict[int, DiagnosticSeverityData]
data_per_severity = {} # type: Dict[Tuple[int, bool], DiagnosticSeverityData]
total_errors = 0
total_warnings = 0
should_show_diagnostics_panel = False
Expand All @@ -259,12 +259,13 @@ def on_diagnostics_async(self, raw_diagnostics: List[Diagnostic], version: Optio
diagnostics_version = version
diagnostics = [] # type: List[Tuple[Diagnostic, sublime.Region]]
for diagnostic in raw_diagnostics:
region = range_to_region(Range.from_lsp(diagnostic["range"]), view)
rwols marked this conversation as resolved.
Show resolved Hide resolved
severity = diagnostic_severity(diagnostic)
data = data_per_severity.get(severity)
key = (severity, len(view.split_by_newlines(region)) > 1)
data = data_per_severity.get(key)
if data is None:
data = DiagnosticSeverityData(severity)
data_per_severity[severity] = data
region = range_to_region(Range.from_lsp(diagnostic["range"]), view)
data_per_severity[key] = data
tags = diagnostic.get('tags', [])
if tags:
for tag in tags:
Expand Down Expand Up @@ -293,7 +294,7 @@ def _publish_diagnostics_to_session_views(
self,
diagnostics_version: int,
diagnostics: List[Tuple[Diagnostic, sublime.Region]],
data_per_severity: Dict[int, DiagnosticSeverityData],
data_per_severity: Dict[Tuple[int, bool], DiagnosticSeverityData],
total_errors: int,
total_warnings: int,
should_show_diagnostics_panel: bool
Expand Down Expand Up @@ -336,7 +337,7 @@ def _present_diagnostics_async(
self,
diagnostics_version: int,
diagnostics: List[Tuple[Diagnostic, sublime.Region]],
data_per_severity: Dict[int, DiagnosticSeverityData],
data_per_severity: Dict[Tuple[int, bool], DiagnosticSeverityData],
total_errors: int,
total_warnings: int,
should_show_diagnostics_panel: bool
Expand All @@ -348,9 +349,8 @@ def _present_diagnostics_async(
self.total_errors = total_errors
self.total_warnings = total_warnings
self.should_show_diagnostics_panel = should_show_diagnostics_panel
flags = userprefs().diagnostics_highlight_style_to_add_regions_flag()
for sv in self.session_views:
sv.present_diagnostics_async(flags)
sv.present_diagnostics_async()
mgr = self.session.manager()
if mgr:
mgr.update_diagnostics_panel_async()
Expand Down
Loading