diff --git a/CodeLanguages-Container/CodeLanguages-Container.xcodeproj/project.pbxproj b/CodeLanguages-Container/CodeLanguages-Container.xcodeproj/project.pbxproj index ffe0a05..051675c 100644 --- a/CodeLanguages-Container/CodeLanguages-Container.xcodeproj/project.pbxproj +++ b/CodeLanguages-Container/CodeLanguages-Container.xcodeproj/project.pbxproj @@ -37,6 +37,7 @@ 6CA62EA929F9D36700785B11 /* TreeSitterTS in Frameworks */ = {isa = PBXBuildFile; productRef = 6CA62EA829F9D36700785B11 /* TreeSitterTS */; }; 6CA62EAB29F9D36700785B11 /* TreeSitterTSX in Frameworks */ = {isa = PBXBuildFile; productRef = 6CA62EAA29F9D36700785B11 /* TreeSitterTSX */; }; 6CEC70FE29C3A85000B61C7A /* TreeSitterRegex in Frameworks */ = {isa = PBXBuildFile; productRef = 6CEC70FD29C3A85000B61C7A /* TreeSitterRegex */; }; + 7DB18E9729FDC51C00F8EC00 /* TreeSitterScala in Frameworks */ = {isa = PBXBuildFile; productRef = 7DB18E9629FDC51C00F8EC00 /* TreeSitterScala */; }; 9D6DA3B8298F1A4600E69066 /* TreeSitterOCaml in Frameworks */ = {isa = PBXBuildFile; productRef = 9D6DA3B7298F1A4600E69066 /* TreeSitterOCaml */; }; /* End PBXBuildFile section */ @@ -61,6 +62,7 @@ 28B3F02D290C35D9000CD04D /* TreeSitterC in Frameworks */, 28B3F04B290C368B000CD04D /* TreeSitterJS in Frameworks */, 28B3F03C290C363E000CD04D /* TreeSitterGo in Frameworks */, + 7DB18E9729FDC51C00F8EC00 /* TreeSitterScala in Frameworks */, 28B3F05D290C3709000CD04D /* TreeSitterSwift in Frameworks */, 28B9F7AA290DDAC900245748 /* TreeSitterBash in Frameworks */, 28B3F030290C35F9000CD04D /* TreeSitterCPP in Frameworks */, @@ -187,6 +189,7 @@ 28AAB6AD29CA57D40087654B /* TreeSitterDart */, 6CA62EA829F9D36700785B11 /* TreeSitterTS */, 6CA62EAA29F9D36700785B11 /* TreeSitterTSX */, + 7DB18E9629FDC51C00F8EC00 /* TreeSitterScala */, ); productName = "CodeLanguages-Container"; productReference = 28B3F00C290C207D000CD04D /* CodeLanguages_Container.framework */; @@ -246,6 +249,7 @@ 6CEC70FC29C3A85000B61C7A /* XCRemoteSwiftPackageReference "tree-sitter-regex" */, 28AAB6AC29CA57D40087654B /* XCRemoteSwiftPackageReference "tree-sitter-dart" */, 6CA62EA729F9D36700785B11 /* XCRemoteSwiftPackageReference "tree-sitter-typescript" */, + 7DB18E9529FDC51C00F8EC00 /* XCRemoteSwiftPackageReference "tree-sitter-scala" */, ); productRefGroup = 28B3F00D290C207D000CD04D /* Products */; projectDirPath = ""; @@ -719,6 +723,14 @@ kind = branch; }; }; + 7DB18E9529FDC51C00F8EC00 /* XCRemoteSwiftPackageReference "tree-sitter-scala" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/bishabosha/tree-sitter-scala.git"; + requirement = { + branch = feature/spm; + kind = branch; + }; + }; 9D6DA3B6298F1A4500E69066 /* XCRemoteSwiftPackageReference "tree-sitter-ocaml" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/cengelbart39/tree-sitter-ocaml.git"; @@ -875,6 +887,11 @@ package = 6CEC70FC29C3A85000B61C7A /* XCRemoteSwiftPackageReference "tree-sitter-regex" */; productName = TreeSitterRegex; }; + 7DB18E9629FDC51C00F8EC00 /* TreeSitterScala */ = { + isa = XCSwiftPackageProductDependency; + package = 7DB18E9529FDC51C00F8EC00 /* XCRemoteSwiftPackageReference "tree-sitter-scala" */; + productName = TreeSitterScala; + }; 9D6DA3B7298F1A4600E69066 /* TreeSitterOCaml */ = { isa = XCSwiftPackageProductDependency; package = 9D6DA3B6298F1A4500E69066 /* XCRemoteSwiftPackageReference "tree-sitter-ocaml" */; 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 9b9830a..ac7b925 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 @@ -225,6 +225,15 @@ "revision" : "fbf9e507d09d8b3c0bb9dfc4d46c31039a47dc4a" } }, + { + "identity" : "tree-sitter-scala", + "kind" : "remoteSourceControl", + "location" : "https://github.com/bishabosha/tree-sitter-scala.git", + "state" : { + "branch" : "feature/spm", + "revision" : "d6e510497d9a16fa8e45f71908c21271566f63df" + } + }, { "identity" : "tree-sitter-sql", "kind" : "remoteSourceControl", diff --git a/CodeLanguages-Container/CodeLanguages-Container/CodeLanguages_Container.h b/CodeLanguages-Container/CodeLanguages-Container/CodeLanguages_Container.h index 5a04857..03e3655 100644 --- a/CodeLanguages-Container/CodeLanguages-Container/CodeLanguages_Container.h +++ b/CodeLanguages-Container/CodeLanguages-Container/CodeLanguages_Container.h @@ -47,6 +47,7 @@ extern TSLanguage *tree_sitter_python(); extern TSLanguage *tree_sitter_regex(); extern TSLanguage *tree_sitter_ruby(); extern TSLanguage *tree_sitter_rust(); +extern TSLanguage *tree_sitter_scala(); extern TSLanguage *tree_sitter_sql(); extern TSLanguage *tree_sitter_swift(); extern TSLanguage *tree_sitter_tsx(); diff --git a/CodeLanguagesContainer.xcframework.zip b/CodeLanguagesContainer.xcframework.zip index 515f337..d4bdf52 100644 Binary files a/CodeLanguagesContainer.xcframework.zip and b/CodeLanguagesContainer.xcframework.zip differ diff --git a/README.md b/README.md index d00b51d..219c871 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ In order to add support for additional languages we have a complete guide on how | [Regex](https://github.com/tree-sitter/tree-sitter-regex) | ✅ | ✅ | | [Ruby](https://github.com/mattmassicotte/tree-sitter-ruby) | ✅ | ✅ | | [Rust](https://github.com/tree-sitter/tree-sitter-rust) | ✅ | ✅ | -| [Scala](https://github.com/tree-sitter/tree-sitter-scala) | | | +| [Scala](https://github.com/tree-sitter/tree-sitter-scala) | ✅ | ✅ | | [Sql](https://github.com/lukepistrol/tree-sitter-sql/tree/feature/spm) | ✅ | ✅ | | [Swift](https://github.com/alex-pinkus/tree-sitter-swift/tree/with-generated-files) | ✅ | ✅ | | [TOML](https://github.com/ikatyang/tree-sitter-toml) | | | diff --git a/Sources/CodeEditLanguages/CodeLanguage+Definitions.swift b/Sources/CodeEditLanguages/CodeLanguage+Definitions.swift index 29a8ef6..c36ed66 100644 --- a/Sources/CodeEditLanguages/CodeLanguage+Definitions.swift +++ b/Sources/CodeEditLanguages/CodeLanguage+Definitions.swift @@ -37,6 +37,7 @@ public extension CodeLanguage { .regex, .ruby, .rust, + .scala, .sql, .swift, .tsx, @@ -236,6 +237,13 @@ public extension CodeLanguage { highlights: ["injections"] ) + /// A language structure for `Scala` + static let scala: CodeLanguage = .init( + id: .scala, + tsName: "scala", + extensions: ["scala", "sc"] + ) + /// A language structure for `SQL` static let sql: CodeLanguage = .init( id: .sql, diff --git a/Sources/CodeEditLanguages/CodeLanguage.swift b/Sources/CodeEditLanguages/CodeLanguage.swift index 5feff95..219ef34 100644 --- a/Sources/CodeEditLanguages/CodeLanguage.swift +++ b/Sources/CodeEditLanguages/CodeLanguage.swift @@ -118,6 +118,8 @@ public struct CodeLanguage { return tree_sitter_ruby() case .rust: return tree_sitter_rust() + case .scala: + return tree_sitter_scala() case .sql: return tree_sitter_sql() case .swift: diff --git a/Sources/CodeEditLanguages/Documentation.docc/CodeLanguage.md b/Sources/CodeEditLanguages/Documentation.docc/CodeLanguage.md index 428ff8b..a430cd9 100644 --- a/Sources/CodeEditLanguages/Documentation.docc/CodeLanguage.md +++ b/Sources/CodeEditLanguages/Documentation.docc/CodeLanguage.md @@ -43,6 +43,7 @@ let language = CodeLanguage.detectLanguageFrom(url: fileURL) - Python - Ruby - Rust +- Scala - SQL - Swift - YAML @@ -92,6 +93,7 @@ let language = CodeLanguage.detectLanguageFrom(url: fileURL) - ``python`` - ``ruby`` - ``rust`` +- ``scala`` - ``sql`` - ``swift`` - ``yaml`` diff --git a/Sources/CodeEditLanguages/Documentation.docc/TreeSitterModel.md b/Sources/CodeEditLanguages/Documentation.docc/TreeSitterModel.md index b1fa239..fd584ef 100644 --- a/Sources/CodeEditLanguages/Documentation.docc/TreeSitterModel.md +++ b/Sources/CodeEditLanguages/Documentation.docc/TreeSitterModel.md @@ -57,6 +57,7 @@ let query = TreeSitterModel.shared.swiftQuery - ``pythonQuery`` - ``rubyQuery`` - ``rustQuery`` +- ``scalaQuery`` - ``sqlQuery`` - ``swiftQuery`` - ``yamlQuery`` diff --git a/Sources/CodeEditLanguages/Resources/tree-sitter-scala/highlights.scm b/Sources/CodeEditLanguages/Resources/tree-sitter-scala/highlights.scm new file mode 100644 index 0000000..0703ea7 --- /dev/null +++ b/Sources/CodeEditLanguages/Resources/tree-sitter-scala/highlights.scm @@ -0,0 +1,254 @@ +; CREDITS @stumash (stuart.mashaal@gmail.com) + +(class_definition + name: (identifier) @type) + +(enum_definition + name: (identifier) @type) + +(object_definition + name: (identifier) @type) + +(trait_definition + name: (identifier) @type) + +(full_enum_case + name: (identifier) @type) + +(simple_enum_case + name: (identifier) @type) + +;; variables + +(class_parameter + name: (identifier) @parameter) + +(self_type (identifier) @parameter) + +(interpolation (identifier) @none) +(interpolation (block) @none) + +;; types + +(type_definition + name: (type_identifier) @type.definition) + +(type_identifier) @type + +;; val/var definitions/declarations + +(val_definition + pattern: (identifier) @variable) + +(var_definition + pattern: (identifier) @variable) + +(val_declaration + name: (identifier) @variable) + +(var_declaration + name: (identifier) @variable) + +; method definition + +(function_declaration + name: (identifier) @method) + +(function_definition + name: (identifier) @method) + +; imports/exports + +(import_declaration + path: (identifier) @namespace) +((stable_identifier (identifier) @namespace)) + +((import_declaration + path: (identifier) @type) (#lua-match? @type "^[A-Z]")) +((stable_identifier (identifier) @type) (#lua-match? @type "^[A-Z]")) + +(export_declaration + path: (identifier) @namespace) +((stable_identifier (identifier) @namespace)) + +((export_declaration + path: (identifier) @type) (#lua-match? @type "^[A-Z]")) +((stable_identifier (identifier) @type) (#lua-match? @type "^[A-Z]")) + +((namespace_selectors (identifier) @type) (#lua-match? @type "^[A-Z]")) + +; method invocation + +(call_expression + function: (identifier) @function.call) + +(call_expression + function: (operator_identifier) @function.call) + +(call_expression + function: (field_expression + field: (identifier) @method.call)) + +((call_expression + function: (identifier) @constructor) + (#lua-match? @constructor "^[A-Z]")) + +(generic_function + function: (identifier) @function.call) + +(interpolated_string_expression + interpolator: (identifier) @function.call) + +; function definitions + +(function_definition + name: (identifier) @function) + +(parameter + name: (identifier) @parameter) + +(binding + name: (identifier) @parameter) + +; expressions + +(field_expression field: (identifier) @property) +(field_expression value: (identifier) @type + (#lua-match? @type "^[A-Z]")) + +(infix_expression operator: (identifier) @operator) +(infix_expression operator: (operator_identifier) @operator) +(infix_type operator: (operator_identifier) @operator) +(infix_type operator: (operator_identifier) @operator) + +; literals + +(boolean_literal) @boolean +(integer_literal) @number +(floating_point_literal) @float + +[ + (symbol_literal) + (string) + (character_literal) + (interpolated_string_expression) +] @string + +(interpolation "$" @punctuation.special) + +;; keywords + +(opaque_modifier) @type.qualifier +(infix_modifier) @keyword +(transparent_modifier) @type.qualifier +(open_modifier) @type.qualifier + +[ + "case" + "class" + "enum" + "extends" + "derives" + "finally" +;; `forSome` existential types not implemented yet +;; `macro` not implemented yet + "object" + "override" + "package" + "trait" + "type" + "val" + "var" + "with" + "given" + "using" + "end" + "implicit" + "extension" + "with" +] @keyword + +[ + "abstract" + "final" + "lazy" + "sealed" + "private" + "protected" +] @type.qualifier + +(inline_modifier) @storageclass + +(null_literal) @constant.builtin + +(wildcard) @parameter + +(annotation) @attribute + +;; special keywords + +"new" @keyword.operator + +[ + "else" + "if" + "match" + "then" +] @conditional + +[ + "(" + ")" + "[" + "]" + "{" + "}" +] @punctuation.bracket + +[ + "." + "," +] @punctuation.delimiter + +[ + "do" + "for" + "while" + "yield" +] @repeat + +"def" @keyword.function + +[ + "=>" + "<-" + "@" +] @operator + +["import" "export"] @include + +[ + "try" + "catch" + "throw" +] @exception + +"return" @keyword.return + +(comment) @comment @spell + +;; `case` is a conditional keyword in case_block + +(case_block + (case_clause ("case") @conditional)) + +(operator_identifier) @operator + +((identifier) @type (#lua-match? @type "^[A-Z]")) +((identifier) @variable.builtin + (#lua-match? @variable.builtin "^this$")) + +( + (identifier) @function.builtin + (#lua-match? @function.builtin "^super$") +) diff --git a/Sources/CodeEditLanguages/Resources/tree-sitter-scala/locals.scm b/Sources/CodeEditLanguages/Resources/tree-sitter-scala/locals.scm new file mode 100644 index 0000000..8eaa75e --- /dev/null +++ b/Sources/CodeEditLanguages/Resources/tree-sitter-scala/locals.scm @@ -0,0 +1,29 @@ +(template_body) @local.scope +(lambda_expression) @local.scope + + +(function_declaration + name: (identifier) @local.definition) @local.scope + +(function_definition + name: (identifier) @local.definition) + +(parameter + name: (identifier) @local.definition) + +(binding + name: (identifier) @local.definition) + +(val_definition + pattern: (identifier) @local.definition) + +(var_definition + pattern: (identifier) @local.definition) + +(val_declaration + name: (identifier) @local.definition) + +(var_declaration + name: (identifier) @local.definition) + +(identifier) @local.reference diff --git a/Sources/CodeEditLanguages/TreeSitterLanguage.swift b/Sources/CodeEditLanguages/TreeSitterLanguage.swift index 005b341..14eb587 100644 --- a/Sources/CodeEditLanguages/TreeSitterLanguage.swift +++ b/Sources/CodeEditLanguages/TreeSitterLanguage.swift @@ -35,6 +35,7 @@ public enum TreeSitterLanguage: String { case regex case ruby case rust + case scala case sql case swift case tsx diff --git a/Sources/CodeEditLanguages/TreeSitterModel.swift b/Sources/CodeEditLanguages/TreeSitterModel.swift index 4c3955c..bb25a42 100644 --- a/Sources/CodeEditLanguages/TreeSitterModel.swift +++ b/Sources/CodeEditLanguages/TreeSitterModel.swift @@ -72,6 +72,8 @@ public class TreeSitterModel { return rubyQuery case .rust: return rustQuery + case .scala: + return scalaQuery case .sql: return sqlQuery case .swift: @@ -219,6 +221,11 @@ public class TreeSitterModel { return queryFor(.rust) }() + /// Query for `Scala` files. + public private(set) lazy var scalaQuery: Query? = { + return queryFor(.scala) + }() + /// Query for `SQL` files. public private(set) lazy var sqlQuery: Query? = { return queryFor(.sql) diff --git a/Tests/CodeEditLanguagesTests/CodeEditLanguagesTests.swift b/Tests/CodeEditLanguagesTests/CodeEditLanguagesTests.swift index da10255..ade6bda 100644 --- a/Tests/CodeEditLanguagesTests/CodeEditLanguagesTests.swift +++ b/Tests/CodeEditLanguagesTests/CodeEditLanguagesTests.swift @@ -534,7 +534,34 @@ final class CodeEditLanguagesTests: XCTestCase { XCTAssertNotNil(query) XCTAssertNotEqual(query?.patternCount, 0) } + + // MARK: - Scala + + func test_CodeLanguageScala() throws { + let url = URL(fileURLWithPath: "~/path/to/file.scala") + let language = CodeLanguage.detectLanguageFrom(url: url) + + XCTAssertEqual(language.id, .scala) + } + + func test_CodeLanguageScalaScript() throws { + let url = URL(fileURLWithPath: "~/path/to/file.sc") + let language = CodeLanguage.detectLanguageFrom(url: url) + + XCTAssertEqual(language.id, .scala) + } + func test_FetchQueryScala() throws { + var language = CodeLanguage.scala + 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: - SQL func test_CodeLanguageSQL() throws {