├── Comments.tmPreferences ├── LICENSE ├── README.md ├── Swift.sublime-syntax ├── package.json └── syntax_test.swift /Comments.tmPreferences: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Comments 7 | scope 8 | source.swift 9 | settings 10 | 11 | shellVariables 12 | 13 | 14 | name 15 | TM_COMMENT_START 16 | value 17 | // 18 | 19 | 20 | name 21 | TM_COMMENT_START_2 22 | value 23 | /* 24 | 25 | 26 | name 27 | TM_COMMENT_END_2 28 | value 29 | */ 30 | 31 | 32 | 33 | uuid 34 | 66529EE0-35DE-11E4-8C21-0800200C9A66 35 | 36 | 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2019, Colin Gray 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Decent Swift Syntax 2 | =================== 3 | 4 | Uses the new 'sublime-syntax' format, which is super easy to work with. 5 | 6 | Still a work in progress. I think there's room for improvement in which symbols 7 | to include, like class and instance `var`/`let`. 8 | -------------------------------------------------------------------------------- /Swift.sublime-syntax: -------------------------------------------------------------------------------- 1 | %YAML 1.2 2 | --- 3 | name: Swift 4 | file_extensions: [swift, swiftinterface] 5 | scope: source.swift 6 | prototype: 7 | - include: main 8 | 9 | contexts: 10 | main: 11 | ###################################################### COMMENTS 12 | - match: (//+\s+MARK:) ?(.*) 13 | scope: comment.line 14 | captures: 15 | 1: punctuation.definition.comment 16 | 2: meta.toc-list 17 | - match: (//+\s+TODO:) ?(.*) 18 | scope: comment.line 19 | captures: 20 | 1: punctuation.definition.comment 21 | 2: meta.toc-list 22 | - match: (//+\s+FIXME:) ?(.*) 23 | scope: comment.line 24 | captures: 25 | 1: punctuation.definition.comment 26 | 2: meta.toc-list 27 | - match: (//+).*(\n|$) 28 | scope: comment.line 29 | captures: 30 | 1: punctuation.definition.comment 31 | - match: (/\*) 32 | scope: punctuation.definition.comment 33 | push: comment_block 34 | ###################################################### PRECOMPILED 35 | - match: ^\s*(#)(\w+)(.*)$ 36 | captures: 37 | 1: punctuation.definition.preprocessor meta.preprocessor.swift 38 | 2: punctuation.definition.preprocessor meta.preprocessor.swift 39 | ###################################################### ENUMS 40 | - match: "(?:[^\\?\\!\\)\\\"\\w]|^)(\\.[a-zA-Z]\\w*)\\(" 41 | captures: 42 | 1: constant.language.enum 43 | push: enum 44 | - match: "(?<=[^\\?\\!\\)\\\"\\w]|^)(\\.[a-zA-Z]\\w*)" 45 | captures: 46 | 1: constant.language.enum 47 | ###################################################### CONSTANTS 48 | - match: \btrue\b 49 | scope: constant.language.true 50 | - match: \bfalse\b 51 | scope: constant.language.false 52 | - match: \bnil\b 53 | scope: constant.language.nil 54 | ###################################################### NUMERICS 55 | - match: \b0[XOB] 56 | scope: invalid illegal.invalid 57 | - match: '0x([[:xdigit:]][[:xdigit:]_]*)((\.\g<1>)?[pP][-+]?\d[\d_]*)?' 58 | scope: constant.numeric.hex 59 | - match: 0o[0-7][0-7_]* 60 | scope: constant.numeric.octal 61 | - match: 0b[01][01_]* 62 | scope: constant.numeric.binary 63 | - match: '(\d[\d_]*)(\.\g<1>)([eE][-+]?\g<1>)?' 64 | scope: constant.numeric.float 65 | - match: '(\d[\d_]*)([eE][-+]?\g<1>)' 66 | scope: constant.numeric.float 67 | - match: '(\d[\d_]*)' 68 | scope: constant.numeric.decimal 69 | ###################################################### TYPES 70 | # class func 71 | - match: \b(class)\s+(?=func) 72 | scope: meta.function storage.type.function 73 | - match: \b(enum|class|struct|protocol|extension)\s+((\w+)\s*(:)\s+(\w+)) 74 | scope: entity.name.type 75 | captures: 76 | 1: keyword.entity 77 | 2: entity.name.type 78 | 3: support.class 79 | 4: keyword.operator 80 | 5: support.class 81 | - match: \b(enum|class|struct|protocol|extension)\s+(\w+) 82 | scope: entity.name.type 83 | captures: 84 | 1: keyword.entity 85 | 2: entity.name.type support.class 86 | ###################################################### KEYWORDS 87 | - match: \b(self|super)\b 88 | scope: keyword.variable 89 | - match: \b_\b 90 | scope: constant.language.other 91 | - match: \b(import)\b 92 | scope: keyword.other.import 93 | ###################################################### CONTROL 94 | - match: \b(if|where|else|for|in|is|as|while|switch|do|defer|repeat)\b 95 | scope: keyword.control 96 | - match: \b(break|fallthrough|guard|try|catch|throws?|rethrows|return|case|continue|default|didSet|willSet|get|set)\b 97 | scope: keyword.control 98 | - match: \b(async|await)\b 99 | scope: keyword.control 100 | - match: \b(some|any)\b 101 | scope: keyword.control 102 | - match: '#(available)\b' 103 | scope: keyword.control 104 | ###################################################### VARIABLES 105 | - match: \b(var|let|typealias|unowned)\b 106 | captures: 107 | 1: keyword.variable 108 | ###################################################### STRING 109 | - match: '"""' 110 | push: string_multiline 111 | - match: '#"' 112 | push: string_raw_1 113 | - match: '##"' 114 | push: string_raw_2 115 | - match: '###"' 116 | push: string_raw_3 117 | - match: '"' 118 | push: string_double 119 | ###################################################### MODIFIERS 120 | - match: \b(weak|lazy|mutating|convenience|associatedtype|public|internal|private|fileprivate|final|static|override|required|prefix|postfix|infix|indirect|inout|open)\b 121 | scope: storage.modifier 122 | - match: '@\w+' 123 | scope: storage.type.decorator 124 | ###################################################### SUPPORT 125 | # "system" classes: 126 | - match: \b([A-Z]{2})\w+ 127 | scope: support.class 128 | - match: \b(String|Array|Int\d*|Float|Double)\w+ 129 | scope: support.class 130 | # user classes: 131 | - match: \b([A-Z])\w* 132 | scope: support.class 133 | ###################################################### FUNCTIONS 134 | - match: '\b(func|operator)\s+(\w+)\s*\(' 135 | captures: 136 | 1: storage.type.function 137 | 2: entity.name.function variable.function 138 | push: function_params 139 | - match: '\b(deinit|init(\??))\s*\(' 140 | captures: 141 | 1: storage.type.function 142 | 2: entity.name.function variable.function 143 | push: function_params 144 | - match: \b(func)\s+(\w+) 145 | captures: 146 | 1: storage.type.function 147 | 2: entity.name.function variable.function 148 | - match: \b(func|deinit|init(\??))\b 149 | scope: entity.name.type storage.type.function 150 | ###################################################### VARIABLES 151 | - match: '(\w+):' 152 | captures: 153 | 1: variable.parameter 154 | - match: '\b\w+' 155 | scope: '' 156 | - match: '[-+=<>^$#@!~*\\|&?\/%.]*' 157 | scope: keyword.operator 158 | - match: '\(' 159 | push: paren_expr 160 | ###################################################### 161 | comment_block: 162 | - meta_scope: comment.block 163 | - match: /\* 164 | push: comment_block 165 | - match: \*/ 166 | pop: true 167 | function_params: 168 | - include: main 169 | - meta_scope: meta.function meta.toc-list 170 | - match: '\)' 171 | pop: true 172 | string_multiline: 173 | - meta_scope: string.quoted.double string.quoted.multiline 174 | - match: \\\( 175 | scope: punctuation.section.embedded 176 | set: embedded_multiline 177 | - match: \\[ntr0\\"'] 178 | scope: constant.character.escape.c 179 | - match: \\u{[[:xdigit:]]{1,8}} 180 | scope: constant.character.escape.c 181 | - match: \\\n 182 | scope: constant.character.escape.c 183 | - match: \\ 184 | scope: invalid.illegal 185 | - match: '"""' 186 | pop: true 187 | string_raw_1: 188 | - meta_scope: string.quoted.double string.quoted.raw 189 | - match: \\\( 190 | scope: punctuation.section.embedded 191 | set: embedded_raw_1 192 | - match: \\[ntr0\\"'] 193 | scope: constant.character.escape.c 194 | - match: \\u{[[:xdigit:]]{1,8}} 195 | scope: constant.character.escape.c 196 | - match: \\\n 197 | scope: constant.character.escape.c 198 | - match: \\ 199 | scope: invalid.illegal 200 | - match: '"#' 201 | pop: true 202 | string_raw_2: 203 | - meta_scope: string.quoted.double string.quoted.raw 204 | - match: \\\( 205 | scope: punctuation.section.embedded 206 | set: embedded_raw_2 207 | - match: \\[ntr0\\"'] 208 | scope: constant.character.escape.c 209 | - match: \\u{[[:xdigit:]]{1,8}} 210 | scope: constant.character.escape.c 211 | - match: \\\n 212 | scope: constant.character.escape.c 213 | - match: \\ 214 | scope: invalid.illegal 215 | - match: '"##' 216 | pop: true 217 | string_raw_3: 218 | - meta_scope: string.quoted.double string.quoted.raw 219 | - match: \\\( 220 | scope: punctuation.section.embedded 221 | set: embedded_raw_3 222 | - match: \\[ntr0\\"'] 223 | scope: constant.character.escape.c 224 | - match: \\u{[[:xdigit:]]{1,8}} 225 | scope: constant.character.escape.c 226 | - match: \\\n 227 | scope: constant.character.escape.c 228 | - match: \\ 229 | scope: invalid.illegal 230 | - match: '"###' 231 | pop: true 232 | string_double: 233 | - meta_scope: string.quoted.double 234 | - match: \\\( 235 | scope: punctuation.section.embedded 236 | set: embedded_double 237 | - match: \\[ntr0\\"'] 238 | scope: constant.character.escape.c 239 | - match: \\u{[[:xdigit:]]{1,8}} 240 | # Unicode scalar escape 241 | # feels like this needs a different scope 242 | scope: constant.character.escape.c 243 | - match: \\ 244 | scope: invalid.illegal 245 | - match: '"' 246 | pop: true 247 | embedded_double: 248 | - include: main 249 | - match: \( 250 | push: nested 251 | - match: \) 252 | scope: punctuation.section.embedded 253 | set: string_double 254 | embedded_multiline: 255 | - include: main 256 | - match: \( 257 | push: nested 258 | - match: \) 259 | scope: punctuation.section.embedded 260 | set: string_multiline 261 | embedded_raw_1: 262 | - include: main 263 | - match: \( 264 | push: nested 265 | - match: \) 266 | scope: punctuation.section.embedded 267 | set: string_raw_1 268 | embedded_raw_2: 269 | - include: main 270 | - match: \( 271 | push: nested 272 | - match: \) 273 | scope: punctuation.section.embedded 274 | set: string_raw_2 275 | embedded_raw_3: 276 | - include: main 277 | - match: \( 278 | push: nested 279 | - match: \) 280 | scope: punctuation.section.embedded 281 | set: string_raw_3 282 | nested: 283 | - include: main 284 | - match: \( 285 | push: nested 286 | - match: \) 287 | pop: true 288 | paren_expr: 289 | - include: main 290 | - match: '\)' 291 | pop: true 292 | enum: 293 | - meta_scope: internal.enum 294 | - include: main 295 | - match: '\)' 296 | pop: true 297 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Decent Swift Syntax", 3 | "details": "https://github.com/colinta/decent-swift-syntax", 4 | "description": "Swift language grammar that doesn't suck.", 5 | "author": "Colin T.A. Gray (colinta)", 6 | "labels": [ 7 | "language syntax" 8 | ], 9 | "previous_names": [ 10 | "Swift for F*ing Sublime" 11 | ], 12 | "releases": [ 13 | { 14 | "tags": true, 15 | "sublime_text": ">=3084" 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /syntax_test.swift: -------------------------------------------------------------------------------- 1 | // SYNTAX TEST "Packages/Decent-Swift-Syntax/Swift.sublime-syntax" 2 | 3 | // comment 4 | // ^ comment.line 5 | // <- punctuation.definition.comment 6 | 7 | // MARK: testing! 8 | // ^ comment.line 9 | // ^ punctuation.definition.comment 10 | // ^ meta.toc-list 11 | 12 | /* comment */ 13 | // ^comment.block 14 | /* 000 */ 15 | // ^comment.block 16 | // ^ comment - constant 17 | 000 /* "string" */ 18 | // <- -comment 19 | // ^comment.block 20 | // ^-string 21 | 22 | true 23 | // <- constant.language 24 | // <- constant.language.true 25 | false 26 | // <- constant.language 27 | // <- constant.language.false 28 | nil 29 | // <- constant.language 30 | // <- constant.language.nil 31 | 32 | 1.1 100.001 33 | // <- constant.numeric 34 | // <- constant.numeric.float 35 | // ^ constant.numeric 36 | // ^^^^^^^ constant.numeric.float 37 | // ^ source.swift 38 | 100 39 | // <- constant.numeric 40 | // <- constant.numeric.decimal 41 | 1_000_000 42 | // ^ constant.numeric.decimal 43 | 0xDEADBEEF 44 | // <- constant.numeric.hex 45 | // ^ constant.numeric.hex 46 | 0xGGGGG 47 | // ^ -constant.numeric.hex 48 | 0o12345670 49 | // <- constant.numeric.octal 50 | // ^ constant.numeric.octal 51 | 0o8888 52 | // ^ -constant.numeric.octal 53 | 0b01010110101 54 | // <- constant.numeric.binary 55 | // ^ constant.numeric.binary 56 | 0b22222 57 | // ^ -constant.numeric.binary 58 | word123 59 | // ^ -constant.numeric 60 | 61 | if { /**/ } 62 | // <- keyword.control 63 | where { /**/ } 64 | // <- keyword.control 65 | 66 | #if FOO 67 | // <- punctuation.definition.preprocessor 68 | #endif 69 | // ^ source.swift punctuation.definition.preprocessor meta.preprocessor.swift 70 | 71 | if a || b 72 | // <- keyword 73 | // ^ keyword.operator 74 | 75 | public func foo 76 | // <- storage.modifier 77 | // ^ storage.type 78 | // ^ storage.type.function 79 | // ^ variable 80 | // ^ entity.name.function 81 | 82 | self 83 | // <- keyword.variable 84 | super 85 | // <- keyword.variable 86 | 87 | Color 88 | // <- support.class 89 | UIColor 90 | // <- support.class 91 | 92 | enum Foo1 { case value } 93 | // <- keyword.entity 94 | // ^ support.class 95 | // ^ entity.name.type 96 | enum Foo2 : String { case value } 97 | // <- keyword.entity 98 | // ^ support.class 99 | // ^ entity.name.type 100 | // ^ support.class 101 | 102 | enum Foo3 : String { 103 | case value 104 | // ^ keyword.control 105 | } 106 | 107 | if foo {} 108 | // <- keyword.control 109 | else {} 110 | // <- keyword.control 111 | for {} 112 | // <- keyword.control 113 | while true {} 114 | // <- keyword.control 115 | // ^ constant 116 | switch foo { case .bar: } 117 | // <- keyword.control 118 | // ^ keyword.control 119 | break 120 | // <- keyword.control 121 | return 122 | // <- keyword.control 123 | case 0..0 124 | // <- keyword.control 125 | // ^ constant.numeric 126 | // ^ keyword.operator 127 | // ^ constant.numeric 128 | continue 129 | // <- keyword.control 130 | default 131 | // <- keyword.control 132 | 133 | enum Foo4 134 | // <- keyword.entity 135 | // ^ support.class 136 | enum Foo5 : Bar {} 137 | // <- keyword.entity 138 | // ^ support.class 139 | // ^ support.class 140 | enum Foo6 { indirect case foo(Foo6) } 141 | // <- keyword.entity 142 | // ^ support.class 143 | // ^ storage.modifier 144 | // ^ keyword.control 145 | // ^ support.class 146 | struct Foo7 147 | // <- keyword.entity 148 | // ^ support.class 149 | struct Foo8 : Bar 150 | // ^ -invalid 151 | // ^ -invalid 152 | // ^ support.class 153 | class Foo9 154 | // <- keyword.entity 155 | // ^ support.class 156 | class Foo10 : Bar {} 157 | // <- keyword.entity 158 | // ^ support.class 159 | // ^ support.class 160 | protocol Foo11 161 | // <- keyword.entity 162 | // ^ support.class 163 | protocol Foo12 : Bar {} 164 | // <- keyword.entity 165 | // ^ support.class 166 | // ^ support.class 167 | extension Foo13 168 | // <- keyword.entity 169 | // ^ support.class 170 | extension Foo14 : Bar 171 | // <- keyword.entity 172 | // ^ support.class 173 | // ^ keyword.operator 174 | // ^ support.class 175 | 176 | func foo() 177 | // ^ variable.function 178 | class func foo() 179 | // <- meta.function 180 | // <- storage.type.function 181 | // ^ storage.type.function 182 | 183 | func foo() { foo } 184 | // ^ variable.function 185 | // ^ meta.function 186 | 187 | func foo(abc, def: String) { foo } 188 | // ^ variable.function 189 | // ^ meta.function 190 | // ^ variable.parameter 191 | 192 | func foo(abc: inout String) { foo } 193 | // ^ variable.function 194 | // ^ variable.parameter 195 | // ^ storage.modifier 196 | 197 | "foo" 198 | // <- string 199 | // <- string.quoted 200 | 201 | "foo\"" foo 202 | // <- string 203 | // ^ constant.character.escape 204 | // ^ constant.character.escape 205 | // ^ string 206 | // ^ -string 207 | 208 | ".foo" 209 | // <- string 210 | //^ string 211 | // ^ string 212 | 213 | "foo \(bar + (foo * bar))" 214 | // <- string 215 | // ^ punctuation.section 216 | // ^ punctuation.section 217 | // ^ -string 218 | // ^ -punctuation.section 219 | 220 | """f"oo""" 221 | // <- string.quoted.multiline 222 | // ^ string.quoted 223 | 224 | """ 225 | f"oo\("bar") 226 | // <- string 227 | // <- string.quoted.multiline 228 | // ^ punctuation.section.embedded 229 | // ^ string.quoted.double 230 | // ^ punctuation.section.embedded 231 | """ 232 | .bar 233 | // <- constant.language.enum 234 | 235 | #"te"st"# 236 | // <- string 237 | // <- string.quoted.raw 238 | // ^ string.quoted 239 | 240 | ##"te"#st"## 241 | // <- string 242 | // <- string.quoted.raw 243 | // ^ string.quoted 244 | 245 | a = (.foo(.bar)) 246 | // ^ constant.language.enum 247 | // ^ constant.language.enum 248 | 249 | .foo + .bar 250 | // <- constant.language.enum 251 | // ^ -constant.language.enum 252 | // ^ constant.language.enum 253 | 254 | a.foo + a?.bar() 255 | // <- -constant.language.enum 256 | //^ -constant.language.enum 257 | // ^ -constant.language.enum 258 | --------------------------------------------------------------------------------