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