Search code examples
javascriptregexcodemirrorcodemirror-modes

Codemirror: Own Module Keywords


I try to write my owm module, for our own script language for codemirror.Right know I am hanging on our keywords.

I have this test-code:

Window(EditWin, SELECT_MULTIPLE, NO_SIZE, 310, 87, 500, 60, T("Sitzungsdatum", "Session date"))
{
     Prompt(SessionDatePmt, 11, 4, T("Sitzungsdatum", "Session date"))
     Date(SessionDate, 175, 4, 88)

     Button(SystemDateAsSessionDateBtn, 290, 3, 190, 10, T("Übernehme Systemdatum", "Get system date"))
     [ SELECT: SystemObject Call(SystemDate) PutObject(, SessionDate) ]
}

And some of our Keywords are:

  • Window
  • SELECT_MULTIPLE
  • NO_SIZE
  • Prompt
  • Date
  • Button
  • Select
  • SystemObject
  • Call
  • PutObject

For my regular expression, I use an array, called cons, with all keywords.

Then i join all the array entrys like this:

var keywordRegex = new RegExp("\\b(("+cons.join(")|(")+"))\\b");

Till there everything works fine. The regular expression i get, does work in normal javascript match(). I even fetched the text of my site using jQuery, and than used the regular expression, and got what I wanted.

But, when I do:

if (stream.match(keywordRegex)) return 'keyword';

in Codemirror, the Date of SessionDate is matched too.

Here is my whole Codemirror mode:

(function(mod) {
    if (typeof exports == "object" && typeof module == "object") // CommonJS
        mod(require("../../lib/codemirror"));
    else if (typeof define == "function" && define.amd) // AMD
        define(["../../lib/codemirror"], mod);
    else // Plain browser env
        mod(CodeMirror);
})(function(CodeMirror) {
    "use strict";
    CodeMirror.defineMode("testmode", function() {
        var cons = ['Window', 'SELECT_MULTIPLE', 'NO_SIZE', 'PROMPT', 'Date', 'Button', 'Select', 'SystemObject', 'Call', 'PutObject'];
        var keywordRegex = new RegExp("\\b(("+cons.join(")|(")+"))\\b");
        var numLiteral = /(-|\+)?([0-9]+(\.[0-9]*)?|0x[0-9a-f]+)/;
        return {
            token: function(stream, state) {
                if (stream.match(/^('([^']|\\.)*'?|"([^"]|\\.)*"?)/))
                    return "string";


                if (stream.match(keywordRegex)) return 'keyword';
                if (stream.match(/({|})/)) return "bracket";
                if (stream.match(numLiteral)) return "number";
                if (stream.match(/(->)/)) return "arrow";


                stream.next();
                return null;
            },
            startState: function() {
              return {
                pair: false,
                pairStart: false,
                keyCol: 0,
                inlinePairs: 0,
                inlineList: 0,
                literal: false,
                escaped: false
              };
            }
        };
    });

    CodeMirror.defineMIME("application/testmode", "testmode");
});

Edit:

As asked for, here is a working plunker:

http://plnkr.co/edit/bPyuJd?p=preview

There you can see, I don't have a keyword "SessionDate", but because of the Keyword "Date", the "Date" of "SessionDate" gets highlighted too.


Solution

  • It seems I have found a way to solve it. There is no support for anchors in Code Mirror:

    (The ^ regexp marker doesn't work as you'd expect in this context because of limitations in JavaScript's RegExp API.)

    Thus, use 2 regexps for the beginning of string condition and a mid-string position, and for the start-of-string position, check the position with stream.sol():

    var keywordRegex = new RegExp("("+cons.join("|")+")(?=\\W)");
    var midkeywordRegex = new RegExp("\\W("+cons.join("|")+")(?=\\W)");
    
    ...
    
    if (stream.sol() && stream.match(/('([^']|\\.)*'?|"([^"]|\\.)*"?)/))
        return "iv-string";
    
    if (stream.sol() && stream.match(keywordRegex)) return 'keyword';
    if (stream.match(midkeywordRegex)) return 'keyword';
    

    See Updated plunker