d.js 9.3 KB

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