d.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. CodeMirror.defineMode("d", function(config, parserConfig) {
  2. var indentUnit = config.indentUnit,
  3. statementIndentUnit = parserConfig.statementIndentUnit || indentUnit,
  4. keywords = parserConfig.keywords || {},
  5. builtin = parserConfig.builtin || {},
  6. blockKeywords = parserConfig.blockKeywords || {},
  7. atoms = parserConfig.atoms || {},
  8. hooks = parserConfig.hooks || {},
  9. multiLineStrings = parserConfig.multiLineStrings;
  10. var isOperatorChar = /[+\-*&%=<>!?|\/]/;
  11. var curPunc;
  12. function tokenBase(stream, state) {
  13. var ch = stream.next();
  14. if (hooks[ch]) {
  15. var result = hooks[ch](stream, state);
  16. if (result !== false) return result;
  17. }
  18. if (ch == '"' || ch == "'" || ch == "`") {
  19. state.tokenize = tokenString(ch);
  20. return state.tokenize(stream, state);
  21. }
  22. if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
  23. curPunc = ch;
  24. return null;
  25. }
  26. if (/\d/.test(ch)) {
  27. stream.eatWhile(/[\w\.]/);
  28. return "number";
  29. }
  30. if (ch == "/") {
  31. if (stream.eat("+")) {
  32. state.tokenize = tokenComment;
  33. return tokenNestedComment(stream, state);
  34. }
  35. if (stream.eat("*")) {
  36. state.tokenize = tokenComment;
  37. return tokenComment(stream, state);
  38. }
  39. if (stream.eat("/")) {
  40. stream.skipToEnd();
  41. return "comment";
  42. }
  43. }
  44. if (isOperatorChar.test(ch)) {
  45. stream.eatWhile(isOperatorChar);
  46. return "operator";
  47. }
  48. stream.eatWhile(/[\w\$_]/);
  49. var cur = stream.current();
  50. if (keywords.propertyIsEnumerable(cur)) {
  51. if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
  52. return "keyword";
  53. }
  54. if (builtin.propertyIsEnumerable(cur)) {
  55. if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
  56. return "builtin";
  57. }
  58. if (atoms.propertyIsEnumerable(cur)) return "atom";
  59. return "variable";
  60. }
  61. function tokenString(quote) {
  62. return function(stream, state) {
  63. var escaped = false, next, end = false;
  64. while ((next = stream.next()) != null) {
  65. if (next == quote && !escaped) {end = true; break;}
  66. escaped = !escaped && next == "\\";
  67. }
  68. if (end || !(escaped || multiLineStrings))
  69. state.tokenize = null;
  70. return "string";
  71. };
  72. }
  73. function tokenComment(stream, state) {
  74. var maybeEnd = false, ch;
  75. while (ch = stream.next()) {
  76. if (ch == "/" && maybeEnd) {
  77. state.tokenize = null;
  78. break;
  79. }
  80. maybeEnd = (ch == "*");
  81. }
  82. return "comment";
  83. }
  84. function tokenNestedComment(stream, state) {
  85. var maybeEnd = false, ch;
  86. while (ch = stream.next()) {
  87. if (ch == "/" && maybeEnd) {
  88. state.tokenize = null;
  89. break;
  90. }
  91. maybeEnd = (ch == "+");
  92. }
  93. return "comment";
  94. }
  95. function Context(indented, column, type, align, prev) {
  96. this.indented = indented;
  97. this.column = column;
  98. this.type = type;
  99. this.align = align;
  100. this.prev = prev;
  101. }
  102. function pushContext(state, col, type) {
  103. var indent = state.indented;
  104. if (state.context && state.context.type == "statement")
  105. indent = state.context.indented;
  106. return state.context = new Context(indent, col, type, null, state.context);
  107. }
  108. function popContext(state) {
  109. var t = state.context.type;
  110. if (t == ")" || t == "]" || t == "}")
  111. state.indented = state.context.indented;
  112. return state.context = state.context.prev;
  113. }
  114. // Interface
  115. return {
  116. startState: function(basecolumn) {
  117. return {
  118. tokenize: null,
  119. context: new Context((basecolumn || 0) - indentUnit, 0, "top", false),
  120. indented: 0,
  121. startOfLine: true
  122. };
  123. },
  124. token: function(stream, state) {
  125. var ctx = state.context;
  126. if (stream.sol()) {
  127. if (ctx.align == null) ctx.align = false;
  128. state.indented = stream.indentation();
  129. state.startOfLine = true;
  130. }
  131. if (stream.eatSpace()) return null;
  132. curPunc = null;
  133. var style = (state.tokenize || tokenBase)(stream, state);
  134. if (style == "comment" || style == "meta") return style;
  135. if (ctx.align == null) ctx.align = true;
  136. if ((curPunc == ";" || curPunc == ":" || curPunc == ",") && ctx.type == "statement") popContext(state);
  137. else if (curPunc == "{") pushContext(state, stream.column(), "}");
  138. else if (curPunc == "[") pushContext(state, stream.column(), "]");
  139. else if (curPunc == "(") pushContext(state, stream.column(), ")");
  140. else if (curPunc == "}") {
  141. while (ctx.type == "statement") ctx = popContext(state);
  142. if (ctx.type == "}") ctx = popContext(state);
  143. while (ctx.type == "statement") ctx = popContext(state);
  144. }
  145. else if (curPunc == ctx.type) popContext(state);
  146. else if (((ctx.type == "}" || ctx.type == "top") && curPunc != ';') || (ctx.type == "statement" && curPunc == "newstatement"))
  147. pushContext(state, stream.column(), "statement");
  148. state.startOfLine = false;
  149. return style;
  150. },
  151. indent: function(state, textAfter) {
  152. if (state.tokenize != tokenBase && state.tokenize != null) return CodeMirror.Pass;
  153. var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
  154. if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev;
  155. var closing = firstChar == ctx.type;
  156. if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit);
  157. else if (ctx.align) return ctx.column + (closing ? 0 : 1);
  158. else return ctx.indented + (closing ? 0 : indentUnit);
  159. },
  160. electricChars: "{}"
  161. };
  162. });
  163. (function() {
  164. function words(str) {
  165. var obj = {}, words = str.split(" ");
  166. for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
  167. return obj;
  168. }
  169. var blockKeywords = "body catch class do else enum for foreach foreach_reverse if in interface mixin " +
  170. "out scope struct switch try union unittest version while with";
  171. CodeMirror.defineMIME("text/x-d", {
  172. name: "d",
  173. keywords: words("abstract alias align asm assert auto break case cast cdouble cent cfloat const continue " +
  174. "debug default delegate delete deprecated export extern final finally function goto immutable " +
  175. "import inout invariant is lazy macro module new nothrow override package pragma private " +
  176. "protected public pure ref return shared short static super synchronized template this " +
  177. "throw typedef typeid typeof volatile __FILE__ __LINE__ __gshared __traits __vector __parameters " +
  178. blockKeywords),
  179. blockKeywords: words(blockKeywords),
  180. builtin: words("bool byte char creal dchar double float idouble ifloat int ireal long real short ubyte " +
  181. "ucent uint ulong ushort wchar wstring void size_t sizediff_t"),
  182. atoms: words("exit failure success true false null"),
  183. hooks: {
  184. "@": function(stream, _state) {
  185. stream.eatWhile(/[\w\$_]/);
  186. return "meta";
  187. }
  188. }
  189. });
  190. }());