Highlight.js not respecting parent regex of a sub mode

Viewed 177

I need to write a lexer which highlights my command-line tool commands properly.

$ dvc add file.csv
$ dvc pipeline list

So the command starts with dvc and it may have one or two subcommands - add or pipeline list respectively.

Therefore, it should highlight dvc add and dvc pipeline list in first and second case respectively.

contains: [
          {
            begin: /^\s*\$\s(dvc|git) [a-z-]+/,
            returnBegin: true,
            contains: [
              {
                begin: /dvc [a-z-]+ ?/,
                lexemes: '[a-z-]+',
                keywords: {
                  built_in:
                    'dvc'
                },
                contains: [
                  {
                    begin: /\w+(?![\S])/,
                    keywords: {
                      built_in: 'list'
                    }
                  }
                ],
                className: 'strong'
              }
            ]
          }
        ]

It matches dvc pipeline list even though the parent regex i.e. /^\s*\$\s(dvc|git) [a-z-]+/ should only match till dvc pipeline. How is it exactly functioning?

How does /dvc [a-z-]+ ?/ override it and continues matching the expression?

Please refer to this library docs here: https://highlightjs.readthedocs.io/en/latest/reference.html

1 Answers

Begin only starts a match, it does not limit it. The first rule matches, then rewinds... then /dvc [a-z-]+ ?/ is matched which will then start looking for children in contains ... so then /\w+(?![\S])/ is matched (you're still inside your strong rule) so you'd see:

<strong>dvc pipeline list</strong>
<!-- matches /^\s*\$\s(dvc|git) [a-z-]+/ -->
  <!-- matches /dvc [a-z-]+ ?/ -->
  <strong>
    dvc pipeline   
      <!-- contains matches  /\w+(?![\S])/ --> 
      list
      <!-- no more matches for /\w+(?![\S])/ --> 
      <!-- end fires, back up -->
    <!-- no more matches for /dvc [a-z-]+ ?/-->
    <!-- end fires --> 
  </strong>
  <!-- back up -->

If you want to detect a bunch of different patterns I'd suggest different modes for each:

{ begin: /dvc add .../, contains: ... }
{ begin: /dvc pipeline .../, contains: ... }

Although you may also want to take a look at starts vs contains. Writing grammars to express match A, then B, then C can be quite difficult. The tools are there, but it can be very complex to get right and fraught with peril vs doing something simpler.

Related