swift.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2. // Distributed under an MIT license: https://codemirror.net/LICENSE
  3. // Swift mode created by Michael Kaminsky https://github.com/mkaminsky11
  4. (function(mod) {
  5. if (typeof exports == "object" && typeof module == "object")
  6. mod(require("../../lib/codemirror"))
  7. else if (typeof define == "function" && define.amd)
  8. define(["../../lib/codemirror"], mod)
  9. else
  10. mod(CodeMirror)
  11. })(function(CodeMirror) {
  12. "use strict"
  13. function wordSet(words) {
  14. var set = {}
  15. for (var i = 0; i < words.length; i++) set[words[i]] = true
  16. return set
  17. }
  18. var keywords = wordSet(["_","var","let","class","enum","extension","import","protocol","struct","func","typealias","associatedtype",
  19. "open","public","internal","fileprivate","private","deinit","init","new","override","self","subscript","super",
  20. "convenience","dynamic","final","indirect","lazy","required","static","unowned","unowned(safe)","unowned(unsafe)","weak","as","is",
  21. "break","case","continue","default","else","fallthrough","for","guard","if","in","repeat","switch","where","while",
  22. "defer","return","inout","mutating","nonmutating","catch","do","rethrows","throw","throws","try","didSet","get","set","willSet",
  23. "assignment","associativity","infix","left","none","operator","postfix","precedence","precedencegroup","prefix","right",
  24. "Any","AnyObject","Type","dynamicType","Self","Protocol","__COLUMN__","__FILE__","__FUNCTION__","__LINE__"])
  25. var definingKeywords = wordSet(["var","let","class","enum","extension","import","protocol","struct","func","typealias","associatedtype","for"])
  26. var atoms = wordSet(["true","false","nil","self","super","_"])
  27. var types = wordSet(["Array","Bool","Character","Dictionary","Double","Float","Int","Int8","Int16","Int32","Int64","Never","Optional","Set","String",
  28. "UInt8","UInt16","UInt32","UInt64","Void"])
  29. var operators = "+-/*%=|&<>~^?!"
  30. var punc = ":;,.(){}[]"
  31. var binary = /^\-?0b[01][01_]*/
  32. var octal = /^\-?0o[0-7][0-7_]*/
  33. var hexadecimal = /^\-?0x[\dA-Fa-f][\dA-Fa-f_]*(?:(?:\.[\dA-Fa-f][\dA-Fa-f_]*)?[Pp]\-?\d[\d_]*)?/
  34. var decimal = /^\-?\d[\d_]*(?:\.\d[\d_]*)?(?:[Ee]\-?\d[\d_]*)?/
  35. var identifier = /^\$\d+|(`?)[_A-Za-z][_A-Za-z$0-9]*\1/
  36. var property = /^\.(?:\$\d+|(`?)[_A-Za-z][_A-Za-z$0-9]*\1)/
  37. var instruction = /^\#[A-Za-z]+/
  38. var attribute = /^@(?:\$\d+|(`?)[_A-Za-z][_A-Za-z$0-9]*\1)/
  39. //var regexp = /^\/(?!\s)(?:\/\/)?(?:\\.|[^\/])+\//
  40. function tokenBase(stream, state, prev) {
  41. if (stream.sol()) state.indented = stream.indentation()
  42. if (stream.eatSpace()) return null
  43. var ch = stream.peek()
  44. if (ch == "/") {
  45. if (stream.match("//")) {
  46. stream.skipToEnd()
  47. return "comment"
  48. }
  49. if (stream.match("/*")) {
  50. state.tokenize.push(tokenComment)
  51. return tokenComment(stream, state)
  52. }
  53. }
  54. if (stream.match(instruction)) return "builtin"
  55. if (stream.match(attribute)) return "attribute"
  56. if (stream.match(binary)) return "number"
  57. if (stream.match(octal)) return "number"
  58. if (stream.match(hexadecimal)) return "number"
  59. if (stream.match(decimal)) return "number"
  60. if (stream.match(property)) return "property"
  61. if (operators.indexOf(ch) > -1) {
  62. stream.next()
  63. return "operator"
  64. }
  65. if (punc.indexOf(ch) > -1) {
  66. stream.next()
  67. stream.match("..")
  68. return "punctuation"
  69. }
  70. if (ch == '"' || ch == "'") {
  71. stream.next()
  72. var tokenize = tokenString(ch)
  73. state.tokenize.push(tokenize)
  74. return tokenize(stream, state)
  75. }
  76. if (stream.match(identifier)) {
  77. var ident = stream.current()
  78. if (types.hasOwnProperty(ident)) return "variable-2"
  79. if (atoms.hasOwnProperty(ident)) return "atom"
  80. if (keywords.hasOwnProperty(ident)) {
  81. if (definingKeywords.hasOwnProperty(ident))
  82. state.prev = "define"
  83. return "keyword"
  84. }
  85. if (prev == "define") return "def"
  86. return "variable"
  87. }
  88. stream.next()
  89. return null
  90. }
  91. function tokenUntilClosingParen() {
  92. var depth = 0
  93. return function(stream, state, prev) {
  94. var inner = tokenBase(stream, state, prev)
  95. if (inner == "punctuation") {
  96. if (stream.current() == "(") ++depth
  97. else if (stream.current() == ")") {
  98. if (depth == 0) {
  99. stream.backUp(1)
  100. state.tokenize.pop()
  101. return state.tokenize[state.tokenize.length - 1](stream, state)
  102. }
  103. else --depth
  104. }
  105. }
  106. return inner
  107. }
  108. }
  109. function tokenString(quote) {
  110. return function(stream, state) {
  111. var ch, escaped = false
  112. while (ch = stream.next()) {
  113. if (escaped) {
  114. if (ch == "(") {
  115. state.tokenize.push(tokenUntilClosingParen())
  116. return "string"
  117. }
  118. escaped = false
  119. } else if (ch == quote) {
  120. break
  121. } else {
  122. escaped = ch == "\\"
  123. }
  124. }
  125. state.tokenize.pop()
  126. return "string"
  127. }
  128. }
  129. function tokenComment(stream, state) {
  130. var ch
  131. while (true) {
  132. stream.match(/^[^/*]+/, true)
  133. ch = stream.next()
  134. if (!ch) break
  135. if (ch === "/" && stream.eat("*")) {
  136. state.tokenize.push(tokenComment)
  137. } else if (ch === "*" && stream.eat("/")) {
  138. state.tokenize.pop()
  139. }
  140. }
  141. return "comment"
  142. }
  143. function Context(prev, align, indented) {
  144. this.prev = prev
  145. this.align = align
  146. this.indented = indented
  147. }
  148. function pushContext(state, stream) {
  149. var align = stream.match(/^\s*($|\/[\/\*])/, false) ? null : stream.column() + 1
  150. state.context = new Context(state.context, align, state.indented)
  151. }
  152. function popContext(state) {
  153. if (state.context) {
  154. state.indented = state.context.indented
  155. state.context = state.context.prev
  156. }
  157. }
  158. CodeMirror.defineMode("swift", function(config) {
  159. return {
  160. startState: function() {
  161. return {
  162. prev: null,
  163. context: null,
  164. indented: 0,
  165. tokenize: []
  166. }
  167. },
  168. token: function(stream, state) {
  169. var prev = state.prev
  170. state.prev = null
  171. var tokenize = state.tokenize[state.tokenize.length - 1] || tokenBase
  172. var style = tokenize(stream, state, prev)
  173. if (!style || style == "comment") state.prev = prev
  174. else if (!state.prev) state.prev = style
  175. if (style == "punctuation") {
  176. var bracket = /[\(\[\{]|([\]\)\}])/.exec(stream.current())
  177. if (bracket) (bracket[1] ? popContext : pushContext)(state, stream)
  178. }
  179. return style
  180. },
  181. indent: function(state, textAfter) {
  182. var cx = state.context
  183. if (!cx) return 0
  184. var closing = /^[\]\}\)]/.test(textAfter)
  185. if (cx.align != null) return cx.align - (closing ? 1 : 0)
  186. return cx.indented + (closing ? 0 : config.indentUnit)
  187. },
  188. electricInput: /^\s*[\)\}\]]$/,
  189. lineComment: "//",
  190. blockCommentStart: "/*",
  191. blockCommentEnd: "*/",
  192. fold: "brace",
  193. closeBrackets: "()[]{}''\"\"``"
  194. }
  195. })
  196. CodeMirror.defineMIME("text/x-swift","swift")
  197. });