swift.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  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. var stringMatch
  71. if (stringMatch = stream.match(/("""|"|')/)) {
  72. var tokenize = tokenString.bind(null, stringMatch[0])
  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(openQuote, stream, state) {
  110. var singleLine = openQuote.length == 1
  111. var ch, escaped = false
  112. while (ch = stream.peek()) {
  113. if (escaped) {
  114. stream.next()
  115. if (ch == "(") {
  116. state.tokenize.push(tokenUntilClosingParen())
  117. return "string"
  118. }
  119. escaped = false
  120. } else if (stream.match(openQuote)) {
  121. state.tokenize.pop()
  122. return "string"
  123. } else {
  124. stream.next()
  125. escaped = ch == "\\"
  126. }
  127. }
  128. if (singleLine) {
  129. state.tokenize.pop()
  130. }
  131. return "string"
  132. }
  133. function tokenComment(stream, state) {
  134. var ch
  135. while (true) {
  136. stream.match(/^[^/*]+/, true)
  137. ch = stream.next()
  138. if (!ch) break
  139. if (ch === "/" && stream.eat("*")) {
  140. state.tokenize.push(tokenComment)
  141. } else if (ch === "*" && stream.eat("/")) {
  142. state.tokenize.pop()
  143. }
  144. }
  145. return "comment"
  146. }
  147. function Context(prev, align, indented) {
  148. this.prev = prev
  149. this.align = align
  150. this.indented = indented
  151. }
  152. function pushContext(state, stream) {
  153. var align = stream.match(/^\s*($|\/[\/\*])/, false) ? null : stream.column() + 1
  154. state.context = new Context(state.context, align, state.indented)
  155. }
  156. function popContext(state) {
  157. if (state.context) {
  158. state.indented = state.context.indented
  159. state.context = state.context.prev
  160. }
  161. }
  162. CodeMirror.defineMode("swift", function(config) {
  163. return {
  164. startState: function() {
  165. return {
  166. prev: null,
  167. context: null,
  168. indented: 0,
  169. tokenize: []
  170. }
  171. },
  172. token: function(stream, state) {
  173. var prev = state.prev
  174. state.prev = null
  175. var tokenize = state.tokenize[state.tokenize.length - 1] || tokenBase
  176. var style = tokenize(stream, state, prev)
  177. if (!style || style == "comment") state.prev = prev
  178. else if (!state.prev) state.prev = style
  179. if (style == "punctuation") {
  180. var bracket = /[\(\[\{]|([\]\)\}])/.exec(stream.current())
  181. if (bracket) (bracket[1] ? popContext : pushContext)(state, stream)
  182. }
  183. return style
  184. },
  185. indent: function(state, textAfter) {
  186. var cx = state.context
  187. if (!cx) return 0
  188. var closing = /^[\]\}\)]/.test(textAfter)
  189. if (cx.align != null) return cx.align - (closing ? 1 : 0)
  190. return cx.indented + (closing ? 0 : config.indentUnit)
  191. },
  192. electricInput: /^\s*[\)\}\]]$/,
  193. lineComment: "//",
  194. blockCommentStart: "/*",
  195. blockCommentEnd: "*/",
  196. fold: "brace",
  197. closeBrackets: "()[]{}''\"\"``"
  198. }
  199. })
  200. CodeMirror.defineMIME("text/x-swift","swift")
  201. });