sieve.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  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('sieve', function (config) {
  15. function words(str) {
  16. var obj = {},
  17. words = str.split(' ')
  18. for (var i = 0; i < words.length; ++i) obj[words[i]] = true
  19. return obj
  20. }
  21. var keywords = words('if elsif else stop require')
  22. var atoms = words('true false not')
  23. var indentUnit = config.indentUnit
  24. function tokenBase(stream, state) {
  25. var ch = stream.next()
  26. if (ch == '/' && stream.eat('*')) {
  27. state.tokenize = tokenCComment
  28. return tokenCComment(stream, state)
  29. }
  30. if (ch === '#') {
  31. stream.skipToEnd()
  32. return 'comment'
  33. }
  34. if (ch == '"') {
  35. state.tokenize = tokenString(ch)
  36. return state.tokenize(stream, state)
  37. }
  38. if (ch == '(') {
  39. state._indent.push('(')
  40. // add virtual angel wings so that editor behaves...
  41. // ...more sane in case of broken brackets
  42. state._indent.push('{')
  43. return null
  44. }
  45. if (ch === '{') {
  46. state._indent.push('{')
  47. return null
  48. }
  49. if (ch == ')') {
  50. state._indent.pop()
  51. state._indent.pop()
  52. }
  53. if (ch === '}') {
  54. state._indent.pop()
  55. return null
  56. }
  57. if (ch == ',') return null
  58. if (ch == ';') return null
  59. if (/[{}\(\),;]/.test(ch)) return null
  60. // 1*DIGIT "K" / "M" / "G"
  61. if (/\d/.test(ch)) {
  62. stream.eatWhile(/[\d]/)
  63. stream.eat(/[KkMmGg]/)
  64. return 'number'
  65. }
  66. // ":" (ALPHA / "_") *(ALPHA / DIGIT / "_")
  67. if (ch == ':') {
  68. stream.eatWhile(/[a-zA-Z_]/)
  69. stream.eatWhile(/[a-zA-Z0-9_]/)
  70. return 'operator'
  71. }
  72. stream.eatWhile(/\w/)
  73. var cur = stream.current()
  74. // "text:" *(SP / HTAB) (hash-comment / CRLF)
  75. // *(multiline-literal / multiline-dotstart)
  76. // "." CRLF
  77. if (cur == 'text' && stream.eat(':')) {
  78. state.tokenize = tokenMultiLineString
  79. return 'string'
  80. }
  81. if (keywords.propertyIsEnumerable(cur)) return 'keyword'
  82. if (atoms.propertyIsEnumerable(cur)) return 'atom'
  83. return null
  84. }
  85. function tokenMultiLineString(stream, state) {
  86. state._multiLineString = true
  87. // the first line is special it may contain a comment
  88. if (!stream.sol()) {
  89. stream.eatSpace()
  90. if (stream.peek() == '#') {
  91. stream.skipToEnd()
  92. return 'comment'
  93. }
  94. stream.skipToEnd()
  95. return 'string'
  96. }
  97. if (stream.next() == '.' && stream.eol()) {
  98. state._multiLineString = false
  99. state.tokenize = tokenBase
  100. }
  101. return 'string'
  102. }
  103. function tokenCComment(stream, state) {
  104. var maybeEnd = false,
  105. ch
  106. while ((ch = stream.next()) != null) {
  107. if (maybeEnd && ch == '/') {
  108. state.tokenize = tokenBase
  109. break
  110. }
  111. maybeEnd = ch == '*'
  112. }
  113. return 'comment'
  114. }
  115. function tokenString(quote) {
  116. return function (stream, state) {
  117. var escaped = false,
  118. ch
  119. while ((ch = stream.next()) != null) {
  120. if (ch == quote && !escaped) break
  121. escaped = !escaped && ch == '\\'
  122. }
  123. if (!escaped) state.tokenize = tokenBase
  124. return 'string'
  125. }
  126. }
  127. return {
  128. startState: function (base) {
  129. return { tokenize: tokenBase, baseIndent: base || 0, _indent: [] }
  130. },
  131. token: function (stream, state) {
  132. if (stream.eatSpace()) return null
  133. return (state.tokenize || tokenBase)(stream, state)
  134. },
  135. indent: function (state, _textAfter) {
  136. var length = state._indent.length
  137. if (_textAfter && _textAfter[0] == '}') length--
  138. if (length < 0) length = 0
  139. return length * indentUnit
  140. },
  141. electricChars: '}',
  142. }
  143. })
  144. CodeMirror.defineMIME('application/sieve', 'sieve')
  145. })