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.

221 lines
7.4 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. // 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","actor","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","isolated","nonisolated","catch","do","rethrows","throw","throws","async","await","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","actor","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 (ch = stream.next()) {
  136. if (ch === "/" && stream.eat("*")) {
  137. state.tokenize.push(tokenComment)
  138. } else if (ch === "*" && stream.eat("/")) {
  139. state.tokenize.pop()
  140. break
  141. }
  142. }
  143. return "comment"
  144. }
  145. function Context(prev, align, indented) {
  146. this.prev = prev
  147. this.align = align
  148. this.indented = indented
  149. }
  150. function pushContext(state, stream) {
  151. var align = stream.match(/^\s*($|\/[\/\*])/, false) ? null : stream.column() + 1
  152. state.context = new Context(state.context, align, state.indented)
  153. }
  154. function popContext(state) {
  155. if (state.context) {
  156. state.indented = state.context.indented
  157. state.context = state.context.prev
  158. }
  159. }
  160. CodeMirror.defineMode("swift", function(config) {
  161. return {
  162. startState: function() {
  163. return {
  164. prev: null,
  165. context: null,
  166. indented: 0,
  167. tokenize: []
  168. }
  169. },
  170. token: function(stream, state) {
  171. var prev = state.prev
  172. state.prev = null
  173. var tokenize = state.tokenize[state.tokenize.length - 1] || tokenBase
  174. var style = tokenize(stream, state, prev)
  175. if (!style || style == "comment") state.prev = prev
  176. else if (!state.prev) state.prev = style
  177. if (style == "punctuation") {
  178. var bracket = /[\(\[\{]|([\]\)\}])/.exec(stream.current())
  179. if (bracket) (bracket[1] ? popContext : pushContext)(state, stream)
  180. }
  181. return style
  182. },
  183. indent: function(state, textAfter) {
  184. var cx = state.context
  185. if (!cx) return 0
  186. var closing = /^[\]\}\)]/.test(textAfter)
  187. if (cx.align != null) return cx.align - (closing ? 1 : 0)
  188. return cx.indented + (closing ? 0 : config.indentUnit)
  189. },
  190. electricInput: /^\s*[\)\}\]]$/,
  191. lineComment: "//",
  192. blockCommentStart: "/*",
  193. blockCommentEnd: "*/",
  194. fold: "brace",
  195. closeBrackets: "()[]{}''\"\"``"
  196. }
  197. })
  198. CodeMirror.defineMIME("text/x-swift","swift")
  199. });