cypher.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2. // Distributed under an MIT license: https://codemirror.net/LICENSE
  3. // By the Neo4j Team and contributors.
  4. // https://github.com/neo4j-contrib/CodeMirror
  5. (function(mod) {
  6. if (typeof exports == "object" && typeof module == "object") // CommonJS
  7. mod(require("../../lib/codemirror"));
  8. else if (typeof define == "function" && define.amd) // AMD
  9. define(["../../lib/codemirror"], mod);
  10. else // Plain browser env
  11. mod(CodeMirror);
  12. })(function(CodeMirror) {
  13. "use strict";
  14. var wordRegexp = function(words) {
  15. return new RegExp("^(?:" + words.join("|") + ")$", "i");
  16. };
  17. CodeMirror.defineMode("cypher", function(config) {
  18. var tokenBase = function(stream/*, state*/) {
  19. var ch = stream.next();
  20. if (ch ==='"') {
  21. stream.match(/.*?"/);
  22. return "string";
  23. }
  24. if (ch === "'") {
  25. stream.match(/.*?'/);
  26. return "string";
  27. }
  28. if (/[{}\(\),\.;\[\]]/.test(ch)) {
  29. curPunc = ch;
  30. return "node";
  31. } else if (ch === "/" && stream.eat("/")) {
  32. stream.skipToEnd();
  33. return "comment";
  34. } else if (operatorChars.test(ch)) {
  35. stream.eatWhile(operatorChars);
  36. return null;
  37. } else {
  38. stream.eatWhile(/[_\w\d]/);
  39. if (stream.eat(":")) {
  40. stream.eatWhile(/[\w\d_\-]/);
  41. return "atom";
  42. }
  43. var word = stream.current();
  44. if (funcs.test(word)) return "builtin";
  45. if (preds.test(word)) return "def";
  46. if (keywords.test(word)) return "keyword";
  47. return "variable";
  48. }
  49. };
  50. var pushContext = function(state, type, col) {
  51. return state.context = {
  52. prev: state.context,
  53. indent: state.indent,
  54. col: col,
  55. type: type
  56. };
  57. };
  58. var popContext = function(state) {
  59. state.indent = state.context.indent;
  60. return state.context = state.context.prev;
  61. };
  62. var indentUnit = config.indentUnit;
  63. var curPunc;
  64. var funcs = wordRegexp(["abs", "acos", "allShortestPaths", "asin", "atan", "atan2", "avg", "ceil", "coalesce", "collect", "cos", "cot", "count", "degrees", "e", "endnode", "exp", "extract", "filter", "floor", "haversin", "head", "id", "keys", "labels", "last", "left", "length", "log", "log10", "lower", "ltrim", "max", "min", "node", "nodes", "percentileCont", "percentileDisc", "pi", "radians", "rand", "range", "reduce", "rel", "relationship", "relationships", "replace", "reverse", "right", "round", "rtrim", "shortestPath", "sign", "sin", "size", "split", "sqrt", "startnode", "stdev", "stdevp", "str", "substring", "sum", "tail", "tan", "timestamp", "toFloat", "toInt", "toString", "trim", "type", "upper"]);
  65. var preds = wordRegexp(["all", "and", "any", "contains", "exists", "has", "in", "none", "not", "or", "single", "xor"]);
  66. var keywords = wordRegexp(["as", "asc", "ascending", "assert", "by", "case", "commit", "constraint", "create", "csv", "cypher", "delete", "desc", "descending", "detach", "distinct", "drop", "else", "end", "ends", "explain", "false", "fieldterminator", "foreach", "from", "headers", "in", "index", "is", "join", "limit", "load", "match", "merge", "null", "on", "optional", "order", "periodic", "profile", "remove", "return", "scan", "set", "skip", "start", "starts", "then", "true", "union", "unique", "unwind", "using", "when", "where", "with", "call", "yield"]);
  67. var operatorChars = /[*+\-<>=&|~%^]/;
  68. return {
  69. startState: function(/*base*/) {
  70. return {
  71. tokenize: tokenBase,
  72. context: null,
  73. indent: 0,
  74. col: 0
  75. };
  76. },
  77. token: function(stream, state) {
  78. if (stream.sol()) {
  79. if (state.context && (state.context.align == null)) {
  80. state.context.align = false;
  81. }
  82. state.indent = stream.indentation();
  83. }
  84. if (stream.eatSpace()) {
  85. return null;
  86. }
  87. var style = state.tokenize(stream, state);
  88. if (style !== "comment" && state.context && (state.context.align == null) && state.context.type !== "pattern") {
  89. state.context.align = true;
  90. }
  91. if (curPunc === "(") {
  92. pushContext(state, ")", stream.column());
  93. } else if (curPunc === "[") {
  94. pushContext(state, "]", stream.column());
  95. } else if (curPunc === "{") {
  96. pushContext(state, "}", stream.column());
  97. } else if (/[\]\}\)]/.test(curPunc)) {
  98. while (state.context && state.context.type === "pattern") {
  99. popContext(state);
  100. }
  101. if (state.context && curPunc === state.context.type) {
  102. popContext(state);
  103. }
  104. } else if (curPunc === "." && state.context && state.context.type === "pattern") {
  105. popContext(state);
  106. } else if (/atom|string|variable/.test(style) && state.context) {
  107. if (/[\}\]]/.test(state.context.type)) {
  108. pushContext(state, "pattern", stream.column());
  109. } else if (state.context.type === "pattern" && !state.context.align) {
  110. state.context.align = true;
  111. state.context.col = stream.column();
  112. }
  113. }
  114. return style;
  115. },
  116. indent: function(state, textAfter) {
  117. var firstChar = textAfter && textAfter.charAt(0);
  118. var context = state.context;
  119. if (/[\]\}]/.test(firstChar)) {
  120. while (context && context.type === "pattern") {
  121. context = context.prev;
  122. }
  123. }
  124. var closing = context && firstChar === context.type;
  125. if (!context) return 0;
  126. if (context.type === "keywords") return CodeMirror.commands.newlineAndIndent;
  127. if (context.align) return context.col + (closing ? 0 : 1);
  128. return context.indent + (closing ? 0 : indentUnit);
  129. }
  130. };
  131. });
  132. CodeMirror.modeExtensions["cypher"] = {
  133. autoFormatLineBreaks: function(text) {
  134. var i, lines, reProcessedPortion;
  135. var lines = text.split("\n");
  136. var reProcessedPortion = /\s+\b(return|where|order by|match|with|skip|limit|create|delete|set)\b\s/g;
  137. for (var i = 0; i < lines.length; i++)
  138. lines[i] = lines[i].replace(reProcessedPortion, " \n$1 ").trim();
  139. return lines.join("\n");
  140. }
  141. };
  142. CodeMirror.defineMIME("application/x-cypher-query", "cypher");
  143. });