-
Notifications
You must be signed in to change notification settings - Fork 188
"Goto Diagnostic" quick panels. #1884
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
Changes from all commits
d159ae2
e00a80f
2331053
7431acf
cb3fc4a
17c9134
18a3eca
4238443
379d399
0579708
442e11f
63e8948
0395b89
853553f
7b76e9a
d98f1ff
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -252,6 +252,33 @@ | |
| // } | ||
| // ] | ||
| // }, | ||
| // Goto Diagnostic | ||
| // { | ||
| // "command": "lsp_goto_diagnostic", | ||
| // "args": { | ||
| // "uri": "$view_uri" | ||
| // }, | ||
| // "keys": [ | ||
| // "f8" | ||
| // ], | ||
| // "context": [ | ||
| // { | ||
| // "key": "setting.lsp_active" | ||
| // } | ||
| // ] | ||
| // }, | ||
| // Goto Diagnostic in Project | ||
| // { | ||
| // "command": "lsp_goto_diagnostic", | ||
| // "keys": [ | ||
| // "shift+f8" | ||
| // ], | ||
| // "context": [ | ||
| // { | ||
| // "key": "setting.lsp_active" | ||
| // } | ||
| // ] | ||
|
Comment on lines
+276
to
+280
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd say that this one should have no context check because it should still work even if current file doesn't have any session.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is supposed to work for all files in project, even for those without a session, and it does.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It does work indeed but this context check is wrong because, if it would work, it would only allow this command to run when the active file has active session. The reason it doesn't cause problems is due to this being a
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or more precisely, the |
||
| // }, | ||
| // Rename | ||
| // { | ||
| // "command": "lsp_symbol_rename", | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,10 @@ | ||
| { | ||
| "*": { | ||
| ">=3124": [ | ||
| ">=4096": [ | ||
| "backrefs", | ||
| "bracex", | ||
| "mdpopups", | ||
| "pathlib", | ||
| "pyyaml", | ||
| "wcmatch" | ||
| ] | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,9 +1,12 @@ | ||||||||||||||||
| from .protocol import Diagnostic, DiagnosticSeverity | ||||||||||||||||
| from .settings import userprefs | ||||||||||||||||
| from .typing import Callable, Iterator, List, Optional, Tuple | ||||||||||||||||
| from .protocol import Diagnostic, DiagnosticSeverity, DocumentUri | ||||||||||||||||
| from .typing import Callable, Iterator, List, Tuple, TypeVar | ||||||||||||||||
| from .url import parse_uri | ||||||||||||||||
| from .views import diagnostic_severity, format_diagnostic_for_panel | ||||||||||||||||
| from .views import diagnostic_severity | ||||||||||||||||
| from collections import OrderedDict | ||||||||||||||||
| import functools | ||||||||||||||||
|
|
||||||||||||||||
| ParsedUri = Tuple[str, str] | ||||||||||||||||
| T = TypeVar('T') | ||||||||||||||||
|
|
||||||||||||||||
|
|
||||||||||||||||
| class DiagnosticsManager(OrderedDict): | ||||||||||||||||
|
|
@@ -17,44 +20,83 @@ class DiagnosticsManager(OrderedDict): | |||||||||||||||
| # | ||||||||||||||||
| # https://microsoft.github.io/language-server-protocol/specification#textDocument_publishDiagnostics | ||||||||||||||||
|
|
||||||||||||||||
| def add_diagnostics_async(self, uri: str, diagnostics: List[Diagnostic]) -> None: | ||||||||||||||||
| _, path = parse_uri(uri) | ||||||||||||||||
| def add_diagnostics_async(self, document_uri: DocumentUri, diagnostics: List[Diagnostic]) -> None: | ||||||||||||||||
| """ | ||||||||||||||||
| Add `diagnostics` for `document_uri` to the store, replacing previously received `diagnoscis` | ||||||||||||||||
| for this `document_uri`. If `diagnostics` is the empty list, `document_uri` is removed from | ||||||||||||||||
| the store. The item received is moved to the end of the store. | ||||||||||||||||
| """ | ||||||||||||||||
| uri = parse_uri(document_uri) | ||||||||||||||||
| if not diagnostics: | ||||||||||||||||
| # received "clear diagnostics" message for this path | ||||||||||||||||
| self.pop(path, None) | ||||||||||||||||
| # received "clear diagnostics" message for this uri | ||||||||||||||||
| self.pop(uri, None) | ||||||||||||||||
| return | ||||||||||||||||
| max_severity = userprefs().diagnostics_panel_include_severity_level | ||||||||||||||||
| self[path] = ( | ||||||||||||||||
| list( | ||||||||||||||||
| filter( | ||||||||||||||||
| None, | ||||||||||||||||
| ( | ||||||||||||||||
| format_diagnostic_for_panel(diagnostic) | ||||||||||||||||
| for diagnostic in diagnostics | ||||||||||||||||
| if diagnostic_severity(diagnostic) <= max_severity | ||||||||||||||||
| ), | ||||||||||||||||
| ) | ||||||||||||||||
| ), | ||||||||||||||||
| len(list(filter(has_severity(DiagnosticSeverity.Error), diagnostics))), | ||||||||||||||||
| len(list(filter(has_severity(DiagnosticSeverity.Warning), diagnostics))), | ||||||||||||||||
| ) | ||||||||||||||||
| self.move_to_end(path) # maintain incoming order | ||||||||||||||||
| self[uri] = diagnostics | ||||||||||||||||
| self.move_to_end(uri) # maintain incoming order | ||||||||||||||||
|
|
||||||||||||||||
| def filter_map_diagnostics_async(self, pred: Callable[[Diagnostic], bool], | ||||||||||||||||
| f: Callable[[ParsedUri, Diagnostic], T]) -> Iterator[Tuple[ParsedUri, List[T]]]: | ||||||||||||||||
| """ | ||||||||||||||||
| Yields `(uri, results)` items with `results` being a list of `f(diagnostic)` for each | ||||||||||||||||
| diagnostic for this `uri` with `pred(diagnostic) == True`, filtered by `bool(f(diagnostic))`. | ||||||||||||||||
| Only `uri`s with non-empty `results` are returned. Each `uri` is guaranteed to be yielded | ||||||||||||||||
| not more than once. Items and results are ordered as they came in from the server. | ||||||||||||||||
| """ | ||||||||||||||||
| for uri, diagnostics in self.items(): | ||||||||||||||||
| results = list(filter(None, map(functools.partial(f, uri), filter(pred, diagnostics)))) # type: List[T] | ||||||||||||||||
htmue marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||
| if results: | ||||||||||||||||
| yield uri, results | ||||||||||||||||
|
|
||||||||||||||||
| def diagnostics_panel_contributions_async( | ||||||||||||||||
| self, | ||||||||||||||||
| ) -> Iterator[Tuple[str, List[Tuple[str, Optional[int], Optional[str], Optional[str]]]]]: | ||||||||||||||||
| for path, (contribution, _, _) in self.items(): | ||||||||||||||||
| if contribution: | ||||||||||||||||
| yield path, contribution | ||||||||||||||||
| def filter_map_diagnostics_flat_async(self, pred: Callable[[Diagnostic], bool], | ||||||||||||||||
| f: Callable[[ParsedUri, Diagnostic], T]) -> Iterator[Tuple[ParsedUri, T]]: | ||||||||||||||||
| """ | ||||||||||||||||
| Flattened variant of `filter_map_diagnostics_async()`. Yields `(uri, result)` items for each | ||||||||||||||||
| of the `result`s per `uri` instead. Each `uri` can be yielded more than once. Items are | ||||||||||||||||
| grouped by `uri` and each `uri` group is guaranteed to appear not more than once. Items are | ||||||||||||||||
| ordered as they came in from the server. | ||||||||||||||||
| """ | ||||||||||||||||
| for uri, results in self.filter_map_diagnostics_async(pred, f): | ||||||||||||||||
| for result in results: | ||||||||||||||||
| yield uri, result | ||||||||||||||||
|
|
||||||||||||||||
| def sum_total_errors_and_warnings_async(self) -> Tuple[int, int]: | ||||||||||||||||
| """ | ||||||||||||||||
| Returns `(total_errors, total_warnings)` count of all diagnostics currently in store. | ||||||||||||||||
| """ | ||||||||||||||||
| return ( | ||||||||||||||||
| sum(errors for _, errors, _ in self.values()), | ||||||||||||||||
| sum(warnings for _, _, warnings in self.values()), | ||||||||||||||||
| sum(map(severity_count(DiagnosticSeverity.Error), self.values())), | ||||||||||||||||
| sum(map(severity_count(DiagnosticSeverity.Warning), self.values())), | ||||||||||||||||
| ) | ||||||||||||||||
|
|
||||||||||||||||
| def diagnostics_by_document_uri(self, document_uri: DocumentUri) -> List[Diagnostic]: | ||||||||||||||||
| """ | ||||||||||||||||
| Returns possibly empty list of diagnostic for `document_uri`. | ||||||||||||||||
| """ | ||||||||||||||||
| return self.get(parse_uri(document_uri), []) | ||||||||||||||||
|
|
||||||||||||||||
| def diagnostics_by_parsed_uri(self, uri: ParsedUri) -> List[Diagnostic]: | ||||||||||||||||
| """ | ||||||||||||||||
| Returns possibly empty list of diagnostic for `uri`. | ||||||||||||||||
| """ | ||||||||||||||||
| return self.get(uri, []) | ||||||||||||||||
|
|
||||||||||||||||
|
|
||||||||||||||||
| def severity_count(severity: int) -> Callable[[List[Diagnostic]], int]: | ||||||||||||||||
| def severity_count(diagnostics: List[Diagnostic]) -> int: | ||||||||||||||||
| return len(list(filter(has_severity(severity), diagnostics))) | ||||||||||||||||
|
|
||||||||||||||||
| return severity_count | ||||||||||||||||
|
Comment on lines
+84
to
+88
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can't this be a lambda?
Suggested change
|
||||||||||||||||
|
|
||||||||||||||||
|
|
||||||||||||||||
| def has_severity(severity: int) -> Callable[[Diagnostic], bool]: | ||||||||||||||||
| def has_severity(diagnostic: Diagnostic) -> bool: | ||||||||||||||||
| return diagnostic_severity(diagnostic) == severity | ||||||||||||||||
|
|
||||||||||||||||
| return has_severity | ||||||||||||||||
|
Comment on lines
91
to
95
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe turn this into a lambda as well?
Suggested change
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These I would leave as they are because it's immediately clear from the layout that they are just curried functions, with lambdas this would be a little harder to get. A proper @curry
def is_severity_included(max_severity: ..., diagnostic: ...) -> ...:
return diagnostic_severity(diagnostic) <= max_severityThere is one in the
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm personally not accustomed to the use of curried functions. I see a callable as return type and would expect a
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One downside of lambdas is that those can't be type-annotated properly.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would recommend Currying is really cool, but it's not native to Python and will forever feel alien unless it becomes integrated and more Python developers get to know it. The fact that a calling any function may return another function if it isn't provided with all its requested arguments just doesn't apply to languages without this concept at its core. |
||||||||||||||||
|
|
||||||||||||||||
|
|
||||||||||||||||
| def is_severity_included(max_severity: int) -> Callable[[Diagnostic], bool]: | ||||||||||||||||
| def severity_included(diagnostic: Diagnostic) -> bool: | ||||||||||||||||
| return diagnostic_severity(diagnostic) <= max_severity | ||||||||||||||||
|
|
||||||||||||||||
| return severity_included | ||||||||||||||||
|
Comment on lines
+98
to
+102
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Lambda?
Suggested change
|
||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.