From 19cd1ea29e3f3fecda6561994f1c56cf0b7a0a5a Mon Sep 17 00:00:00 2001 From: Gab Date: Thu, 28 Sep 2023 11:15:13 -0700 Subject: [PATCH] Adding extension for swift-mode --- extensions/swift-mode/lem-swift-mode.asd | 4 + extensions/swift-mode/lsp-config.lisp | 12 + extensions/swift-mode/swift-mode.lisp | 41 +++ extensions/swift-mode/swift.json | 328 +++++++++++++++++++++++ lem.asd | 1 + 5 files changed, 386 insertions(+) create mode 100644 extensions/swift-mode/lem-swift-mode.asd create mode 100644 extensions/swift-mode/lsp-config.lisp create mode 100644 extensions/swift-mode/swift-mode.lisp create mode 100644 extensions/swift-mode/swift.json diff --git a/extensions/swift-mode/lem-swift-mode.asd b/extensions/swift-mode/lem-swift-mode.asd new file mode 100644 index 000000000..7d4a69183 --- /dev/null +++ b/extensions/swift-mode/lem-swift-mode.asd @@ -0,0 +1,4 @@ +(defsystem "lem-swift-mode" + :depends-on ("lem" "yason") + :serial t + :components ((:file "swift-mode") (:file "lsp-config"))) \ No newline at end of file diff --git a/extensions/swift-mode/lsp-config.lisp b/extensions/swift-mode/lsp-config.lisp new file mode 100644 index 000000000..f3b9b0291 --- /dev/null +++ b/extensions/swift-mode/lsp-config.lisp @@ -0,0 +1,12 @@ +(defpackage :lem-swift-mode/lsp-config + (:use :cl :lem-lsp-mode :lem-lsp-base/type)) + +(in-package :lem-swift-mode/lsp-config) + +(define-language-spec (swift-spec lem-swift-mode:swift-mode) + :language-id "swift" + :root-uri-patterns '("Package.swift") + :command '("xcrun" "--toolchain" "swift" "sourcekit-lsp") ;; either behind $PATH or 'xcrun --toolchain swift sourcekit-lsp' + :install-command "" ;; It kinda..has to be installed? + :readme-url "https://github.com/apple/sourcekit-lsp" + :connection-mode :stdio) \ No newline at end of file diff --git a/extensions/swift-mode/swift-mode.lisp b/extensions/swift-mode/swift-mode.lisp new file mode 100644 index 000000000..d9ad5951d --- /dev/null +++ b/extensions/swift-mode/swift-mode.lisp @@ -0,0 +1,41 @@ +(defpackage :lem-swift-mode + (:use :cl :lem :lem/completion-mode :lem/language-mode) + (:import-from :lem/tmlanguage :load-tmlanguage) + (:export :*swift-mode-hook* :swift-mode)) + +(in-package :lem-swift-mode) + +;; Syntax highlighting (like the go implementation) is effectively +;; a json file from Atom's system. Eventually, I will have to +;; update the json for Swift 5.9's macros and new syntax +(defvar *swift-syntax-table* + (let ((table (make-syntax-table + :space-chars '(#\space #\tab #\newline) + :symbol-chars '(#\_) + :paren-pairs '((#\( . #\)) + (#\{ . #\}) + (#\[ . #\])) + :string-quote-chars '(#\" #\#) + :line-comment-string "//" + :block-comment-pairs '(("/*" . "*/")))) + (tmlanguage (load-tmlanguage + (merge-pathnames "swift.json" + (asdf:system-source-directory :lem-swift-mode))))) + (set-syntax-parser table tmlanguage) + table)) + +(define-major-mode swift-mode language-mode + (:name "Swift" + :syntax-table *swift-syntax-table* + :mode-hook *swift-mode-hook*) + (setf (variable-value 'enable-syntax-highlight) t) + (setf (variable-value 'tab-width) 2) ;; Can be 4, Swift OSS is 2 + (setf (variable-value 'line-comment) "//") + (setf (variable-value 'insertion-line-comment) "// ")) + +(define-file-type ("swift") swift-mode) + + + + + diff --git a/extensions/swift-mode/swift.json b/extensions/swift-mode/swift.json new file mode 100644 index 000000000..1c2cce61a --- /dev/null +++ b/extensions/swift-mode/swift.json @@ -0,0 +1,328 @@ +{ + "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", + "name": "Swift", + "scopeName": "source.swift", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#constant" + }, + { + "include": "#entity" + }, + { + "include": "#invalid" + }, + { + "include": "#keyword" + }, + { + "include": "#meta" + }, + { + "include": "#operator" + }, + { + "include": "#punctuation" + }, + { + "include": "#storage" + }, + { + "include": "#string" + }, + { + "include": "#support" + }, + { + "include": "#type" + }, + { + "include": "#variable" + } + ], + "repository": { + "comment": { + "patterns": [ + { + "name": "comment.block.swift", + "begin": "/\\*", + "end": "\\*/", + "captures": { + "0": { + "name": "punctuation.definition.comment.swift" + } + } + }, + { + "name": "comment.line.double-slash.swift", + "begin": "//", + "end": "$", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.swift" + } + } + } + ] + }, + "constant": { + "patterns": [ + { + "name": "constant.language.swift", + "match": "\\b(true|false|nil|none)\\b" + }, + { + "name": "constant.numeric.swift", + "match": "(?x)(0b[0-1]+)|(0x[0-9a-fA-F]+)|(0o[0-7]+)|([+-]?([0-9]*[.])?[0-9]+)" + }, + { + "name": "constant.character.escape.swift", + "match": "\\\\[0\\\\tnr\"']" + }, + { + "name": "constant.character.escape.swift", + "match": "\\\\(x\\h{2}|u\\h{4}|U\\h{8})" + } + ] + }, + "entity": { + "patterns": [ + { + "match": "([a-zA-Z!][a-zA-Z_]+)(?=[(])", + "name": "entity.name.function.swift" + }, + { + "match": "(?<=protocol\\s)([a-zA-Z][a-zA-Z_]+)", + "captures": { + "1": { + "name": "entity.name.function.protocol.swift" + } + } + }, + { + "match": "(?<=extension\\s)([a-zA-Z][a-zA-Z_]+)", + "captures": { + "1": { + "name": "entity.name.function.extension.swift" + } + } + }, + { + "match": "(?<=enum\\s)([a-zA-Z][a-zA-Z_]+)", + "captures": { + "1": { + "name": "entity.name.type.enum.swift" + } + } + }, + { + "match": "(?<=class\\s)([a-zA-Z][a-zA-Z_]+)", + "captures": { + "1": { + "name": "entity.name.class.swift" + } + } + }, + { + "match": "(?<=import\\s)([a-zA-Z][a-zA-Z_]+)", + "captures": { + "1": { + "name": "entity.name.type.module.swift" + } + } + }, + { + "match": "(?<=struct\\s)([a-zA-Z][a-zA-Z_]+)", + "captures": { + "1": { + "name": "entity.name.type.struct.swift" + } + } + }, + { + "match": "\\b(func)\\s+([^\\t\\n\\x20\\x28]+)", + "captures": { + "1": { + "name": "storage.type.function.swift" + }, + "2": { + "name": "entity.name.function.swift" + } + } + } + ] + }, + "invalid": { + "patterns": [] + }, + "keyword": { + "patterns": [ + { + "name": "keyword.statement.swift", + "match": "\\b(break|case|continue|catch|do|default|defer|else|fallthrough|for|guard|if|in|repeat|return|switch|try|where|while)\\b" + }, + { + "name": "keyword.declaration.swift", + "match": "\\b(deinit|import|init|subscript)\\b" + }, + { + "name": "keyword.other.placeholder.swift", + "match": "\\b(_)\\b" + }, + { + "name": "variable.language.swift", + "match": "\\b(new|super)\\b" + }, + { + "name": "keyword.reserved.swift", + "match": "\\b(associativity|didSet|get|infix|inout|left|mutating|nonmutating|operator|override|postfix|precedence|prefix|right|set|unowned|unowned(safe)|unowned(unsafe)|weak|willSet)\\b" + } + ] + }, + "meta": { + "patterns": [] + }, + "operator": { + "patterns": [ + { + "name": "keyword.operator.swift", + "match": "\\B[\\/=\\-+!*%<>&|^~\\?:]\\B" + }, + { + "name": "keyword.operator.access.swift", + "match": "[.](?!\\d)" + } + ] + }, + "punctuation": { + "patterns": [ + { + "name": "punctuation.other.comma.swift", + "match": "," + }, + { + "name": "punctuation.other.paren.swift", + "match": "[)(]" + } + ] + }, + "storage": { + "patterns": [ + { + "name": "storage.modifier.swift", + "match": "\\b(final|internal|private|fileprivate|public|open|override|static|required|convenience)\\b" + }, + { + "name": "storage.type.swift", + "match": "\\b(class|enum|extension|protocol|precedencegroup|struct|typealias)\\b" + }, + { + "name": "storage.type.swift", + "match": "\\b(typealias|precedencegroup)\\b" + } + ] + }, + "escaped-char": { + "patterns": [ + { + "name": "constant.character.escape.swift", + "match": "\\\\[0\\\\tnr\"']" + }, + { + "name": "constant.character.escape.swift", + "match": "\\\\(x\\h{2}|u\\h{4}|U\\h{8})" + }, + { + "name": "invalid.illegal.constant.character.escape.swift", + "match": "\\\\[^uxU]" + } + ] + }, + "string": { + "patterns": [ + { + "name": "string.quoted.single.swift", + "begin": "'", + "end": "'" + }, + { + "name": "string.quoted.double.swift", + "begin": "\"", + "end": "\"", + "patterns": [ + { + "begin": "\\\\\\(", + "end": "\\)", + "beginCaptures": { + "0": { + "name": "punctuation.section.embedded.begin.swift" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.section.embedded.end.swift" + } + }, + "patterns": [ + { + "name": "meta.embedded.line.swift", + "match": "." + } + ] + }, + { + "include": "#escaped-char" + } + ] + } + ] + }, + "support": { + "patterns": [] + }, + "type": { + "patterns": [ + { + "match": "(?<=->\\s)([a-zA-Z][a-zA-Z_?]+)", + "captures": { + "1": { + "name": "entity.name.type.return_type.swift" + } + } + }, + { + "name": "support.type.swift", + "match": "(?x) \\b(Character|U?Int|U?Int(8|16|32|64) |Float|Double|Float(32|64)|Bool|String|Date|Data|URL |(double|float)[234]|(double|float)[234]x[234] |Any |AnyObject |Error |Equatable |Hashable |Comparable |CustomDebugStringConvertible |CustomStringConvertible |OptionSet |ManagedBuffer |ManagedBufferPointer |BitwiseOperations |CountedSet |Counter |Directions |ExpressibleByArrayLiteral |ExpressibleByBooleanLiteral |ExpressibleByDictionaryLiteral |ExpressibleByExtendedGraphemeClusterLiteral |ExpressibleByFloatLitera |ExpressibleByIntegerLiteral |ExpressibleByNilLiteral |ExpressibleByStringInterpolation |ExpressibleByStringLiteral |ExpressibleByUnicodeScalarLiteral |OrderedSet |PaperSize |RawRepresentable |(UI|NS|CF|CG)[A-Z][a-zA-Z0-9]+ |Stream |(In|Out)putStream |FileManager |Array |Unsafe[a-zA-Z]*Pointer |Bundle |Jex)\\b[?]?" + } + ] + }, + "variable": { + "patterns": [ + { + "match": "\\b(self)\\b", + "name": "variable.language.self.swift" + }, + { + "match": "\\b(let|var)\\s([a-zA-Z0-9]+)(:?)\\s([a-zA-Z0-9]+)?", + "captures": { + "1": { + "name": "storage.type.swift" + }, + "2": { + "name": "variable.other.swift" + }, + "3": { + "name": "punctuation.definition.type.swift" + }, + "4": { + "name": "entity.name.type.swift" + } + } + } + ] + } + } +} diff --git a/lem.asd b/lem.asd index 84dc647f0..a3137f53e 100644 --- a/lem.asd +++ b/lem.asd @@ -138,6 +138,7 @@ "lem-lisp-mode" #+sbcl "lem-go-mode" + "lem-swift-mode" "lem-c-mode" "lem-xml-mode"