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

[Request] Multi-match for end matchers #3156

Closed
joshgoebel opened this issue Apr 20, 2021 · 3 comments · Fixed by #3159
Closed

[Request] Multi-match for end matchers #3156

joshgoebel opened this issue Apr 20, 2021 · 3 comments · Fixed by #3159
Assignees
Labels
enhancement An enhancement or new feature parser

Comments

@joshgoebel
Copy link
Member

joshgoebel commented Apr 20, 2021

Is your request related to a specific problem you're having?

Working on JSX I end up with the following mess:

{
    end: regex.lookahead(/<\/[A-Za-z-]+>|\/>/),
    starts: {
      contains: [
        { match: /\/>/, className: "tag", endsParent: true },
        { match:
          [/<\//, /[A-Za-z-]+/,/>/],
          className: {1: "tag", 2: "name", 3:"tag"},
          endsParent: true },
      ]
}

Once we find the end (with a look-ahead) we have to jump into a new mode (with starts) and two rules using multi-class on match/begin to highlight the individual pieces of tag as well as using endParent to prevent those same modes from gobbling up anymore then a SINGLE end tag.

And of course the look-ahead also prevents END_SAME_AS_BEGIN since we have no capture.

The solution you'd prefer / feature you'd like to see added...

Not sure.

{
  begin: ...,
  end: [ /</, /[A-Za-z-]+/, />/],
  scope: { 
    1: "tag", 2: ... // scopes for `begin`
    end: {1: "tag.bracket", 2: "tag.name", 3:"tag.bracket" }}
}

This is problematic though because eventually I'd like to use begin and end to allow scoping the ENTIRE begin and end block individually, ie:

{
  begin: /"/, end: /"/
  scope: { begin: "string.quote", end: "string.quote", middle: "string" }

Though I suppose a string vs an object is easy to differentiate at runtime.

A dedicated key is another option:

{
  end: [ /</, /[A-Za-z-]+/, />/ ],
  endScope: { 1: "tag.bracket", 2: "tag.name", 3:"tag.bracket" }
}

Any alternative solutions you considered...

TextMate grammars use captures, beginCaptures, endCaptures. Making a case for a separate key. A fuller example:

{
  begin: [ /</, /[A-Za-z-]+/ ],
  beginScope: {1: "tag.bracket", 2:"tag.name"},
  end: [ /</, /[A-Za-z-]+/, />/ ],
  endScope: { 1: "tag.bracket", 2: "tag.name", 3:"tag.bracket" }
}

With scope and match being sugar for beginScope and begin.

Additional context...

This is the next obvious improvement for multi-match.

@joshgoebel joshgoebel added enhancement An enhancement or new feature parser labels Apr 20, 2021
@joshgoebel
Copy link
Member Author

CC @highlightjs/core

@joshgoebel joshgoebel self-assigned this Apr 20, 2021
@joshgoebel
Copy link
Member Author

Oh but we still have the legacy behavior of scope/className as a string referring to the ENTIRE block... so that is problematic.

{
  begin: /"/, 
  end: /"/,
  scope: "string" // refers to the whole shebang: ".*"
}

So here scope vs beginScope would have VERY different output.

@joshgoebel
Copy link
Member Author

joshgoebel commented Apr 20, 2021

I think I'd also be fine going ultra-explicit and all the places we're currently using scope: [] we'd simply change them to beginScope... so then scope/className would retain it's prior behavior... string or nothing, and wrap the entire block. And if you want to get specific, use *Scope.

{
  begin: /"/, 
  end: /"/,
  scope: "string",
  beginScope: "string.delim",
  endScope: "string.delim",
}
"hello world"
<span class='string'><span class="string.delim">&quot;</span>hello world<span class="string.delim">&quot;</span></span>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement An enhancement or new feature parser
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant