You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

223 lines
7.5 KiB

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