Skip to content

Consistent highlight on derives' qualIds #240

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

Closed
wants to merge 2 commits into from

Conversation

tanishiking
Copy link
Member

fix: #239

vscode-scala-syntax couldn't provide consistent highlights for
C and D in derives C, D.

Screen Shot 2022-08-04 at 15 27 41

Problem

Consider we have the following code

enum A extends B derives C, D

Previously,
B and C have the following TextMate Scopes

entity.other.inherited-class.scala
source.scala

while D has

entity.name.class
source.scala

because it had accepted only one qualId after derived

match: `\\b(extends|with|derives)\\b\\s*(${idUpper}|${backQuotedId}|(?=\\([^\\)]+=>)|(?=${plainid})|(?="))?`,

even though Scala3 syntax allows us to put multiple qualIds.

Therefore, the first one will have entity.other.inherited-class.scala, but the following qualIds won't be named as
entity.other.inherited-class.scala. Instead, falllback to entity.name.class based on it's name (upper camel).

fix

This commit makes it provides consistent highlight for each qualId after derives keyword.
Now, both C and D will have entity.name.class instead of entity.other.inherited-class.scala.

alternative solution

It would be ideal to put entity.other.inherited-class.scala to both C and D,
but it looks like impossible with TextMate grammar.
Because according to the syntax
(see the syntax spec for Scala3 here https://docs.scala-lang.org/scala3/reference/syntax.html)
we can't tell where's the end of derives clause.

In the complete program, we can tell { or : is the end of derives
clause, but it messes up if the program is incomplete like

enum A extends B derives C, D

where there's no : or {.

So, just give up providing entity.other.inherited-class.scala and put entity.name.class based on their name (upper camel).

@tanishiking
Copy link
Member Author

@Meowcolm024 What do you think about this? you can check it by

  • check out this branch tanishiking:derives
  • yarn install, yarn build
  • code --install-extension scala-0.5.6.vsix
  • restart vscode

fix: scala#239

vscode-scala-syntax couldn't provide consistent highlights for
`C` and `D` in `derives C, D`.

Consider we have the following code

```scala
enum A extends B derives C, D
```

Previously,
`B` and `C` have the following TextMate Scopes

```
entity.other.inherited-class.scala
source.scala
```

while `D` has

```
entity.name.class
source.scala
```

because it had accepted only one qualId after `derived`
https://github.com/scala/vscode-scala-syntax/blob/0b2b1e8829254f0d190e723d3a49874cb7d135c0/src/typescript/Scala.tmLanguage.ts#L1156
even though Scala3 syntax allows us to put multiple qualIds.
Therefore, the first one will have `entity.other.inherited-class.scala`,
but the following qualIds won't be named as
`entity.other.inherited-class.scala`. Instead, falllback to
`entity.name.class` based on it's name (upper camel).

This commit makes it provide consistent highlight for each qualId after
`derives` keyword.
Now, both `C` and `D` will have `entity.name.class` instead of
`entity.other.inherited-class.scala`.

It would be ideal to put `entity.other.inherited-class.scala` to both `C` and `D`,
but it looks like impossible with TextMate grammer.
Because, according to the [syntax](https://dotty.epfl.ch/docs/reference/contextual/derivation.html#syntax)
(see the syntax spec for Scala3 here https://docs.scala-lang.org/scala3/reference/syntax.html)
we can't tell where's the end of `derives` clause.

In the complete program, we can tell `{` or `:` is the end of `derives`
clause, but it messes up if the program is incomplete like

```scala
enum A extends B derives C, D
```

where there's no `:` or `{`.

Just give up providing `entity.other.inherited-class.scala` and
put `entity.name.class` based on their name (upper camel).
Copy link
Contributor

@tgodzik tgodzik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for looking into this! 🎉

case B, c, D

enum A extends B derives X, Y, Z
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
enum A extends B derives X, Y, Z
enum A extends B, C derives X, Y, Z

wouldn't we have the same problem with extends?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, right!

@@ -1153,7 +1156,7 @@ export const scalaTmLanguage: TmLanguage = {
inheritance: {
patterns: [
{
match: `\\b(extends|with|derives)\\b\\s*(${idUpper}|${backQuotedId}|(?=\\([^\\)]+=>)|(?=${plainid})|(?="))?`,
match: `\\b(extends|with)\\b\\s*(${idUpper}|${backQuotedId}|(?=\\([^\\)]+=>)|(?=${plainid})|(?="))?`,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
match: `\\b(extends|with)\\b\\s*(${idUpper}|${backQuotedId}|(?=\\([^\\)]+=>)|(?=${plainid})|(?="))?`,
match: `\\b(extends|with|derives|,)\\b\\s*(${idUpper}|${backQuotedId}|(?=\\([^\\)]+=>)|(?=${plainid})|(?="))?`,

something like this wouldn't work?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so because it's too generic, that rule accepts any identifiers separated by , as entity.other.inherited-class.scala. For example A , B, B will be entity.other.inherited-class.scala though it's not.

It would be great if we can apply such rules only in extends and derives clause by

patterns: [
  {
    start: `\\b(extends|derives)`,
    end: ???,
    patterns: [
      // patterns that matches `qualId`s and assign name as `entity.other.inherited-class.scala`
    ]
  }
]

However, the problem is we can't tell what is the end of extends or derives.
(At first, I thought maybe we can end with : or { or <newline> but it doesn't work if derives clause contains new line)

class A derives B,
  C

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With new line that should be ok since we ended with , we still expect something to be after it, no?

@tanishiking
Copy link
Member Author

Decided to assign entity.name.class to A, B in extends A, B, maybe we should do the same thing for with A (even though it doesn't accept with A, B) for consistency 🤔

Screen Shot 2022-08-09 at 17 07 42

@@ -1165,6 +1168,18 @@ export const scalaTmLanguage: TmLanguage = {
}
]
},
derives: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Derives is a soft keyword, wouldn't it be an issue when someone uses it as an identifier?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it would be a problem.

derives, if it appears after an extension clause or after the name and possibly parameters of a class, trait, object, or enum definition.
https://docs.scala-lang.org/scala3/reference/soft-modifier.html

However, I don't think there's a way for regex to check the previous clause is "extension clause or after the name and possibly parameters of a class, trait, object, or enum definition."
(for using, we could determine it's after ( by positive-lookahead though).

@tanishiking
Copy link
Member Author

Closing for #242

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Wrong highlighting with derives in Scala 3
2 participants