diff --git a/CodeLanguages-Container/CodeLanguages-Container.xcodeproj/project.pbxproj b/CodeLanguages-Container/CodeLanguages-Container.xcodeproj/project.pbxproj index 96eb55c3..96315045 100644 --- a/CodeLanguages-Container/CodeLanguages-Container.xcodeproj/project.pbxproj +++ b/CodeLanguages-Container/CodeLanguages-Container.xcodeproj/project.pbxproj @@ -7,8 +7,10 @@ objects = { /* Begin PBXBuildFile section */ + 28171CB2298143C400523F1C /* TreeSitterObjC in Frameworks */ = {isa = PBXBuildFile; productRef = 28171CB1298143C400523F1C /* TreeSitterObjC */; }; 282E5977298051980064B34A /* TreeSitterYAML in Frameworks */ = {isa = PBXBuildFile; productRef = 282E5976298051980064B34A /* TreeSitterYAML */; }; 2846B262296BA1CF005F60B6 /* TreeSitterDockerfile in Frameworks */ = {isa = PBXBuildFile; productRef = 2846B261296BA1CF005F60B6 /* TreeSitterDockerfile */; }; + 2886C788298135540023E016 /* TreeSitterKotlin in Frameworks */ = {isa = PBXBuildFile; productRef = 2886C787298135540023E016 /* TreeSitterKotlin */; }; 28B3F010290C207D000CD04D /* CodeLanguages_Container.h in Headers */ = {isa = PBXBuildFile; fileRef = 28B3F00F290C207D000CD04D /* CodeLanguages_Container.h */; settings = {ATTRIBUTES = (Public, ); }; }; 28B3F02D290C35D9000CD04D /* TreeSitterC in Frameworks */ = {isa = PBXBuildFile; productRef = 28B3F02C290C35D9000CD04D /* TreeSitterC */; }; 28B3F030290C35F9000CD04D /* TreeSitterCPP in Frameworks */ = {isa = PBXBuildFile; productRef = 28B3F02F290C35F9000CD04D /* TreeSitterCPP */; }; @@ -60,8 +62,10 @@ 28B3F045290C366E000CD04D /* TreeSitterHTML in Frameworks */, 28B3F05A290C36E5000CD04D /* TreeSitterRust in Frameworks */, 28B3F054290C36C5000CD04D /* TreeSitterPython in Frameworks */, + 28171CB2298143C400523F1C /* TreeSitterObjC in Frameworks */, 28B3F048290C367C000CD04D /* TreeSitterJava in Frameworks */, 282E5977298051980064B34A /* TreeSitterYAML in Frameworks */, + 2886C788298135540023E016 /* TreeSitterKotlin in Frameworks */, 28B3F057290C36D5000CD04D /* TreeSitterRuby in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -160,6 +164,8 @@ 28B9F7A9290DDAC900245748 /* TreeSitterBash */, 2846B261296BA1CF005F60B6 /* TreeSitterDockerfile */, 282E5976298051980064B34A /* TreeSitterYAML */, + 2886C787298135540023E016 /* TreeSitterKotlin */, + 28171CB1298143C400523F1C /* TreeSitterObjC */, ); productName = "CodeLanguages-Container"; productReference = 28B3F00C290C207D000CD04D /* CodeLanguages_Container.framework */; @@ -211,6 +217,8 @@ 28B9F7A6290DDAB500245748 /* XCRemoteSwiftPackageReference "tree-sitter-bash" */, 2846B260296BA1CF005F60B6 /* XCRemoteSwiftPackageReference "tree-sitter-dockerfile" */, 282E5975298051980064B34A /* XCRemoteSwiftPackageReference "tree-sitter-yaml" */, + 2886C786298135540023E016 /* XCRemoteSwiftPackageReference "tree-sitter-kotlin" */, + 28171CB0298143C400523F1C /* XCRemoteSwiftPackageReference "tree-sitter-objc" */, ); productRefGroup = 28B3F00D290C207D000CD04D /* Products */; projectDirPath = ""; @@ -450,6 +458,14 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ + 28171CB0298143C400523F1C /* XCRemoteSwiftPackageReference "tree-sitter-objc" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/CodeEditApp/tree-sitter-objc"; + requirement = { + branch = feature/spm; + kind = branch; + }; + }; 282E5975298051980064B34A /* XCRemoteSwiftPackageReference "tree-sitter-yaml" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/lukepistrol/tree-sitter-yaml.git"; @@ -466,6 +482,14 @@ kind = branch; }; }; + 2886C786298135540023E016 /* XCRemoteSwiftPackageReference "tree-sitter-kotlin" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/lukepistrol/tree-sitter-kotlin"; + requirement = { + branch = "feature/spm-queries"; + kind = branch; + }; + }; 28B3F02B290C35D9000CD04D /* XCRemoteSwiftPackageReference "tree-sitter-c" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/tree-sitter/tree-sitter-c.git"; @@ -621,6 +645,11 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ + 28171CB1298143C400523F1C /* TreeSitterObjC */ = { + isa = XCSwiftPackageProductDependency; + package = 28171CB0298143C400523F1C /* XCRemoteSwiftPackageReference "tree-sitter-objc" */; + productName = TreeSitterObjC; + }; 282E5976298051980064B34A /* TreeSitterYAML */ = { isa = XCSwiftPackageProductDependency; package = 282E5975298051980064B34A /* XCRemoteSwiftPackageReference "tree-sitter-yaml" */; @@ -631,6 +660,11 @@ package = 2846B260296BA1CF005F60B6 /* XCRemoteSwiftPackageReference "tree-sitter-dockerfile" */; productName = TreeSitterDockerfile; }; + 2886C787298135540023E016 /* TreeSitterKotlin */ = { + isa = XCSwiftPackageProductDependency; + package = 2886C786298135540023E016 /* XCRemoteSwiftPackageReference "tree-sitter-kotlin" */; + productName = TreeSitterKotlin; + }; 28B3F02C290C35D9000CD04D /* TreeSitterC */ = { isa = XCSwiftPackageProductDependency; package = 28B3F02B290C35D9000CD04D /* XCRemoteSwiftPackageReference "tree-sitter-c" */; diff --git a/CodeLanguages-Container/CodeLanguages-Container.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/CodeLanguages-Container/CodeLanguages-Container.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index f0d45d91..43532471 100644 --- a/CodeLanguages-Container/CodeLanguages-Container.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/CodeLanguages-Container/CodeLanguages-Container.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -123,7 +123,7 @@ "location" : "https://github.com/tree-sitter/tree-sitter-javascript.git", "state" : { "branch" : "master", - "revision" : "7a29d06274b7cf87d643212a433d970b73969016" + "revision" : "15e85e80b851983fab6b12dce5a535f5a0df0f9c" } }, { @@ -135,6 +135,24 @@ "revision" : "73076754005a460947cafe8e03a8cf5fa4fa2938" } }, + { + "identity" : "tree-sitter-kotlin", + "kind" : "remoteSourceControl", + "location" : "https://github.com/lukepistrol/tree-sitter-kotlin", + "state" : { + "branch" : "feature/spm-queries", + "revision" : "e32e32678449efaeccd908e41ed6b27ec8c9d2cf" + } + }, + { + "identity" : "tree-sitter-objc", + "kind" : "remoteSourceControl", + "location" : "https://github.com/CodeEditApp/tree-sitter-objc", + "state" : { + "branch" : "feature/spm", + "revision" : "1b54ef0b5efddddf393b45e173788499cc572048" + } + }, { "identity" : "tree-sitter-php", "kind" : "remoteSourceControl", diff --git a/CodeLanguages-Container/CodeLanguages-Container/CodeLanguages_Container.h b/CodeLanguages-Container/CodeLanguages-Container/CodeLanguages_Container.h index f5bf87d8..bb9aa019 100644 --- a/CodeLanguages-Container/CodeLanguages-Container/CodeLanguages_Container.h +++ b/CodeLanguages-Container/CodeLanguages-Container/CodeLanguages_Container.h @@ -36,6 +36,8 @@ extern TSLanguage *tree_sitter_html(); extern TSLanguage *tree_sitter_java(); extern TSLanguage *tree_sitter_javascript(); extern TSLanguage *tree_sitter_json(); +extern TSLanguage *tree_sitter_kotlin(); +extern TSLanguage *tree_sitter_objc(); extern TSLanguage *tree_sitter_php(); extern TSLanguage *tree_sitter_python(); extern TSLanguage *tree_sitter_ruby(); diff --git a/CodeLanguagesContainer.xcframework.zip b/CodeLanguagesContainer.xcframework.zip index a0fba872..dbc7edc8 100644 Binary files a/CodeLanguagesContainer.xcframework.zip and b/CodeLanguagesContainer.xcframework.zip differ diff --git a/README.md b/README.md index fe740759..3bdb454a 100644 --- a/README.md +++ b/README.md @@ -64,8 +64,9 @@ In order to add support for additional languages we have a complete guide on how | [JSDoc](https://github.com/tree-sitter/tree-sitter-jsdoc) | | | | [JSON](https://github.com/mattmassicotte/tree-sitter-json) | ✅ | ✅ | | [Julia](https://github.com/tree-sitter/tree-sitter-julia) | | _not available_ | -| [Kotlin](https://github.com/fwcd/tree-sitter-kotlin) | | _not available_ | +| [Kotlin](https://github.com/fwcd/tree-sitter-kotlin/tree/feature/spm-queries) | ✅ | ✅ | | [Markdown](https://github.com/ikatyang/tree-sitter-markdown) | | _not available_ | +| [Objective C](https://github.com/CodeEditApp/tree-sitter-objc/tree/feature/spm) | ✅ | ✅ | | [OCaml](https://github.com/tree-sitter/tree-sitter-ocaml) | | | | Plain Text | ✅ | _not available_ | | [Perl](https://github.com/ganezdragon/tree-sitter-perl) | | _not available_ | diff --git a/Sources/CodeEditLanguages/CodeLanguage+Definitions.swift b/Sources/CodeEditLanguages/CodeLanguage+Definitions.swift index 549f7e03..57cd1a97 100644 --- a/Sources/CodeEditLanguages/CodeLanguage+Definitions.swift +++ b/Sources/CodeEditLanguages/CodeLanguage+Definitions.swift @@ -26,6 +26,8 @@ public extension CodeLanguage { .javascript, .json, .jsx, + .kotlin, + .objc, .php, .python, .ruby, @@ -142,6 +144,20 @@ public extension CodeLanguage { highlights: ["highlights-jsx"] ) + /// A language structure for `Kotlin` + static let kotlin: CodeLanguage = .init( + id: .kotlin, + tsName: "kotlin", + extensions: ["kt", "kts"] + ) + + /// A language structure for `Objective C` + static let objc: CodeLanguage = .init( + id: .objc, + tsName: "objc", + extensions: ["m"] + ) + /// A language structure for `PHP` static let php: CodeLanguage = .init( id: .php, diff --git a/Sources/CodeEditLanguages/CodeLanguage.swift b/Sources/CodeEditLanguages/CodeLanguage.swift index 54cdfbce..02948013 100644 --- a/Sources/CodeEditLanguages/CodeLanguage.swift +++ b/Sources/CodeEditLanguages/CodeLanguage.swift @@ -96,6 +96,10 @@ public struct CodeLanguage { return tree_sitter_json() case .jsx: return tree_sitter_javascript() + case .kotlin: + return tree_sitter_kotlin() + case .objc: + return tree_sitter_objc() case .php: return tree_sitter_php() case .python: diff --git a/Sources/CodeEditLanguages/Documentation.docc/CodeLanguage.md b/Sources/CodeEditLanguages/Documentation.docc/CodeLanguage.md index 3cc6a846..3a8b6b57 100644 --- a/Sources/CodeEditLanguages/Documentation.docc/CodeLanguage.md +++ b/Sources/CodeEditLanguages/Documentation.docc/CodeLanguage.md @@ -34,6 +34,8 @@ let language = CodeLanguage.detectLanguageFrom(url: fileURL) - JavaScript - JSON - JSX +- Kotlin +- Objective C - PHP - Python - Ruby @@ -78,6 +80,8 @@ let language = CodeLanguage.detectLanguageFrom(url: fileURL) - ``javascript`` - ``json`` - ``jsx`` +- ``kotlin`` +- ``objc`` - ``php`` - ``python`` - ``ruby`` diff --git a/Sources/CodeEditLanguages/Documentation.docc/TreeSitterModel.md b/Sources/CodeEditLanguages/Documentation.docc/TreeSitterModel.md index 54a43a97..24521490 100644 --- a/Sources/CodeEditLanguages/Documentation.docc/TreeSitterModel.md +++ b/Sources/CodeEditLanguages/Documentation.docc/TreeSitterModel.md @@ -47,6 +47,8 @@ let query = TreeSitterModel.shared.swiftQuery - ``javascriptQuery`` - ``jsonQuery`` - ``jsxQuery`` +- ``kotlinQuery`` +- ``objcQuery`` - ``phpQuery`` - ``pythonQuery`` - ``rubyQuery`` diff --git a/Sources/CodeEditLanguages/Resources/tree-sitter-javascript/tags.scm b/Sources/CodeEditLanguages/Resources/tree-sitter-javascript/tags.scm index a7bbd311..e32eaf3c 100644 --- a/Sources/CodeEditLanguages/Resources/tree-sitter-javascript/tags.scm +++ b/Sources/CodeEditLanguages/Resources/tree-sitter-javascript/tags.scm @@ -86,3 +86,14 @@ (new_expression constructor: (_) @name) @reference.class + +(export_statement value: (assignment_expression left: (identifier) @name right: ([ + (number) + (string) + (identifier) + (undefined) + (null) + (new_expression) + (binary_expression) + (call_expression) +]))) @definition.constant \ No newline at end of file diff --git a/Sources/CodeEditLanguages/Resources/tree-sitter-kotlin/highlights.scm b/Sources/CodeEditLanguages/Resources/tree-sitter-kotlin/highlights.scm new file mode 100644 index 00000000..ad7a3dcd --- /dev/null +++ b/Sources/CodeEditLanguages/Resources/tree-sitter-kotlin/highlights.scm @@ -0,0 +1,416 @@ +;;; Identifiers + +(simple_identifier) @variable + +; `it` keyword inside lambdas +; FIXME: This will highlight the keyword outside of lambdas since tree-sitter +; does not allow us to check for arbitrary nestation +((simple_identifier) @variable.builtin +(#eq? @variable.builtin "it")) + +; `field` keyword inside property getter/setter +; FIXME: This will highlight the keyword outside of getters and setters +; since tree-sitter does not allow us to check for arbitrary nestation +((simple_identifier) @variable.builtin +(#eq? @variable.builtin "field")) + +; `this` this keyword inside classes +(this_expression) @variable.builtin + +; `super` keyword inside classes +(super_expression) @variable.builtin + +(class_parameter + (simple_identifier) @property) + +(class_body + (property_declaration + (variable_declaration + (simple_identifier) @property))) + +; id_1.id_2.id_3: `id_2` and `id_3` are assumed as object properties +(_ + (navigation_suffix + (simple_identifier) @property)) + +; SCREAMING CASE identifiers are assumed to be constants +((simple_identifier) @constant +(#match? @constant "^[A-Z][A-Z0-9_]*$")) + +(_ + (navigation_suffix + (simple_identifier) @constant + (#match? @constant "^[A-Z][A-Z0-9_]*$"))) + +(enum_entry + (simple_identifier) @constant) + +(type_identifier) @type + +(type_alias + (type_identifier) @type.definition) + +((type_identifier) @type.builtin + (#any-of? @type.builtin + "Byte" + "Short" + "Int" + "Long" + "UByte" + "UShort" + "UInt" + "ULong" + "Float" + "Double" + "Boolean" + "Char" + "String" + "Array" + "ByteArray" + "ShortArray" + "IntArray" + "LongArray" + "UByteArray" + "UShortArray" + "UIntArray" + "ULongArray" + "FloatArray" + "DoubleArray" + "BooleanArray" + "CharArray" + "Map" + "Set" + "List" + "EmptyMap" + "EmptySet" + "EmptyList" + "MutableMap" + "MutableSet" + "MutableList" +)) + +(package_header "package" @keyword + . (identifier (simple_identifier) @namespace)) + +(import_header + "import" @include) + +; The last `simple_identifier` in a `import_header` will always either be a function +; or a type. Classes can appear anywhere in the import path, unlike functions +(import_header + (identifier + (simple_identifier) @type @_import) + (import_alias + (type_identifier) @type.definition)? + (#match? @_import "^[A-Z]")) + +(import_header + (identifier + (simple_identifier) @function @_import .) + (import_alias + (type_identifier) @function)? + (#match? @_import "^[a-z]")) + +; TODO: Seperate labeled returns/breaks/continue/super/this +; Must be implemented in the parser first +(label) @label + +;;; Function definitions + +(function_declaration + . (simple_identifier) @function) + +(getter + ("get") @function.builtin) +(setter + ("set") @function.builtin) + +(primary_constructor) @constructor +(secondary_constructor + ("constructor") @constructor) + +(constructor_invocation + (user_type + (type_identifier) @constructor)) + +(anonymous_initializer + ("init") @constructor) + +(parameter + (simple_identifier) @parameter) + +(parameter_with_optional_type + (simple_identifier) @parameter) + +; lambda parameters +(lambda_literal + (lambda_parameters + (variable_declaration + (simple_identifier) @parameter))) + +;;; Function calls + +; function() +(call_expression + . (simple_identifier) @function.call) + +; object.function() or object.property.function() +(call_expression + (navigation_expression + (navigation_suffix + (simple_identifier) @function.call) . )) + +(call_expression + . (simple_identifier) @function.builtin + (#any-of? @function.builtin + "arrayOf" + "arrayOfNulls" + "byteArrayOf" + "shortArrayOf" + "intArrayOf" + "longArrayOf" + "ubyteArrayOf" + "ushortArrayOf" + "uintArrayOf" + "ulongArrayOf" + "floatArrayOf" + "doubleArrayOf" + "booleanArrayOf" + "charArrayOf" + "emptyArray" + "mapOf" + "setOf" + "listOf" + "emptyMap" + "emptySet" + "emptyList" + "mutableMapOf" + "mutableSetOf" + "mutableListOf" + "print" + "println" + "error" + "TODO" + "run" + "runCatching" + "repeat" + "lazy" + "lazyOf" + "enumValues" + "enumValueOf" + "assert" + "check" + "checkNotNull" + "require" + "requireNotNull" + "with" + "suspend" + "synchronized" +)) + +;;; Literals + +(comment) @comment + +(shebang_line) @preproc + +(comment) @spell + +(real_literal) @float +[ + (integer_literal) + (long_literal) + (hex_literal) + (bin_literal) + (unsigned_literal) +] @number + +[ + "null" ; should be highlighted the same as booleans + (boolean_literal) +] @boolean + +(character_literal) @character + +[ + (line_string_literal) + (multi_line_string_literal) +] @string + +; NOTE: Escapes not allowed in multi-line strings +(line_string_literal (character_escape_seq) @string.escape) + +; There are 3 ways to define a regex +; - "[abc]?".toRegex() +(call_expression + (navigation_expression + ([(line_string_literal) (multi_line_string_literal)] @string.regex) + (navigation_suffix + ((simple_identifier) @_function + (#eq? @_function "toRegex"))))) + +; - Regex("[abc]?") +(call_expression + ((simple_identifier) @_function + (#eq? @_function "Regex")) + (call_suffix + (value_arguments + (value_argument + [ (line_string_literal) (multi_line_string_literal) ] @string.regex)))) + +; - Regex.fromLiteral("[abc]?") +(call_expression + (navigation_expression + ((simple_identifier) @_class + (#eq? @_class "Regex")) + (navigation_suffix + ((simple_identifier) @_function + (#eq? @_function "fromLiteral")))) + (call_suffix + (value_arguments + (value_argument + [ (line_string_literal) (multi_line_string_literal) ] @string.regex)))) + +;;; Keywords + +(type_alias "typealias" @keyword) + +(companion_object "companion" @keyword) + +[ + (class_modifier) + (member_modifier) + (function_modifier) + (property_modifier) + (platform_modifier) + (variance_modifier) + (parameter_modifier) + (visibility_modifier) + (reification_modifier) + (inheritance_modifier) +] @type.qualifier + +[ + "val" + "var" + "enum" + "class" + "object" + "interface" +; "typeof" ; NOTE: It is reserved for future use +] @keyword + +("fun") @keyword.function + +(jump_expression) @keyword.return + +[ + "if" + "else" + "when" +] @conditional + +[ + "for" + "do" + "while" +] @repeat + +[ + "try" + "catch" + "throw" + "finally" +] @exception + + +(annotation + "@" @attribute (use_site_target)? @attribute) +(annotation + (user_type + (type_identifier) @attribute)) +(annotation + (constructor_invocation + (user_type + (type_identifier) @attribute))) + +(file_annotation + "@" @attribute "file" @attribute ":" @attribute) +(file_annotation + (user_type + (type_identifier) @attribute)) +(file_annotation + (constructor_invocation + (user_type + (type_identifier) @attribute))) + +;;; Operators & Punctuation + +[ + "!" + "!=" + "!==" + "=" + "==" + "===" + ">" + ">=" + "<" + "<=" + "||" + "&&" + "+" + "++" + "+=" + "-" + "--" + "-=" + "*" + "*=" + "/" + "/=" + "%" + "%=" + "?." + "?:" + "!!" + "is" + "!is" + "in" + "!in" + "as" + "as?" + ".." + "->" +] @operator + +[ + "(" ")" + "[" "]" + "{" "}" +] @punctuation.bracket + +[ + "." + "," + ";" + ":" + "::" +] @punctuation.delimiter + +; NOTE: `interpolated_identifier`s can be highlighted in any way +(line_string_literal + "$" @punctuation.special + (interpolated_identifier) @none) +(line_string_literal + "${" @punctuation.special + (interpolated_expression) @none + "}" @punctuation.special) + +(multi_line_string_literal + "$" @punctuation.special + (interpolated_identifier) @none) +(multi_line_string_literal + "${" @punctuation.special + (interpolated_expression) @none + "}" @punctuation.special) diff --git a/Sources/CodeEditLanguages/Resources/tree-sitter-objc/highlights.scm b/Sources/CodeEditLanguages/Resources/tree-sitter-objc/highlights.scm new file mode 100644 index 00000000..ff4c8faa --- /dev/null +++ b/Sources/CodeEditLanguages/Resources/tree-sitter-objc/highlights.scm @@ -0,0 +1,395 @@ +[ + (comment) + (pragma) +] @comment + +[ + (self) + (super) +] @variable.builtin + +[ + (getter) + (setter) + (nonnull) + (nullable) + (null_resettable) + (unsafe_unretained) + (null_unspecified) + (direct) + (readwrite) + (readonly) + (strong) + (weak) + (copy) + (assign) + (retain) + (atomic) + (nonatomic) + (class) + (NS_NONATOMIC_IOSONLY) + (DISPATCH_QUEUE_REFERENCE_TYPE) +] @keyword + +[ + "@interface" + "@protocol" + "@property" + "@end" + "@implementation" + "@compatibility_alias" + "@autoreleasepool" + "@synchronized" + "@class" + "@synthesize" + "@dynamic" + "@defs" + "@try" + "@catch" + "@finally" + "@throw" + "@selector" + "@encode" + (private) + (public) + (protected) + (package) + (optional) + (required) + "NS_ENUM" + "NS_ERROR_ENUM" + "NS_OPTIONS" + "NS_SWIFT_NAME" + (type_qualifier) + (storage_class_specifier) + "NS_NOESCAPE" + "const" + "default" + "enum" + "extern" + "inline" + "static" + "struct" + "typedef" + "typeof" + "__typeof" + "__typeof__" + "_Atomic" + "union" + "volatile" + "goto" + "register" + "__covariant" + "__contravariant" + "__GENERICS" +] @keyword + +"sizeof" @keyword.operator +"return" @keyword.return + +[ + "while" + "for" + "do" + "continue" + "break" +] @keyword.repeat + +"#define" @constant.macro + +[ + "#if" + "#ifdef" + "#ifndef" + "#else" + "#elif" + "#endif" + (preproc_directive) +] @keyword + +"#include" @include +"#import" @include +"@import" @include + +[ + "=" + + "-" + "*" + "/" + "+" + "%" + + "~" + "|" + "&" + "^" + "<<" + ">>" + + "->" + + "<" + "<=" + ">=" + ">" + "==" + "!=" + + "!" + "&&" + "||" + + "-=" + "+=" + "*=" + "/=" + "%=" + "|=" + "&=" + "^=" + ">>=" + "<<=" + "--" + "++" + "@" +] @operator + +[ + "if" + "else" + "case" + "switch" +] @keyword.conditional + +(conditional_expression [ "?" ":" ] @keyword.conditional) + +[ + (true) + (false) + (YES) + (NO) +] @keyword.boolean + +[ "." ";" ":" "," ] @punctuation.delimiter + +"..." @punctuation.special + +[ "(" ")" "[" "]" "{" "}"] @punctuation.bracket + +[ + (string_literal) + (string_expression) + (system_lib_string) + (module_string) +] @string + +(escape_sequence) @string.escape + +(null) @constant.builtin +(nil) @constant.builtin +(number_literal) @number +(number_expression) @number +(char_literal) @character + +[ + (preproc_arg) + (preproc_defined) +] @function.macro + +[ + (type_identifier) + (primitive_type) + (sized_type_specifier) + (type_descriptor) + (generics_type_reference) +] @type + +[ + (id) + (Class) + (Method) + (IMP) + (SEL) + (BOOL) + (instancetype) + (auto) +] @type.builtin + +(declaration (type_qualifier) @type) +(cast_expression type: (type_descriptor) @type) +(sizeof_expression value: (parenthesized_expression (identifier) @type)) + +;; Type Class & Category & Protocol +(class_interface name: (identifier) @type.class) +(category_interface name: (identifier) @type.class) +(category_interface category: (identifier) @type.category) +(superclass_reference name: (identifier) @type.class) +(parameterized_class_type_arguments) @type.class +(class_implementation name: (identifier) @type.class) +(category_implementation name: (identifier) @type.class) +(compatibility_alias_declaration (identifier) @type.class) +(parameterized_class_type_arguments (identifier) @type.class) +(category_implementation category: (identifier) @type.category) +(class_forward_declaration name: (identifier) @type.class) +(protocol_forward_declaration name: (identifier) @type.protocol) +(protocol_declaration name: (identifier) @type.protocol) +(protocol_qualifiers name: (identifier) @type.protocol) +(protocol_expression (identifier) @type.protocol) + +;; Preproc def / undef +(preproc_def + name: (_) @constant) +(preproc_call + directive: (preproc_directive) @_u + argument: (_) @constant + (#eq? @_u "#undef")) + +;; Property +(property_declaration + type: _ @type + declarator: (identifier) @property) + +(property_declaration + type: _ @type + declarator: (_ + declarator: (identifier) @property)) + +(property_declaration + type: _ @type + declarator: (_ + declarator: (_ + declarator: (identifier) @property))) + +(((field_expression + (field_identifier) @property)) @_parent + (#not-has-parent? @_parent function_declarator call_expression)) + +(field_expression + field: (field_identifier) @property) + +(((field_identifier) @property) + (#has-ancestor? @property field_declaration) + (#not-has-ancestor? @property function_declarator)) + +;; Variable +declarator: (identifier) @variable + +(cast_expression value: (identifier) @variable) + +;; Function +(call_expression + function: (identifier) @function) +(function_declarator + declarator: (identifier) @function) +(preproc_function_def + name: (identifier) @function.macro) +(selector_expression + name: (identifier) @function) +(method_declaration + selector: (identifier) @function) + +(method_declaration + (keyword_selector + (keyword_declarator + keyword: (identifier) @function))) + +(method_declaration + (keyword_selector + (keyword_declarator + name: (identifier) @variable.parameter))) + +(message_expression + receiver: (field_expression + field: (field_identifier) @function)) + +(method_definition + selector: (identifier) @function) + +(swift_name_attribute_sepcifier + method: (identifier) @function) + +(setter + name: (identifier) @function) + +(method_definition + (keyword_selector + (keyword_declarator + keyword: (identifier) @function))) + +(message_expression + selector: (identifier) @function) + +(method_definition + (keyword_selector + (keyword_declarator + name: (identifier) @variable.parameter))) + +(message_expression + selector: (keyword_argument_list + (keyword_argument + keyword: (identifier) @function))) + +(message_expression + selector: (keyword_argument_list + (keyword_argument + argument: (identifier) @variable.parameter))) + +(unary_expression argument: (identifier) @function) +(va_arg_expression) @function +(va_arg_expression va_list: (identifier) @variable) +(enumerator name: (identifier) @variable) + + +;; Parameters +(parameter_declaration + declarator: (identifier) @variable.parameter) + +(parameter_declaration + declarator: (pointer_declarator) @variable.parameter) + +(parameter_declaration + declarator: (pointer_declarator + declarator: (identifier) @variable.parameter)) + +(for_in_statement + loop: (identifier) @variable) + +(dictionary_expression + key: (_expression) @variable) +(dictionary_expression + value: (_expression) @variable) +(array_expression + (identifier) @variable) +(argument_list + (identifier) @variable) +(expression_statement + (identifier) @variable) +(_expression (identifier) @variable) + +[ + "__attribute" + "__attribute__" + "__cdecl" + "__clrcall" + "__stdcall" + "__fastcall" + "__thiscall" + "__vectorcall" + "_unaligned" + "__unaligned" + "__declspec" + "__unused" + "__builtin_available" + "@available" + (attribute_specifier) + (class_interface_attribute_sepcifier) + (method_variadic_arguments_attribute_specifier) +] @attribute + +(attribute_specifier) @attribute + +((identifier) @constant + (#match? @constant "^[A-Z][A-Z0-9_$]+$")) + +(ERROR) @error \ No newline at end of file diff --git a/Sources/CodeEditLanguages/TreeSitterLanguage.swift b/Sources/CodeEditLanguages/TreeSitterLanguage.swift index 137cd02d..b87818b5 100644 --- a/Sources/CodeEditLanguages/TreeSitterLanguage.swift +++ b/Sources/CodeEditLanguages/TreeSitterLanguage.swift @@ -24,6 +24,8 @@ public enum TreeSitterLanguage: String { case javascript case json case jsx + case kotlin + case objc case php case python case ruby diff --git a/Sources/CodeEditLanguages/TreeSitterModel.swift b/Sources/CodeEditLanguages/TreeSitterModel.swift index 634ced9a..faac3df0 100644 --- a/Sources/CodeEditLanguages/TreeSitterModel.swift +++ b/Sources/CodeEditLanguages/TreeSitterModel.swift @@ -17,7 +17,8 @@ public class TreeSitterModel { /// Get a query for a specific language /// - Parameter language: The language to request the query for. /// - Returns: A Query if available. Returns `nil` for not implemented languages - public func query(for language: TreeSitterLanguage) -> Query? { // swiftlint:disable:this cyclomatic_complexity + public func query(for language: TreeSitterLanguage) -> Query? { + // swiftlint:disable:previous cyclomatic_complexity function_body_length switch language { case .bash: return bashQuery @@ -49,6 +50,10 @@ public class TreeSitterModel { return jsonQuery case .jsx: return jsxQuery + case .kotlin: + return kotlinQuery + case .objc: + return objcQuery case .php: return phpQuery case .python: @@ -143,6 +148,16 @@ public class TreeSitterModel { return queryFor(.json) }() + /// Query for `Kotlin` files. + public private(set) lazy var kotlinQuery: Query? = { + return queryFor(.kotlin) + }() + + /// Query for `Objective C` files. + public private(set) lazy var objcQuery: Query? = { + return queryFor(.objc) + }() + /// Query for `PHP` files. public private(set) lazy var phpQuery: Query? = { return queryFor(.php) diff --git a/Tests/CodeEditLanguagesTests/CodeEditLanguagesTests.swift b/Tests/CodeEditLanguagesTests/CodeEditLanguagesTests.swift index be17dbc5..a60c0165 100644 --- a/Tests/CodeEditLanguagesTests/CodeEditLanguagesTests.swift +++ b/Tests/CodeEditLanguagesTests/CodeEditLanguagesTests.swift @@ -348,6 +348,51 @@ final class CodeEditLanguagesTests: XCTestCase { XCTAssertNotEqual(query?.patternCount, 0) } +// MARK: - Kotlin + + func test_CodeLanguageKotlin() throws { + let url = URL(fileURLWithPath: "~/path/to/file.kt") + let language = CodeLanguage.detectLanguageFrom(url: url) + + XCTAssertEqual(language.id, .kotlin) + } + + func test_CodeLanguageKotlin2() throws { + let url = URL(fileURLWithPath: "~/path/to/file.kts") + let language = CodeLanguage.detectLanguageFrom(url: url) + + XCTAssertEqual(language.id, .kotlin) + } + + func test_FetchQueryKotlin() throws { + var language = CodeLanguage.kotlin + language.resourceURL = bundleURL + + let data = try Data(contentsOf: language.queryURL!) + let query = try? Query(language: language.language!, data: data) + XCTAssertNotNil(query) + XCTAssertNotEqual(query?.patternCount, 0) + } + +// MARK: - Objective C + + func test_CodeLanguageObjC() throws { + let url = URL(fileURLWithPath: "~/path/to/file.m") + let language = CodeLanguage.detectLanguageFrom(url: url) + + XCTAssertEqual(language.id, .objc) + } + + func test_FetchQueryObjC() throws { + var language = CodeLanguage.objc + language.resourceURL = bundleURL + + let data = try Data(contentsOf: language.queryURL!) + let query = try? Query(language: language.language!, data: data) + XCTAssertNotNil(query) + XCTAssertNotEqual(query?.patternCount, 0) + } + // MARK: - PHP func test_CodeLanguagePHP() throws {