Skip nested parentheses until closing parenthesis is reached

Hi everyone,

I’m working on a ‘blade’ mode for CodeMirror to support syntax highlighting for the Laravel Blade templating language. This language is similar to inline PHP, but uses {{ and }} to encapsulate PHP output instead of <?= or <?php. These double brackets are no problem, but the following is. Blade also has a syntax with @ statements, for example:

@if ($something === 'test')
   This will be echoed when $something is test.
@endif

In fact, everything between ‘@if (’ and ‘)’ is PHP code so should be highlighted like PHP. All the rest is HTML. Here is a screenshot of such highlighting in Sublime Text:

CleanShot 2020-05-05 at 21.52.56

I made a mode for this:

CodeMirror.defineMode('blade', function (config, parserConfig) {
  const closeComment = '--}}'

  return CodeMirror.multiplexingMode(CodeMirror.getMode(config, 'htmlmixed'), {
    open: '{{--',
    close: closeComment,
    delimStyle: 'comment',
    mode: {
      token: function (stream) {
        stream.skipTo(closeComment) || stream.skipToEnd()
        return 'comment'
      },
    },
  }, {
    open: '{{',
    close: '}}',
    mode: CodeMirror.getMode(config, 'application/x-httpd-php-open'),
  }, {
    open: '@if (',
    close: ')',
    mode: CodeMirror.getMode(config, 'application/x-httpd-php-open'),
  })
}, 'htmlmixed')

But this doesn’t work well for the @if statement. As you can see, the highlighting stops as soon as a closing parenthesis is reached:

CleanShot 2020-05-05 at 21.56.43

Is there a way to deal with this, so the parsing of parentheses is more intelligent and it handles nesting of parentheses better?

Thanks in advance for any help!

This is more complex than the multiplex helper can handle. You’ll have to write your own wrapping mode, which counts parentheses.