diff --git a/CodeLanguages-Container/CodeLanguages-Container.xcodeproj/project.pbxproj b/CodeLanguages-Container/CodeLanguages-Container.xcodeproj/project.pbxproj index 50637c9..8b16a17 100644 --- a/CodeLanguages-Container/CodeLanguages-Container.xcodeproj/project.pbxproj +++ b/CodeLanguages-Container/CodeLanguages-Container.xcodeproj/project.pbxproj @@ -31,6 +31,7 @@ 28B3F05D290C3709000CD04D /* TreeSitterSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 28B3F05C290C3709000CD04D /* TreeSitterSwift */; }; 28B3F063290C372D000CD04D /* TreeSitterZig in Frameworks */ = {isa = PBXBuildFile; productRef = 28B3F062290C372D000CD04D /* TreeSitterZig */; }; 28B9F7AA290DDAC900245748 /* TreeSitterBash in Frameworks */ = {isa = PBXBuildFile; productRef = 28B9F7A9290DDAC900245748 /* TreeSitterBash */; }; + 9D6DA3B8298F1A4600E69066 /* TreeSitterOCaml in Frameworks */ = {isa = PBXBuildFile; productRef = 9D6DA3B7298F1A4600E69066 /* TreeSitterOCaml */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -58,6 +59,7 @@ 28B3F036290C361D000CD04D /* TreeSitterCSS in Frameworks */, 28B3F033290C3608000CD04D /* TreeSitterCSharp in Frameworks */, 28B3F03F290C364D000CD04D /* TreeSitterGoMod in Frameworks */, + 9D6DA3B8298F1A4600E69066 /* TreeSitterOCaml in Frameworks */, 28B3F063290C372D000CD04D /* TreeSitterZig in Frameworks */, 28B3F045290C366E000CD04D /* TreeSitterHTML in Frameworks */, 28B3F05A290C36E5000CD04D /* TreeSitterRust in Frameworks */, @@ -166,6 +168,7 @@ 282E5976298051980064B34A /* TreeSitterYAML */, 2886C787298135540023E016 /* TreeSitterKotlin */, 28171CB729814CD800523F1C /* TreeSitterObjC */, + 9D6DA3B7298F1A4600E69066 /* TreeSitterOCaml */, ); productName = "CodeLanguages-Container"; productReference = 28B3F00C290C207D000CD04D /* CodeLanguages_Container.framework */; @@ -219,6 +222,7 @@ 282E5975298051980064B34A /* XCRemoteSwiftPackageReference "tree-sitter-yaml" */, 2886C786298135540023E016 /* XCRemoteSwiftPackageReference "tree-sitter-kotlin" */, 28171CB629814CD800523F1C /* XCRemoteSwiftPackageReference "tree-sitter-objc" */, + 9D6DA3B6298F1A4500E69066 /* XCRemoteSwiftPackageReference "tree-sitter-ocaml" */, ); productRefGroup = 28B3F00D290C207D000CD04D /* Products */; projectDirPath = ""; @@ -642,6 +646,14 @@ kind = branch; }; }; + 9D6DA3B6298F1A4500E69066 /* XCRemoteSwiftPackageReference "tree-sitter-ocaml" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/cengelbart39/tree-sitter-ocaml.git"; + requirement = { + branch = feature/spm; + kind = branch; + }; + }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ @@ -760,6 +772,11 @@ package = 28B9F7A6290DDAB500245748 /* XCRemoteSwiftPackageReference "tree-sitter-bash" */; productName = TreeSitterBash; }; + 9D6DA3B7298F1A4600E69066 /* TreeSitterOCaml */ = { + isa = XCSwiftPackageProductDependency; + package = 9D6DA3B6298F1A4500E69066 /* XCRemoteSwiftPackageReference "tree-sitter-ocaml" */; + productName = TreeSitterOCaml; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 28B3F003290C207D000CD04D /* Project object */; 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 51553ac..96fd703 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 @@ -15,7 +15,7 @@ "location" : "https://github.com/tree-sitter/tree-sitter-bash.git", "state" : { "branch" : "master", - "revision" : "4488aa41406547e478636a4fcfd24f5bbc3f2f74" + "revision" : "7f9506c34ab6a0f4e3e052b7a49cbeef91f71236" } }, { @@ -42,7 +42,7 @@ "location" : "https://github.com/tree-sitter/tree-sitter-cpp.git", "state" : { "branch" : "master", - "revision" : "3845ff48d6e370616cec189eb43ddce4fd57f4d4" + "revision" : "56cec4c2eb5d6af3d2942e69e35db15ae2433740" } }, { @@ -114,7 +114,7 @@ "location" : "https://github.com/tree-sitter/tree-sitter-java.git", "state" : { "branch" : "master", - "revision" : "09d650def6cdf7f479f4b78f595e9ef5b58ce31e" + "revision" : "dd597f13eb9bab0c1bccc9aec390e8e6ebf9e0a6" } }, { @@ -153,6 +153,15 @@ "revision" : "1b54ef0b5efddddf393b45e173788499cc572048" } }, + { + "identity" : "tree-sitter-ocaml", + "kind" : "remoteSourceControl", + "location" : "https://github.com/cengelbart39/tree-sitter-ocaml.git", + "state" : { + "branch" : "feature/spm", + "revision" : "506d9a4a7709b3cb629e015476a8a640ac3c06ed" + } + }, { "identity" : "tree-sitter-php", "kind" : "remoteSourceControl", @@ -177,7 +186,7 @@ "location" : "https://github.com/tree-sitter/tree-sitter-ruby.git", "state" : { "branch" : "master", - "revision" : "7a1921bcfd90e3a04c1ad011059087aaf0168dd4" + "revision" : "206c7077164372c596ffa8eaadb9435c28941364" } }, { @@ -213,7 +222,7 @@ "location" : "https://github.com/maxxnino/tree-sitter-zig.git", "state" : { "branch" : "main", - "revision" : "d90d38d28ce8cc27bfea8b4e0c75211e9e2398ca" + "revision" : "b0693dd473efd91d6085acd8e0ff9c627d37e077" } } ], diff --git a/CodeLanguages-Container/CodeLanguages-Container/CodeLanguages_Container.h b/CodeLanguages-Container/CodeLanguages-Container/CodeLanguages_Container.h index bb9aa01..99ea2b0 100644 --- a/CodeLanguages-Container/CodeLanguages-Container/CodeLanguages_Container.h +++ b/CodeLanguages-Container/CodeLanguages-Container/CodeLanguages_Container.h @@ -38,6 +38,8 @@ extern TSLanguage *tree_sitter_javascript(); extern TSLanguage *tree_sitter_json(); extern TSLanguage *tree_sitter_kotlin(); extern TSLanguage *tree_sitter_objc(); +extern TSLanguage *tree_sitter_ocaml(); +extern TSLanguage *tree_sitter_ocaml_interface(); 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 8d196d1..65a86cc 100644 Binary files a/CodeLanguagesContainer.xcframework.zip and b/CodeLanguagesContainer.xcframework.zip differ diff --git a/Sources/CodeEditLanguages/CodeLanguage+Definitions.swift b/Sources/CodeEditLanguages/CodeLanguage+Definitions.swift index 57cd1a9..4f0804e 100644 --- a/Sources/CodeEditLanguages/CodeLanguage+Definitions.swift +++ b/Sources/CodeEditLanguages/CodeLanguage+Definitions.swift @@ -28,6 +28,8 @@ public extension CodeLanguage { .jsx, .kotlin, .objc, + .ocaml, + .ocamlInterface, .php, .python, .ruby, @@ -158,6 +160,20 @@ public extension CodeLanguage { extensions: ["m"] ) + /// A language structure for `OCaml` + static let ocaml: CodeLanguage = .init( + id: .ocaml, + tsName: "ocaml", + extensions: ["ml"] + ) + + /// A language structure for `OCaml Interface` + static let ocamlInterface: CodeLanguage = .init( + id: .ocamlInterface, + tsName: "ocaml", + extensions: ["mli"] + ) + /// 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 0294801..df1deb1 100644 --- a/Sources/CodeEditLanguages/CodeLanguage.swift +++ b/Sources/CodeEditLanguages/CodeLanguage.swift @@ -100,6 +100,10 @@ public struct CodeLanguage { return tree_sitter_kotlin() case .objc: return tree_sitter_objc() + case .ocaml: + return tree_sitter_ocaml() + case .ocamlInterface: + return tree_sitter_ocaml_interface() 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 3a8b6b5..014f316 100644 --- a/Sources/CodeEditLanguages/Documentation.docc/CodeLanguage.md +++ b/Sources/CodeEditLanguages/Documentation.docc/CodeLanguage.md @@ -36,6 +36,7 @@ let language = CodeLanguage.detectLanguageFrom(url: fileURL) - JSX - Kotlin - Objective C +- OCaml / OCaml Interface - PHP - Python - Ruby diff --git a/Sources/CodeEditLanguages/Documentation.docc/TreeSitterModel.md b/Sources/CodeEditLanguages/Documentation.docc/TreeSitterModel.md index 2452149..3101056 100644 --- a/Sources/CodeEditLanguages/Documentation.docc/TreeSitterModel.md +++ b/Sources/CodeEditLanguages/Documentation.docc/TreeSitterModel.md @@ -49,6 +49,8 @@ let query = TreeSitterModel.shared.swiftQuery - ``jsxQuery`` - ``kotlinQuery`` - ``objcQuery`` +- ``ocamlQuery`` +- ``ocamlInterfaceQuery`` - ``phpQuery`` - ``pythonQuery`` - ``rubyQuery`` diff --git a/Sources/CodeEditLanguages/Resources/tree-sitter-ocaml/highlights.scm b/Sources/CodeEditLanguages/Resources/tree-sitter-ocaml/highlights.scm new file mode 100644 index 0000000..2ace68f --- /dev/null +++ b/Sources/CodeEditLanguages/Resources/tree-sitter-ocaml/highlights.scm @@ -0,0 +1,147 @@ +; Modules +;-------- + +[(module_name) (module_type_name)] @constructor + +; Types +;------ + +( + (type_constructor) @type.builtin + (#match? @type.builtin "^(int|char|bytes|string|float|bool|unit|exn|array|list|option|int32|int64|nativeint|format6|lazy_t)$") +) + +[(class_name) (class_type_name) (type_constructor)] @type + +[(constructor_name) (tag)] @tag + +; Functions +;---------- + +(let_binding + pattern: (value_name) @function + (parameter)) + +(let_binding + pattern: (value_name) @function + body: [(fun_expression) (function_expression)]) + +(value_specification (value_name) @function) + +(external (value_name) @function) + +(method_name) @function.method + +; Application +;------------ + +( + (value_name) @function.builtin + (#match? @function.builtin "^(raise(_notrace)?|failwith|invalid_arg)$") +) + +(infix_expression + left: (value_path (value_name) @function) + (infix_operator) @operator + (#eq? @operator "@@")) + +(infix_expression + (infix_operator) @operator + right: (value_path (value_name) @function) + (#eq? @operator "|>")) + +(application_expression + function: (value_path (value_name) @function)) + +; Variables +;---------- + +[(value_name) (type_variable)] @variable + +(value_pattern) @variable.parameter + +; Properties +;----------- + +[(label_name) (field_name) (instance_variable_name)] @property + +; Constants +;---------- + +(boolean) @constant + +[(number) (signed_number)] @number + +[(string) (character)] @string + +(quoted_string "{" @string "}" @string) @string + +(escape_sequence) @escape + +(conversion_specification) @string.special + +; Operators +;---------- + +(match_expression (match_operator) @keyword) + +(value_definition [(let_operator) (and_operator)] @keyword) + +[ + (prefix_operator) + (sign_operator) + (infix_operator) + (hash_operator) + (indexing_operator) + (let_operator) + (and_operator) + (match_operator) +] @operator + +(infix_operator ["&" "+" "-" "=" ">" "|" "%"] @operator) +(signed_number ["+" "-"] @operator) + +["*" "#" "::" "<-"] @operator + +; Keywords +;--------- + +[ + "and" "as" "assert" "begin" "class" "constraint" "do" "done" "downto" "else" + "end" "exception" "external" "for" "fun" "function" "functor" "if" "in" + "include" "inherit" "initializer" "lazy" "let" "match" "method" "module" + "mutable" "new" "nonrec" "object" "of" "open" "private" "rec" "sig" "struct" + "then" "to" "try" "type" "val" "virtual" "when" "while" "with" +] @keyword + +; Punctuation +;------------ + +(attribute ["[@" "]"] @punctuation.special) +(item_attribute ["[@@" "]"] @punctuation.special) +(floating_attribute ["[@@@" "]"] @punctuation.special) +(extension ["[%" "]"] @punctuation.special) +(item_extension ["[%%" "]"] @punctuation.special) +(quoted_extension ["{%" "}"] @punctuation.special) +(quoted_item_extension ["{%%" "}"] @punctuation.special) + +"%" @punctuation.special + +["(" ")" "[" "]" "{" "}" "[|" "|]" "[<" "[>"] @punctuation.bracket + +(object_type ["<" ">"] @punctuation.bracket) + +[ + "," "." ";" ":" "=" "|" "~" "?" "+" "-" "!" ">" "&" + "->" ";;" ":>" "+=" ":=" ".." +] @punctuation.delimiter + +; Attributes +;----------- + +(attribute_id) @attribute + +; Comments +;--------- + +[(comment) (line_number_directive) (directive) (shebang)] @comment diff --git a/Sources/CodeEditLanguages/Resources/tree-sitter-ocaml/locals.scm b/Sources/CodeEditLanguages/Resources/tree-sitter-ocaml/locals.scm new file mode 100644 index 0000000..8f3f3fd --- /dev/null +++ b/Sources/CodeEditLanguages/Resources/tree-sitter-ocaml/locals.scm @@ -0,0 +1,24 @@ +; Scopes +;------- + +[ + (let_binding) + (class_binding) + (class_function) + (method_definition) + (fun_expression) + (object_expression) + (for_expression) + (match_case) + (attribute_payload) +] @local.scope + +; Definitions +;------------ + +(value_pattern) @local.definition + +; References +;----------- + +(value_path . (value_name) @local.reference) diff --git a/Sources/CodeEditLanguages/Resources/tree-sitter-ocaml/tags.scm b/Sources/CodeEditLanguages/Resources/tree-sitter-ocaml/tags.scm new file mode 100644 index 0000000..0528a48 --- /dev/null +++ b/Sources/CodeEditLanguages/Resources/tree-sitter-ocaml/tags.scm @@ -0,0 +1,116 @@ +; Modules +;-------- + +( + (comment)? @doc . + (module_definition (module_binding (module_name) @name) @definition.module) + (#strip! @doc "^\\(\\*\\*?\\s*|\\s\\*\\)$") +) + +(module_path (module_name) @name) @reference.module + +; Modules types +;-------------- + +( + (comment)? @doc . + (module_type_definition (module_type_name) @name) @definition.interface + (#strip! @doc "^\\(\\*\\*?\\s*|\\s\\*\\)$") +) + +(module_type_path (module_type_name) @name) @reference.implementation + +; Functions +;---------- + +( + (comment)? @doc . + (value_definition + [ + (let_binding + pattern: (value_name) @name + (parameter)) + (let_binding + pattern: (value_name) @name + body: [(fun_expression) (function_expression)]) + ] @definition.function + ) + (#strip! @doc "^\\(\\*\\*?\\s*|\\s\\*\\)$") +) + +( + (comment)? @doc . + (external (value_name) @name) @definition.function + (#strip! @doc "^\\(\\*\\*?\\s*|\\s\\*\\)$") +) + +(application_expression + function: (value_path (value_name) @name)) @reference.call + +(infix_expression + left: (value_path (value_name) @name) + (infix_operator) @reference.call + (#eq? @reference.call "@@")) + +(infix_expression + (infix_operator) @reference.call + right: (value_path (value_name) @name) + (#eq? @reference.call "|>")) + +; Operator +;--------- + +( + (comment)? @doc . + (value_definition + (let_binding + pattern: (parenthesized_operator [ + (prefix_operator) + (infix_operator) + (hash_operator) + (indexing_operator) + (let_operator) + (and_operator) + (match_operator) + ] @name)) @definition.function) + (#strip! @doc "^\\(\\*\\*?\\s*|\\s\\*\\)$") +) + +[ + (prefix_operator) + (sign_operator) + (infix_operator) + (hash_operator) + (indexing_operator) + (let_operator) + (and_operator) + (match_operator) +] @name @reference.call + +; Classes +;-------- + +( + (comment)? @doc . + [ + (class_definition (class_binding (class_name) @name) @definition.class) + (class_type_definition (class_type_binding (class_type_name) @name) @definition.class) + ] + (#strip! @doc "^\\(\\*\\*?\\s*|\\s\\*\\)$") +) + +[ + (class_path (class_name) @name) + (class_type_path (class_type_name) @name) +] @reference.class + +; Methods +;-------- + +( + (comment)? @doc . + (method_definition (method_name) @name) @definition.method + (#strip! @doc "^\\(\\*\\*?\\s*|\\s\\*\\)$") +) + +(method_invocation (method_name) @name) @reference.call diff --git a/Sources/CodeEditLanguages/TreeSitterLanguage.swift b/Sources/CodeEditLanguages/TreeSitterLanguage.swift index b87818b..f6e55d1 100644 --- a/Sources/CodeEditLanguages/TreeSitterLanguage.swift +++ b/Sources/CodeEditLanguages/TreeSitterLanguage.swift @@ -26,6 +26,8 @@ public enum TreeSitterLanguage: String { case jsx case kotlin case objc + case ocaml + case ocamlInterface case php case python case ruby diff --git a/Sources/CodeEditLanguages/TreeSitterModel.swift b/Sources/CodeEditLanguages/TreeSitterModel.swift index faac3df..82ad3ac 100644 --- a/Sources/CodeEditLanguages/TreeSitterModel.swift +++ b/Sources/CodeEditLanguages/TreeSitterModel.swift @@ -54,6 +54,10 @@ public class TreeSitterModel { return kotlinQuery case .objc: return objcQuery + case .ocaml: + return ocamlQuery + case .ocamlInterface: + return ocamlInterfaceQuery case .php: return phpQuery case .python: @@ -158,6 +162,16 @@ public class TreeSitterModel { return queryFor(.objc) }() + /// Query for `OCaml` files. + public private(set) lazy var ocamlQuery: Query? = { + return queryFor(.ocaml) + }() + + /// Query for `OCaml Interface` files. + public private(set) lazy var ocamlInterfaceQuery: Query? = { + return queryFor(.ocamlInterface) + }() + /// 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 a60c016..67706b0 100644 --- a/Tests/CodeEditLanguagesTests/CodeEditLanguagesTests.swift +++ b/Tests/CodeEditLanguagesTests/CodeEditLanguagesTests.swift @@ -392,7 +392,43 @@ final class CodeEditLanguagesTests: XCTestCase { XCTAssertNotNil(query) XCTAssertNotEqual(query?.patternCount, 0) } + +// MARK: - OCaml + func test_CodeLanguageOCaml() throws { + let url = URL(fileURLWithPath: "~/path/to/file.ml") + let language = CodeLanguage.detectLanguageFrom(url: url) + + XCTAssertEqual(language.id, .ocaml) + } + func test_FetchQueryOCaml() throws { + var language = CodeLanguage.ocaml + 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: - OCaml Interface + func test_CodeLanguageOCamlInterface() throws { + let url = URL(fileURLWithPath: "~/path/to/file.mli") + let language = CodeLanguage.detectLanguageFrom(url: url) + + XCTAssertEqual(language.id, .ocamlInterface) + } + + func test_FetchQueryOCamlInterface() throws { + var language = CodeLanguage.ocamlInterface + 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 {