d.js 7.3 KB

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