Pass State from Outer to Inner with multiplexingMode

I am using CodeMirror.multiplexingMode to add a minor modification to the standard jinja2 mode where I wish to style a couple of specific HTML tags if they appear in the text.

I have this working fine, except within the inner mode I want to be able to detect if the tags appear within a comment block from the outer mode and then skip highlighting them. Within the jinja2 mode we have state.incomment defined - how can I check the state of this when CodeMirror jumps into the inner mode (i.e. can I access the state variable of the outer mode from within the inner mode)?

I have had a look at multiplex.js and it has references to copyState and inner and outer, but I don’t understand if they help me or whether they are just there to support multiplexingMode.

multiplexingMode doesn’t provide the state of the other modes to modes. One possible approach would be to use an overlay mode instead and keep your own state to see where comments start and end.

Ok thanks, I have recreated the same functionality using overlayMode that I had with multiplexingMode, but with the same issue:

function cmOutputMode() {
  return {
    token: function(stream, state) {
      if (stream.match(/<\/?output.*>(?:\[-?[0-9]+\])?/)) {
        return "output";
      }
      stream.next();
    }
  };
}

CodeMirror.defineMode("template", function(config, parserConfig) {
  return CodeMirror.overlayMode(CodeMirror.getMode(config, "jinja2"), cmOutputMode());
});

The state variable exposed in cmOutputMode doesn’t seem to be the state from the jinja2 mode - I assume this isn’t what you meant. If I am using a standard mode, how can I track the state using overlayMode?

I could obviously hack the jinja2 mode and serve a custom copy, but I would prefer not to do this.

The CodeMirror text is as follows with the “output” tags inside a Jinja2 comment:

{#
<output>
...
</output>
#}

Ah, with overlayMode it passes the whole document, so I keep track of comments in my cmOutputMode! Something like this, which seems to do the trick!

function cmOutputMode() {
  return {
    startState: function() {
      return { 'incomment': false }
    },
    token: function(stream, state) {
      if (stream.match(/{#/)) {
        state.incomment = true;
      }
      else if (stream.match(/#}/)) {
        state.incomment = false;
      }
      if ((!state.incomment) && (stream.match(/<\/?output.*>(?:\[-?[0-9]+\])?/))) {
        return "output";
      }
      stream.next();
    }
  };
}

Final question - is there anyway of maintaining the original styling from the previous mode? For example, I am adding a font-weight: bold; via cm-output in my additional mode, but it drops the previous text color from the jinja2 mode where I have used jinja2 syntax within the tags - is it possible for the second mode to compliment the previous mode in styling?

I think the third argument to overlayMode, set to true, does what you are looking for.

This was perfect - thank you!