-
Notifications
You must be signed in to change notification settings - Fork 589
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
[Python] Add syntax highlighting for type comments #1925
Conversation
Can there be a space in between |
It's not explicit in the PEP, but both MyPy and PyCharm treat |
5361354
to
5850d11
Compare
seems unlikely, comments could have a background color for example, plus the scope specificity means the |
In that case, |
ah good point. But in this context, do we not know for sure that it is a class, such that it can be assigned |
5850d11
to
137308c
Compare
I've had this on my todo, but ideally I'd like to see #1842 (comment) resolved because it will hugely affect the type of scopes to be used. Python currently doesn't have highlighting of user types, i.e. class names, but I would like to change that for both type comments and variable/function annotations. However, I'm undecided on the particular scope to use. Do they get |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apparently I had let a bunch of comments, but forgot to "complete" the review - sorry!
- Add Python to type hint scopes - Highlight Mypy's ignore codes - handle type: ignore_something_else as a non-special class name
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noted a number of things that should be tweaked, some stylistic stuff and a couple of questions.
At the high level I think one of my concerns with the current state is how the comment
scopes are stacked multiple times in places. This generally it not what we want to do, but rather specialize. For example, perhaps the first part of the comment is comment.line.type-comment
, but as you hit the second #
it would switch to comment.line.number-sign
.
- Removes some out-of-order stacked scopes - Removes some duplicated scopes - Removes some improper suffixes - Changes context names to fix existing style - Simplifies scope assertions in test file
I think I've resolved the issues I found during review. If anyone is up for a final review, I'll plan on merging this soon. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't or hardly can comment on the actual syntax definition but added some comments about the python examples in the tests.
@@ -1490,70 +1490,80 @@ class Starship: | |||
# Type comments - type: ignore must be by itself. | |||
|
|||
primes = 5 # type: ignore # type: not-a-type-comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just for clarification
primes = 5 # type: ignore # type: str // technically ok but weird
primes = 5 # type: str # type: ignore // not tested here but typical
primes = 5 # type: str # type: str // not tested here and invalid
(I don't know how fine-grained these tests are here.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The impression I had gotten from the previous implementation was that line comments added into a type comment effectively ended the processing of mypy. Is that true?
From your comment above, it almost sounds like mypy will process nested comments that start with type:
and the only logical combinations are type: ignore
and a normal type:
comment, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe mypy stops after the first type: ignore
comment. 🤷 After that everything is "egal". The only thing you see in practice is # type: str # type: ignore
to brutally force a type. And typical # type: ignore[foo-rule] # mypy bug https:\\issue-nr
because you really get hit by a mypy bug every other day.
@rwols Can you paste text of a couple of snippets where you see failures? @kaste I'm tempted to get rid of trying to mark things as invalid, and instead just highlight the things known to be valid, thoughts? You may also have some thoughts @FichteFoll as you've worked on marking various things as invalid in this syntax before. |
Sorry for not pasting the text, it was late :) The last two commits e3b57a9 and 97ae638 fixed the problem. My only remark now is that the syntax contexts from the return type and the Minimal reproducible case: def f() -> List[str]:
# ^^^^ support.class
x = [] # type: List[str]
# ^^^^ support.class Perhaps it can be argued that they shouldn't share the same context. But I don't know what else you'd use the This is still broken: class SessionBufferProtocol(Protocol):
session = None # type: Session
view = None # type: sublime.View
# ^ - invalid.illegal
session_views = None # type: WeakSet[SessionViewProtocol]
file_name = None # type: str
def on_diagnostics_async(self, diagnostics: List[Dict[str, Any]], version: Optional[int]) -> None:
... It's perfectly legal to type-hint something from another module. |
Minimal reproduction case: x = [] # type: List[sublime.Region] |
There's also this issue: x = [] # type: 'List[ParameterInformation]'
# ^ - invalid.illegal
# ^ - invalid.illegal While it looks a bit weird, it's allowed to wrap the type in a string (single-quotes or double-quotes). Used for forward declarations. |
I figured I'd take a quick pass at some fixes, but it seems this requires a fair bit more work. I'm probably gonna hit pause for now and move onto other things. |
FWIW: There is also no "tuple" thing The only fancy thing left is |
@@ -1519,51 +1519,46 @@ class Starship: | |||
# ^^^^^ comment.line.number-sign - comment.line.type-hint | |||
|
|||
# With/for allow commas | |||
for a, b in lst: # type: str, int | |||
# ^ comment.line.type-hint punctuation.separator.sequence | |||
for a, b in lst: # type: (str, int) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The parens in (str, int)
are not allowed. It's actually Tuple[str, int]
. They take explicit > implicit seriously.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am uncertain here. I've created a little test file with
from typing import Tuple
def testing(results):
for a, b in results: # type: Tuple[int, str]
print(a, b)
Hovering a
or b
with LSP and LSP-pylsp installed, doesn't show anything, while an example using current syntax with or without parentheses works fine.
def testing(results):
for a, b in results: # type: (int, str)
print(a, b)
It also makes sense as I found some comments about such type hints to date back to python 2.7 which doesn't know about typing
module.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The related spec can be found at https://mypy.readthedocs.io/en/stable/type_inference_and_annotations.html#declaring-multiple-variable-types-at-a-time
Generally, I don't expect Sublime marks my syntax errors as "invalid". The invalid scope is hard to edit and read, and I sure don't expect it at all. I always thought it is an escape hatch just before the syntax engine becomes incapable of "fixing" it, i.e. keeping the colors reasonable. (T.i. I don't expect it to read my code actually.) I just found it strange to have so many invalid examples in the few python test lines. |
I generally prefer to use invalid scopes only when the syntax parsing reaches a state it cannot recover due to invalid syntax, such as keywords being used when they are not allowed, or when the user is likely to have made an error such as for stray braces. It seems debatable, whether a type comment is a strongly parsed region, considering that on one hand comments are free-form, but on the other hand type comments are expected to be parsed by a type checker. I have never used type comments in Python myself, so I can only comment in a general sense, but my biggest issue is matching any identifier as In fact, running a grep on the entire Packages repos show
|
Just as a procedural note, I probably am not going to have the time to hash out RFC scope names before we get to an ST4 public release. I do want to address them at some point in the future, but they don't make the priority cut at this point. |
Added results for |
@TeamSpen210 Maybe you could update this PR, merge the latest changes from Tests are run against the current dev build from https://www.sublimetext.com/dev. |
I guess he would already have done it, if he was interested in. |
Closing in favor of #3736, which covers all kinds of type annotation supported by current versions of python. |
This commit adds dedicated contexts for type hints. It provides highlighting for type comments including feedback from #1925. Existing type annotations are refactored to follow a common scope naming scheme for type hints. It is inspired by PHP, TS and TSX, which use `meta.type` to scope type hint expressions. The content however remains being handled by normal expressions, even though the primary use case these days are type-hints. That's required as python accepts all kinds of expressions within annotations. Known type classes from typing module are scoped as `support.class.typing`.
This makes
#type:
comments highlighted as normal code (since type checkers expect these to be valid syntax), and treats#type: ignore
as a keyword. I'm not sure though if it should additionally have thecomment.*
scope for the line - any schemes would probably ignore the additional highlighting and make it appear as a comment.