Vince
Vince

Reputation: 4401

new mode for codemirror : Detecting an empty line in a stream

I am trying to develop a simple mode for codemirror. This mode will colour paragraphs alternatively in blue and green. A separation between paragraph is an empty line or a line containing only spaces.

Here is a version of the code that works, but with the big issue that empty lines are not detected:

CodeMirror.defineMode("rt", function() {
  return {
    startState: function() {return {state1: true};},
    token: function(stream, state) {
    if (stream.match(/\s\s*/)!=null){ # this fails to detect empty lines
        state.state1 = !state.state1;
    }
    stream.skipToEnd();
    if (state.state1)  { return "status1"; } 
    return "status2";
    }
  };
});

if I apply it to the following text:

line 1
line 2 # the next line is just a backspace and is not detected

line 3
line 4 # the next line is a few spaces followed by a backspace, it is detected

line 5
line 6

it colors from line 1 to line 4 in one color and line 5 to line 6 in another, which is expected.

I am trying to find a way to update my code so that it detects the empty line between line 2 and line 3. Any way to do this ?

Upvotes: 0

Views: 1489

Answers (2)

Vince
Vince

Reputation: 4401

The documentation of codemirror says:

By default, blank lines are simply skipped when tokenizing a document. For languages that have significant blank lines, you can define a blankLine(state) method on your mode that will get called whenever a blank line is passed over, so that it can update the parser state.

(http://codemirror.net/doc/manual.html#modeapi)

The following code works (blankLine function added):

CodeMirror.defineMode("rt", function() {
  return {
    startState: function() {return {state1: true};},
    blankLine: function (state){ state.state1 = !state.state1; },
    token: function(stream, state) {
    console.log(stream)
    if (stream.match(/^\s*$/)!=null){
        state.state1 = !state.state1;
    }
    stream.skipToEnd();
    if (state.state1)  { return "status1"; } 
    return "status2";
    }
  };
});

Upvotes: 2

AlexStack
AlexStack

Reputation: 17381

You can detect backspace with [\b] in javascript regexp: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions

BTW /\s\s*/ can be simplified to /\s+/ however if you want to detect "an empty line or a line containing only spaces", you can use /\s*/.

Also if you don't care about the actual result array of the regular expression, you can use test() instead: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test

You can use ^ to indicate the beginning of the line and $ for the line end.

So the code will be roughly like this:

CodeMirror.defineMode("rt", function() {
  return {
    startState: function() {
      return {
        state1: true
      };
    },
    token: function(stream, state) {
      if ( /^\s*$/m.test(stream) ) {
        state.state1 = !state.state1;
      }
      stream.skipToEnd();
      return state.state1 ? "status1" : "status2";
    }
  };
});

The m flag is used to specify that a multiline input string should be treated as multiple lines. If the m flag is used, ^ and $ match at the start or end of any line within the input string instead of the start or end of the entire string. Example: http://www.w3schools.com/jsref/jsref_regexp_m.asp

Upvotes: 2

Related Questions