Search code examples
javascriptcodemirrorcodemirror-modes

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);
});

Solution

  • 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.