diff --git a/CodeLanguages-Container/CodeLanguages-Container.xcodeproj/project.pbxproj b/CodeLanguages-Container/CodeLanguages-Container.xcodeproj/project.pbxproj index 69e42b3..3c77922 100644 --- a/CodeLanguages-Container/CodeLanguages-Container.xcodeproj/project.pbxproj +++ b/CodeLanguages-Container/CodeLanguages-Container.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 2846B262296BA1CF005F60B6 /* TreeSitterDockerfile in Frameworks */ = {isa = PBXBuildFile; productRef = 2846B261296BA1CF005F60B6 /* TreeSitterDockerfile */; }; 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 */; }; @@ -43,6 +44,7 @@ files = ( 28B3F051290C36B1000CD04D /* TreeSitterPHP in Frameworks */, 28B3F042290C365C000CD04D /* TreeSitterHaskell in Frameworks */, + 2846B262296BA1CF005F60B6 /* TreeSitterDockerfile in Frameworks */, 28B3F039290C362C000CD04D /* TreeSitterElixir in Frameworks */, 28B3F02D290C35D9000CD04D /* TreeSitterC in Frameworks */, 28B3F04B290C368B000CD04D /* TreeSitterJS in Frameworks */, @@ -157,6 +159,7 @@ 28B3F05F290C3720000CD04D /* TreeSitterYAML */, 28B3F062290C372D000CD04D /* TreeSitterZig */, 28B9F7A9290DDAC900245748 /* TreeSitterBash */, + 2846B261296BA1CF005F60B6 /* TreeSitterDockerfile */, ); productName = "CodeLanguages-Container"; productReference = 28B3F00C290C207D000CD04D /* CodeLanguages_Container.framework */; @@ -207,6 +210,7 @@ 28B3F05E290C3720000CD04D /* XCRemoteSwiftPackageReference "tree-sitter-yaml" */, 28B3F061290C372D000CD04D /* XCRemoteSwiftPackageReference "tree-sitter-zig" */, 28B9F7A6290DDAB500245748 /* XCRemoteSwiftPackageReference "tree-sitter-bash" */, + 2846B260296BA1CF005F60B6 /* XCRemoteSwiftPackageReference "tree-sitter-dockerfile" */, ); productRefGroup = 28B3F00D290C207D000CD04D /* Products */; projectDirPath = ""; @@ -446,6 +450,14 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ + 2846B260296BA1CF005F60B6 /* XCRemoteSwiftPackageReference "tree-sitter-dockerfile" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/camdencheek/tree-sitter-dockerfile.git"; + requirement = { + branch = main; + kind = branch; + }; + }; 28B3F02B290C35D9000CD04D /* XCRemoteSwiftPackageReference "tree-sitter-c" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/tree-sitter/tree-sitter-c.git"; @@ -609,6 +621,11 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ + 2846B261296BA1CF005F60B6 /* TreeSitterDockerfile */ = { + isa = XCSwiftPackageProductDependency; + package = 2846B260296BA1CF005F60B6 /* XCRemoteSwiftPackageReference "tree-sitter-dockerfile" */; + productName = TreeSitterDockerfile; + }; 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 764a476..54f7c89 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 @@ -33,7 +33,7 @@ "location" : "https://github.com/tree-sitter/tree-sitter-c-sharp.git", "state" : { "branch" : "master", - "revision" : "1bd772f69b0db577122533514a239b184650adf2" + "revision" : "f076a8efe30a0b8c249eeb61383f6d914376114c" } }, { @@ -42,7 +42,7 @@ "location" : "https://github.com/tree-sitter/tree-sitter-cpp.git", "state" : { "branch" : "master", - "revision" : "5ead1e26c6ab71919db0f1880c46a278a93bc5ea" + "revision" : "5b7e264bc6354bb6f654cd01b24ac0289f889d4a" } }, { @@ -54,6 +54,15 @@ "revision" : "10d5f9247b180f0eaf92bbb4300a07d0549718f6" } }, + { + "identity" : "tree-sitter-dockerfile", + "kind" : "remoteSourceControl", + "location" : "https://github.com/camdencheek/tree-sitter-dockerfile.git", + "state" : { + "branch" : "main", + "revision" : "09e316dba307b869831e9399b11a83bbf0f2a24b" + } + }, { "identity" : "tree-sitter-elixir", "kind" : "remoteSourceControl", diff --git a/CodeLanguages-Container/CodeLanguages-Container/CodeLanguages_Container.h b/CodeLanguages-Container/CodeLanguages-Container/CodeLanguages_Container.h index ca77d52..f5bf87d 100644 --- a/CodeLanguages-Container/CodeLanguages-Container/CodeLanguages_Container.h +++ b/CodeLanguages-Container/CodeLanguages-Container/CodeLanguages_Container.h @@ -27,6 +27,7 @@ extern TSLanguage *tree_sitter_c(); extern TSLanguage *tree_sitter_cpp(); extern TSLanguage *tree_sitter_c_sharp(); extern TSLanguage *tree_sitter_css(); +extern TSLanguage *tree_sitter_dockerfile(); extern TSLanguage *tree_sitter_elixir(); extern TSLanguage *tree_sitter_go(); extern TSLanguage *tree_sitter_gomod(); diff --git a/CodeLanguagesContainer.xcframework.zip b/CodeLanguagesContainer.xcframework.zip index 440b450..a09f130 100644 Binary files a/CodeLanguagesContainer.xcframework.zip and b/CodeLanguagesContainer.xcframework.zip differ diff --git a/README.md b/README.md index 62620b7..ac126e6 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ In order to add support for additional languages we have a complete guide on how | [C++](https://github.com/tree-sitter/tree-sitter-cpp) | ✅ | ✅ | | [C#](https://github.com/tree-sitter/tree-sitter-c-sharp) | ✅ | ✅ | | [CSS](https://github.com/lukepistrol/tree-sitter-css) | ✅ | ✅ | +| [Dockerfile](https://github.com/camdencheek/tree-sitter-dockerfile) | ✅ | ✅ | | [Elixir](https://github.com/elixir-lang/tree-sitter-elixir) | ✅ | ✅ | | [ERB, EJS](https://github.com/tree-sitter/tree-sitter-embedded-template) | | | | [Go](https://github.com/tree-sitter/tree-sitter-go) | ✅ | ✅ | diff --git a/Sources/CodeEditLanguages/CodeLanguage.swift b/Sources/CodeEditLanguages/CodeLanguage.swift index a86a06c..0ca4008 100644 --- a/Sources/CodeEditLanguages/CodeLanguage.swift +++ b/Sources/CodeEditLanguages/CodeLanguage.swift @@ -33,6 +33,9 @@ public struct CodeLanguage { public let tsName: String /// A set of file extensions for the language + /// + /// In special cases this can also be a file name + /// (e.g `Dockerfile`, `Makefile`) public let extensions: Set /// The query URL of a language this language inherits from. (e.g.: C for C++) @@ -73,6 +76,8 @@ public struct CodeLanguage { return tree_sitter_c_sharp() case .css: return tree_sitter_css() + case .dockerfile: + return tree_sitter_dockerfile() case .elixir: return tree_sitter_elixir() case .go: @@ -120,7 +125,7 @@ public extension CodeLanguage { /// - Returns: A language structure static func detectLanguageFrom(url: URL) -> CodeLanguage { let fileExtension = url.pathExtension.lowercased() - let fileName = url.pathComponents.last?.lowercased() + let fileName = url.pathComponents.last // should not be lowercase since it has to match e.g. `Dockerfile` // This is to handle special file types without an extension (e.g., Makefile, Dockerfile) let fileNameOrExtension = fileExtension.isEmpty ? (fileName != nil ? fileName! : "") : fileExtension if let lang = allLanguages.first(where: { lang in lang.extensions.contains(fileNameOrExtension)}) { @@ -137,6 +142,7 @@ public extension CodeLanguage { .cpp, .cSharp, .css, + .dockerfile, .elixir, .go, .goMod, @@ -173,6 +179,9 @@ public extension CodeLanguage { /// A language structure for `CSS` static let css: CodeLanguage = .init(id: .css, tsName: "css", extensions: ["css"]) + /// A language structure for `Dockerfile` + static let dockerfile: CodeLanguage = .init(id: .dockerfile, tsName: "dockerfile", extensions: ["Dockerfile"]) + /// A language structure for `Elixir` static let elixir: CodeLanguage = .init(id: .elixir, tsName: "elixir", extensions: ["ex", "exs"]) diff --git a/Sources/CodeEditLanguages/Documentation.docc/CodeLanguage.md b/Sources/CodeEditLanguages/Documentation.docc/CodeLanguage.md index 493e678..3cc6a84 100644 --- a/Sources/CodeEditLanguages/Documentation.docc/CodeLanguage.md +++ b/Sources/CodeEditLanguages/Documentation.docc/CodeLanguage.md @@ -24,6 +24,7 @@ let language = CodeLanguage.detectLanguageFrom(url: fileURL) - C++ - C# - CSS +- Dockerfile - Elixir - Go - Go Mod @@ -67,6 +68,7 @@ let language = CodeLanguage.detectLanguageFrom(url: fileURL) - ``cpp`` - ``cSharp`` - ``css`` +- ``dockerfile`` - ``elixir`` - ``go`` - ``goMod`` diff --git a/Sources/CodeEditLanguages/Documentation.docc/TreeSitterModel.md b/Sources/CodeEditLanguages/Documentation.docc/TreeSitterModel.md index fd18369..54a43a9 100644 --- a/Sources/CodeEditLanguages/Documentation.docc/TreeSitterModel.md +++ b/Sources/CodeEditLanguages/Documentation.docc/TreeSitterModel.md @@ -37,6 +37,7 @@ let query = TreeSitterModel.shared.swiftQuery - ``cppQuery`` - ``cSharpQuery`` - ``cssQuery`` +- ``dockerfileQuery`` - ``elixirQuery`` - ``goQuery`` - ``goModQuery`` diff --git a/Sources/CodeEditLanguages/Resources/tree-sitter-cpp/injections.scm b/Sources/CodeEditLanguages/Resources/tree-sitter-cpp/injections.scm new file mode 100644 index 0000000..6850c95 --- /dev/null +++ b/Sources/CodeEditLanguages/Resources/tree-sitter-cpp/injections.scm @@ -0,0 +1,3 @@ +(raw_string_literal + delimiter: (raw_string_delimiter) @injection.language + (raw_string_content) @injection.content) diff --git a/Sources/CodeEditLanguages/Resources/tree-sitter-dockerfile/highlights.scm b/Sources/CodeEditLanguages/Resources/tree-sitter-dockerfile/highlights.scm new file mode 100644 index 0000000..5a945fb --- /dev/null +++ b/Sources/CodeEditLanguages/Resources/tree-sitter-dockerfile/highlights.scm @@ -0,0 +1,51 @@ +[ + "FROM" + "AS" + "RUN" + "CMD" + "LABEL" + "EXPOSE" + "ENV" + "ADD" + "COPY" + "ENTRYPOINT" + "VOLUME" + "USER" + "WORKDIR" + "ARG" + "ONBUILD" + "STOPSIGNAL" + "HEALTHCHECK" + "SHELL" + "MAINTAINER" + "CROSS_BUILD" +] @keyword + +[ + ":" + "@" +] @operator + +(comment) @comment + + +(image_spec + (image_tag + ":" @punctuation.special) + (image_digest + "@" @punctuation.special)) + +(double_quoted_string) @string + +(expansion + [ + "$" + "{" + "}" + ] @punctuation.special +) @none + +((variable) @constant + (#match? @constant "^[A-Z][A-Z_0-9]*$")) + + diff --git a/Sources/CodeEditLanguages/TreeSitterLanguage.swift b/Sources/CodeEditLanguages/TreeSitterLanguage.swift index cc36730..137cd02 100644 --- a/Sources/CodeEditLanguages/TreeSitterLanguage.swift +++ b/Sources/CodeEditLanguages/TreeSitterLanguage.swift @@ -14,6 +14,7 @@ public enum TreeSitterLanguage: String { case cpp case cSharp case css + case dockerfile case elixir case go case goMod diff --git a/Sources/CodeEditLanguages/TreeSitterModel.swift b/Sources/CodeEditLanguages/TreeSitterModel.swift index 8cecbf6..3f7045f 100644 --- a/Sources/CodeEditLanguages/TreeSitterModel.swift +++ b/Sources/CodeEditLanguages/TreeSitterModel.swift @@ -29,6 +29,8 @@ public class TreeSitterModel { return cSharpQuery case .css: return cssQuery + case .dockerfile: + return dockerfileQuery case .elixir: return elixirQuery case .go: @@ -91,6 +93,11 @@ public class TreeSitterModel { return queryFor(.css) }() + /// Query for `Dockerfile` files. + public private(set) lazy var dockerfileQuery: Query? = { + return queryFor(.dockerfile) + }() + /// Query for `Elixir` files. public private(set) lazy var elixirQuery: Query? = { return queryFor(.elixir) diff --git a/Tests/CodeEditLanguagesTests/CodeEditLanguagesTests.swift b/Tests/CodeEditLanguagesTests/CodeEditLanguagesTests.swift index 6c55b94..c1c3140 100644 --- a/Tests/CodeEditLanguagesTests/CodeEditLanguagesTests.swift +++ b/Tests/CodeEditLanguagesTests/CodeEditLanguagesTests.swift @@ -130,6 +130,25 @@ final class CodeEditLanguagesTests: XCTestCase { XCTAssertNotEqual(query?.patternCount, 0) } +// MARK: - Dockerfile + + func test_CodeLanguageDockerfile() throws { + let url = URL(fileURLWithPath: "~/path/to/Dockerfile") + let language = CodeLanguage.detectLanguageFrom(url: url) + + XCTAssertEqual(language.id, .dockerfile) + } + + func test_FetchQueryDockerfile() throws { + var language = CodeLanguage.dockerfile + 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: - Elixir func test_CodeLanguageElixir() throws {