0plus1 0plus1 - 1 month ago 13
Javascript Question

Codemirror, defineMode inside doublequotes

I am writing a custom overlay to create tokens of type

engage
for some custom functionality/styling.

I am currently creating tokens that are inside double quotes, such as
"EXP=SOMETHING"
I need though to get only what's between the double quotes:
EXP=SOMETHING
, I can easily skip the first quote and get something like
EXP=SOMETHING"
but I cannot seem to find a viable way to skip the last quote, I've been banging my head on this issue for so long I started to think it's not actually possible, as backing up by a character returns a
EXCEPTION: Uncaught (in promise): Error: Mode engage failed to advance stream.
which makes sense. I am sure I am missing something, I would love some input.

Follows the code that produces
EXP=SOMETHING"

Thanks for any help :-)

CodeMirror.defineMode("engage", function(config, parserConfig) {
var engageOverlay = {
startState: function() {return {inString: false};},
token: function(stream, state) {
// If we are not inside the engage token and we are peeking a "
if (!state.inString && stream.peek() == '"') {
// We move the stream to the next char
// Then mark the start of the string
// Then return null to avoid including the first " as part of the token
stream.next();
state.inString = true;
return null;
}

// We are inside the target token
if (state.inString)
{
if (stream.skipTo('"'))
{
stream.next();
state.inString = false;
}
else
{
stream.skipToEnd();
}
return "engage";
}
else
{
stream.skipTo('"') || stream.skipToEnd();
return null;
}
}
};
return CodeMirror.overlayMode(CodeMirror.getMode(config, parserConfig.backdrop || "xml"), engageOverlay);
});

Answer

If anybody stumbles upon this, here's the solution to the aforementioned problem:

// If we are not inside the engage token and we are peeking a "
      if ( !state.inString && stream.match(/="/, true) ) {
        state.inString = true;
        return null;
      }

      // We are inside the target token
      if (state.inString)
      {
        if (stream.skipTo('"'))
        {
          state.inString = false;
          return "engage";
        }
        else
        {
          stream.skipToEnd();
          return null;
        }
      }

      stream.next();
      return null;

We basically just distinguish between start and end of the double quotes, in my particular case I always had a = before the first ", if that it's not the case, you can easily set another flag.