Skip to content
Snippets Groups Projects
matefun-mode-EN.js 13.1 KiB
Newer Older
(function(mod) {
  if (typeof exports == "object" && typeof module == "object") // CommonJS
    mod(require("codemirror/lib/codemirror"));
  else if (typeof define == "function" && define.amd) // AMD
    define(["codemirror/lib/codemirror"], mod);
  else // Plain browser env
    mod(CodeMirror);
})(function(CodeMirror) {
  "use strict";

  CodeMirror.defineMode("matefun-EN", function(_config, modeConfig) {

    function switchState(source, setState, f) {
      setState(f);
      return f(source, setState);
    }

    var smallRE = /[a-z_]/;
    var largeRE = /[A-Z]/;
    var digitRE = /\d/;
    var hexitRE = /[0-9A-Fa-f]/;
    var octitRE = /[0-7]/;
    var idRE = /[a-z_A-Z0-9'\xa1-\uffff]/;
    var symbolRE = /[-!#$%&*+.\/<=>?@\\^|~:]/;
    var specialRE = /[(),;[\]`{}]/;
  var whiteCharRE = /[ \t\v\f]/; // newlines are handled in tokenizer

  const hintWords = require('./hint_words');
Franco Pariani's avatar
Franco Pariani committed
  var SET = /set\s*([\w\_\d]*?)\s*\=/;
Franco Pariani's avatar
Franco Pariani committed
  var FUNS = /([\w\_\d]*)\s*\:\:/;
  var FUN = /([\w\_\d]+)\s*\(([\,\w\_\s\d]*)\)\s*\=/;
  var ENUMS = /set\s*[\w\_\d]*\s*\=\s*\{(.*?)\}/;
  var WRITING_SET = /set\s/;
  var WRITING_COMMENT = /\{\-/;

  var RANGE = 500;

  CodeMirror.registerHelper("hint", "anyword", function(editor, options) {
    var word = options && options.word || WORD;
    var range = options && options.range || RANGE;
    var cur = editor.getCursor(), curLine = editor.getLine(cur.line);
    var end = cur.ch, start = end;
    while (start && word.test(curLine.charAt(start - 1))) --start;
    var curWord = start != end && curLine.slice(start, end);

    var list = options && options.list || [], seen = {};
Franco Pariani's avatar
Franco Pariani committed
    
    // not word = 'Enter'
    if (options.key == 'Enter'){
      var previous_line = editor.getLine(cur.line - 1);
      var re_funs = new RegExp(FUNS.source, "g"), match;
      if (previous_line && (match = re_funs.exec(previous_line))){
Franco Pariani's avatar
Franco Pariani committed
        var previous_block = "";
        for (var i = 0; i < cur.line; i++){
Franco Pariani's avatar
Franco Pariani committed
          previous_block += editor.getLine(i) + '\n';
        }
        var next_block = "";
        for (var i = cur.line + 1; i < editor.lastLine(); i++){
          next_block += editor.getLine(i) + '\n';
        }
        var file = previous_block + match[1] + ' ()';
        if (next_block != ""){
          file = file + '\n' + next_block;
        }
        editor.setValue(file);
        editor.setCursor(CodeMirror.Pos(cur.line, match[1].length + 2));
      }
    }else{
      var previous_part = curLine.slice(0, start);
      
      var re_w_s = new RegExp(WRITING_SET.source, "g");
      var re_w_c = new RegExp(WRITING_COMMENT.source, "g");

      if (!re_w_s.exec(previous_part) && !re_w_c.exec(previous_part)){
        // sets
        var re_dom = new RegExp(DOM.source, "g");
        if (re_dom.exec(previous_part)){
          var re_sets = new RegExp(SET.source, "g");
Franco Pariani's avatar
Franco Pariani committed

          for (var dir = -1; dir <= 1; dir += 2) {
            var line = cur.line, endLine = Math.min(Math.max(line + dir * range, editor.firstLine()), editor.lastLine()) + dir;
            for (; line != endLine; line += dir) {
              var text = editor.getLine(line), m;
              while (m = re_sets.exec(text)) {
                if (line == cur.line && m[1] === curWord) continue;
Franco Pariani's avatar
Franco Pariani committed
                if ((!curWord || m[1].lastIndexOf(curWord, 0) == 0) && !Object.prototype.hasOwnProperty.call(seen, m[1])) {
                  seen[m[1]] = true;
                  list.push(m[1]);
                }
              }
            }
          }

          // add default sets
          var default_sets = hintWords.EN_default_sets();
          for (var i = 0; i < default_sets.length; i++) {
            if ((!curWord || default_sets[i].lastIndexOf(curWord, 0) == 0) && !Object.prototype.hasOwnProperty.call(seen, default_sets[i])) {
              seen[default_sets[i]] = true;
              list.push(default_sets[i]);
            }
          }
        }else{
          // get variables of function
          var previous_block = "";
          for (var i = 0; i < cur.line; i++){
            previous_block += editor.getLine(i) + '\n';
          }
          previous_block += previous_part;
          var re_fun = new RegExp(FUN.source, "g"), match, last_match;
          while (match = re_fun.exec(previous_block)){ last_match = match };
          if (last_match){
            var vars = last_match[2].replace(/\s/g,'').split(',');
            for (var i = 0; i < vars.length; i++) {
              if ((!curWord || vars[i].lastIndexOf(curWord, 0) == 0) && !Object.prototype.hasOwnProperty.call(seen, vars[i])) {
                seen[vars[i]] = true;
                list.push(vars[i]);
              }
            }

            // get enums
            var re_enums = new RegExp(ENUMS.source, "g");
            for (var dir = -1; dir <= 1; dir += 2) {
              var line = cur.line, endLine = Math.min(Math.max(line + dir * range, editor.firstLine()), editor.lastLine()) + dir;
              for (; line != endLine; line += dir) {
                var text = editor.getLine(line), m;
                while (m = re_enums.exec(text)) {
                  var enums = m[1].replace(/\s/g,'').split(',');
                  for (var i = 0; i < enums.length; i++) {
                    if ((!curWord || enums[i].lastIndexOf(curWord, 0) == 0) && !Object.prototype.hasOwnProperty.call(seen, enums[i])) {
                      seen[enums[i]] = true;
                      list.push(enums[i]);
                    }
                  }
                }
              }
            }
            // get functions
            var re_funs = new RegExp(FUNS.source, "g");
            for (var dir = -1; dir <= 1; dir += 2) {
              var line = cur.line, endLine = Math.min(Math.max(line + dir * range, editor.firstLine()), editor.lastLine()) + dir;
              for (; line != endLine; line += dir) {
                var text = editor.getLine(line), m;
                while (m = re_funs.exec(text)) {
                  if ((!curWord || m[1].lastIndexOf(curWord, 0) == 0) && !Object.prototype.hasOwnProperty.call(seen, m[1])) {
                    seen[m[1]] = true;
                    list.push(m[1]);
                  }
                }
              }
            }
            // add default functions
            var default_functions = hintWords.EN_functions();
            for (var i = 0; i < default_functions.length; i++) {
              if ((!curWord || default_functions[i].lastIndexOf(curWord, 0) == 0) && !Object.prototype.hasOwnProperty.call(seen, default_functions[i])) {
                seen[default_functions[i]] = true;
                list.push(default_functions[i]);
              }
            }
          }
        }
      }
    }
    return {list: list, from: CodeMirror.Pos(cur.line, start), to: CodeMirror.Pos(cur.line, end)};
  });
  function normal(source, setState) {
    if (source.eatWhile(whiteCharRE)) {
      return null;
    }

    var ch = source.next();
    if (specialRE.test(ch)) {
      if (ch == '{' && source.eat('-')) {
        var t = "comment";
        if (source.eat('#')) {
          t = "meta";
        }
        return switchState(source, setState, ncomment(t, 1));
      }
      return null;
    }

    if (ch == '\'') {
      if (source.eat('\\')) {
        source.next();  // should handle other escapes here
      }
      else {
        source.next();
      }
      if (source.eat('\'')) {
        return "string";
      }
      return "string error";
    }

    if (ch == '"') {
      return switchState(source, setState, stringLiteral);
    }

    if (largeRE.test(ch)) {
      source.eatWhile(idRE);
      if (source.eat('.')) {
        return "qualifier";
      }
      return "variable-2";
    }

    if (smallRE.test(ch)) {
      source.eatWhile(idRE);
      return "variable";
    }

    if (digitRE.test(ch)) {
      if (ch == '0') {
        if (source.eat(/[xX]/)) {
          source.eatWhile(hexitRE); // should require at least 1
          return "integer";
        }
        if (source.eat(/[oO]/)) {
          source.eatWhile(octitRE); // should require at least 1
          return "number";
        }
      }
      source.eatWhile(digitRE);
      var t = "number";
      if (source.match(/^\.\d+/)) {
        t = "number";
      }
      if (source.eat(/[eE]/)) {
        t = "number";
        source.eat(/[-+]/);
        source.eatWhile(digitRE); // should require at least 1
      }
      return t;
    }

    if (ch == "." && source.eat("."))
      return "keyword";

    if (symbolRE.test(ch)) {
      if (ch == '-' && source.eat(/-/)) {
        source.eatWhile(/-/);
        if (!source.eat(symbolRE)) {
          source.skipToEnd();
          return "comment";
        }
      }
      var t = "variable";
      if (ch == ':') {
        t = "variable-2";
      }
      source.eatWhile(symbolRE);
      return t;
    }

    return "error";
  }

  function ncomment(type, nest) {
    if (nest == 0) {
      return normal;
    }
    return function(source, setState) {
      var currNest = nest;
      while (!source.eol()) {
        var ch = source.next();
        if (ch == '{' && source.eat('-')) {
          ++currNest;
        }
        else if (ch == '-' && source.eat('}')) {
          --currNest;
          if (currNest == 0) {
            setState(normal);
            return type;
          }
        }
      }
      setState(ncomment(type, currNest));
      return type;
    };
  }

  function stringLiteral(source, setState) {
    while (!source.eol()) {
      var ch = source.next();
      if (ch == '"') {
        setState(normal);
        return "string";
      }
      if (ch == '\\') {
        if (source.eol() || source.eat(whiteCharRE)) {
          setState(stringGap);
          return "string";
        }
        if (source.eat('&')) {
        }
        else {
          source.next(); // should handle other escapes here
        }
      }
    }
    setState(normal);
    return "string error";
  }

  function stringGap(source, setState) {
    if (source.eat('\\')) {
      return switchState(source, setState, stringLiteral);
    }
    source.next();
    setState(normal);
    return "error";
  }


  var wellKnownWords = (function() {
    var wkw = {};
    function setType(t) {
      return function () {
        for (var i = 0; i < arguments.length; i++)
          wkw[arguments[i]] = t;
      };
    }

    setType("keyword")(
     "include"
     ,"set","in"
     ,"if", "or" 
     ,"isEmpty");

    setType("keyword")("<-", "->");

    setType("builtin")("-", "+", "*", "/","^","!",":","==","/=","<",">","<=",">=","::","->","X","|");

    //tipos predefinidos
    setType("builtin")("Red", "Green", "Blue", "Black","White","Gray","Yellow","FigEmpty", "[]"
      ,"R", "Fig", "Fig3D", "Color", "color3D", "join3D", "rotate3D", "move3D"
      );

    setType("builtin")(
      "abs", "acos", "acosh", "all", "and", "any", "appendFile", "asTypeOf",
      "asin", "asinh", "atan", "atan2", "atanh", "break", "catch", "ceiling",
      "compare", "concat", "concatMap", "const", "cos", "cosh", "curry",
      "cycle", "decodeFloat", "div", "divMod", "drop", "dropWhile", "either",
      "elem", "encodeFloat", "enumFrom", "enumFromThen", "enumFromThenTo",
      "enumFromTo", "error", "even", "exp", "exponent", "fail", "filter",
      "flip", "floatDigits", "floatRadix", "floatRange", "floor", "fmap",
      "foldl", "foldl1", "foldr", "foldr1", "fromEnum", "fromInteger",
      "fromIntegral", "fromRational", "fst", "gcd", "getChar", "getContents",
      "getLine", "head", "id", "init", "interact", "ioError", "isDenormalized",
      "isIEEE", "isInfinite", "isNaN", "isNegativeZero", "iterate", "last",
      "lcm", "length", "lex", "lines", "log", "logBase", "lookup", "map",
      "mapM", "mapM_", "max", "maxBound", "maximum", "maybe", "min", "minBound",
      "minimum", "mod", "negate", "not", "notElem", "null", "odd", "or",
      "otherwise", "pi", "pred", "print", "product", "properFraction",
      "putChar", "putStr", "putStrLn", "quot", "quotRem", "read", "readFile",
      "readIO", "readList", "readLn", "readParen", "reads", "readsPrec",
      "realToFrac", "recip", "rem", "repeat", "replicate", "return", "reverse",
      "round", "scaleFloat", "scanl", "scanl1", "scanr", "scanr1", "seq",
      "sequence", "sequence_", "show", "showChar", "showList", "showParen",
      "showString", "shows", "showsPrec", "significand", "signum", "sin",
      "sinh", "snd", "span", "splitAt", "sqrt", "subtract", "succ", "sum",
      "tail", "take", "takeWhile", "tan", "tanh", "toEnum", "toInteger",
      "toRational", "truncate", "uncurry", "undefined", "unlines", "until",
      "unwords", "unzip", "unzip3", "userError", "words", "writeFile", "zip",
      "zip3", "zipWith", "zipWith3");

    var override = modeConfig.overrideKeywords;
    if (override) for (var word in override) if (override.hasOwnProperty(word))
      wkw[word] = override[word];

    return wkw;
  })();



  return {
    startState: function ()  { return { f: normal }; },
    copyState:  function (s) { return { f: s.f }; },

    token: function(stream, state) {
      var t = state.f(stream, function(s) { state.f = s; });
      var w = stream.current();
      return wellKnownWords.hasOwnProperty(w) ? wellKnownWords[w] : t;
    },

    blockCommentStart: "{-",
    blockCommentEnd: "-}",
    lineComment: "--"
  };

});

CodeMirror.defineMIME("text/x-matefun", "matefun-EN");