diff --git a/Package.swift b/Package.swift index 215980b..b7c58a5 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version: 5.9 +// swift-tools-version: 6.1 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription @@ -16,6 +16,49 @@ let package = Package( .library(name: "MarkdownView", targets: ["MarkdownView"]), .library(name: "MarkdownParser", targets: ["MarkdownParser"]), ], + traits: [ + // By default every language grammar is enabled, so existing consumers + // see no change. Opt into a subset by disabling defaults and listing + // only the languages you need, e.g. `traits: ["Swift", "JSON"]`. + .default(enabledTraits: [ + "Python", + "JavaScript", + "TypeScript", + "Go", + "Rust", + "Swift", + "C", + "CPP", + "Java", + "Ruby", + "Bash", + "JSON", + "HTML", + "CSS", + "CSharp", + "Kotlin", + "SQL", + "YAML", + ]), + .trait(name: "Python", description: "Python syntax highlighting"), + .trait(name: "JavaScript", description: "JavaScript syntax highlighting"), + .trait(name: "TypeScript", description: "TypeScript and TSX syntax highlighting"), + .trait(name: "Go", description: "Go syntax highlighting"), + .trait(name: "Rust", description: "Rust syntax highlighting"), + .trait(name: "Swift", description: "Swift syntax highlighting"), + .trait(name: "C", description: "C syntax highlighting"), + .trait(name: "CPP", description: "C++ syntax highlighting"), + .trait(name: "Java", description: "Java syntax highlighting"), + .trait(name: "Ruby", description: "Ruby syntax highlighting"), + .trait(name: "Bash", description: "Bash/shell syntax highlighting"), + .trait(name: "JSON", description: "JSON syntax highlighting"), + .trait(name: "HTML", description: "HTML syntax highlighting"), + .trait(name: "CSS", description: "CSS syntax highlighting"), + .trait(name: "CSharp", description: "C# syntax highlighting"), + .trait(name: "Kotlin", description: "Kotlin syntax highlighting"), + .trait(name: "SQL", description: "SQL syntax highlighting"), + .trait(name: "YAML", description: "YAML syntax highlighting"), + ], dependencies: [ .package(url: "https://github.com/mgriebling/SwiftMath", from: "1.7.3"), .package(url: "https://github.com/tree-sitter/swift-tree-sitter", from: "0.9.0"), @@ -51,24 +94,42 @@ let package = Package( "MarkdownParser", "SwiftMath", .product(name: "SwiftTreeSitter", package: "swift-tree-sitter"), - .product(name: "TreeSitterPython", package: "tree-sitter-python"), - .product(name: "TreeSitterJavaScript", package: "tree-sitter-javascript"), - .product(name: "TreeSitterTypeScript", package: "tree-sitter-typescript"), - .product(name: "TreeSitterGo", package: "tree-sitter-go"), - .product(name: "TreeSitterRust", package: "tree-sitter-rust"), - .product(name: "TreeSitterSwift", package: "tree-sitter-swift"), - .product(name: "TreeSitterC", package: "tree-sitter-c"), - .product(name: "TreeSitterCPP", package: "tree-sitter-cpp"), - .product(name: "TreeSitterJava", package: "tree-sitter-java"), - .product(name: "TreeSitterRuby", package: "tree-sitter-ruby"), - .product(name: "TreeSitterBash", package: "tree-sitter-bash"), - .product(name: "TreeSitterJSON", package: "tree-sitter-json"), - .product(name: "TreeSitterHTML", package: "tree-sitter-html"), - .product(name: "TreeSitterCSS", package: "tree-sitter-css"), - .product(name: "TreeSitterCSharp", package: "tree-sitter-c-sharp"), - .product(name: "TreeSitterKotlin", package: "tree-sitter-kotlin"), - .product(name: "TreeSitterSql", package: "tree-sitter-sql"), - .product(name: "TreeSitterYAML", package: "tree-sitter-yaml"), + .product(name: "TreeSitterPython", package: "tree-sitter-python", + condition: .when(traits: ["Python"])), + .product(name: "TreeSitterJavaScript", package: "tree-sitter-javascript", + condition: .when(traits: ["JavaScript"])), + .product(name: "TreeSitterTypeScript", package: "tree-sitter-typescript", + condition: .when(traits: ["TypeScript"])), + .product(name: "TreeSitterGo", package: "tree-sitter-go", + condition: .when(traits: ["Go"])), + .product(name: "TreeSitterRust", package: "tree-sitter-rust", + condition: .when(traits: ["Rust"])), + .product(name: "TreeSitterSwift", package: "tree-sitter-swift", + condition: .when(traits: ["Swift"])), + .product(name: "TreeSitterC", package: "tree-sitter-c", + condition: .when(traits: ["C"])), + .product(name: "TreeSitterCPP", package: "tree-sitter-cpp", + condition: .when(traits: ["CPP"])), + .product(name: "TreeSitterJava", package: "tree-sitter-java", + condition: .when(traits: ["Java"])), + .product(name: "TreeSitterRuby", package: "tree-sitter-ruby", + condition: .when(traits: ["Ruby"])), + .product(name: "TreeSitterBash", package: "tree-sitter-bash", + condition: .when(traits: ["Bash"])), + .product(name: "TreeSitterJSON", package: "tree-sitter-json", + condition: .when(traits: ["JSON"])), + .product(name: "TreeSitterHTML", package: "tree-sitter-html", + condition: .when(traits: ["HTML"])), + .product(name: "TreeSitterCSS", package: "tree-sitter-css", + condition: .when(traits: ["CSS"])), + .product(name: "TreeSitterCSharp", package: "tree-sitter-c-sharp", + condition: .when(traits: ["CSharp"])), + .product(name: "TreeSitterKotlin", package: "tree-sitter-kotlin", + condition: .when(traits: ["Kotlin"])), + .product(name: "TreeSitterSql", package: "tree-sitter-sql", + condition: .when(traits: ["SQL"])), + .product(name: "TreeSitterYAML", package: "tree-sitter-yaml", + condition: .when(traits: ["YAML"])), ], resources: [.process("Resources")] ), @@ -83,5 +144,9 @@ let package = Package( "MarkdownParser", ] ), - ] + ], + // Preserve the Swift 5 language mode. Bumping swift-tools-version to 6.1 + // (required for traits) would otherwise default the package to the Swift 6 + // language mode and turn pre-existing concurrency warnings into errors. + swiftLanguageModes: [.v5] ) diff --git a/README.md b/README.md index c006248..3ce2307 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ The plain-text streaming fast path applies to safe token appends that do not int ## Requirements - iOS 16+ / macOS 13+ / visionOS 1+ -- Swift 5.9+ +- Swift 6.1+ (Swift tools 6.1, required for package traits) ## Installation @@ -56,6 +56,24 @@ dependencies: [ Then add `"MarkdownView"` as a dependency of your target. +### Selecting languages with package traits + +Syntax highlighting ships grammars for many languages, each behind a [package trait](https://docs.swift.org/swiftpm/documentation/packagemanagerdocs/packagetraits/). By default every language is enabled, so no configuration is needed. + +To keep only the languages you use — pruning the rest from resolution and build — disable the defaults and list the traits you want: + +```swift +dependencies: [ + .package( + url: "https://github.com/HumanInterfaceDesign/MarkdownView", + branch: "main", + traits: ["Swift", "JSON"] + ), +] +``` + +Available traits: `Python`, `JavaScript`, `TypeScript` (includes TSX), `Go`, `Rust`, `Swift`, `C`, `CPP`, `Java`, `Ruby`, `Bash`, `JSON`, `HTML`, `CSS`, `CSharp`, `Kotlin`, `SQL`, `YAML`. A language whose trait is disabled simply renders as plain text. Traits are a SwiftPM feature; adding the package through Xcode's UI always uses the default (all-languages) set. + ## Usage Xcode 2026-03-02 09 24 19 diff --git a/Sources/MarkdownView/Components/CodeView/CodeHighlighter.swift b/Sources/MarkdownView/Components/CodeView/CodeHighlighter.swift index 2ac2a70..148f4df 100644 --- a/Sources/MarkdownView/Components/CodeView/CodeHighlighter.swift +++ b/Sources/MarkdownView/Components/CodeView/CodeHighlighter.swift @@ -5,25 +5,61 @@ import Foundation import SwiftTreeSitter -import TreeSitterPython -import TreeSitterJavaScript -import TreeSitterTypeScript -import TreeSitterTSX -import TreeSitterGo -import TreeSitterRust -import TreeSitterSwift -import TreeSitterC -import TreeSitterCPP -import TreeSitterJava -import TreeSitterRuby -import TreeSitterBash -import TreeSitterJSON -import TreeSitterHTML -import TreeSitterCSS -import TreeSitterCSharp -import TreeSitterKotlin -import TreeSitterSql -import TreeSitterYAML +#if Python + import TreeSitterPython +#endif +#if JavaScript + import TreeSitterJavaScript +#endif +#if TypeScript + import TreeSitterTypeScript + import TreeSitterTSX +#endif +#if Go + import TreeSitterGo +#endif +#if Rust + import TreeSitterRust +#endif +#if Swift + import TreeSitterSwift +#endif +#if C + import TreeSitterC +#endif +#if CPP + import TreeSitterCPP +#endif +#if Java + import TreeSitterJava +#endif +#if Ruby + import TreeSitterRuby +#endif +#if Bash + import TreeSitterBash +#endif +#if JSON + import TreeSitterJSON +#endif +#if HTML + import TreeSitterHTML +#endif +#if CSS + import TreeSitterCSS +#endif +#if CSharp + import TreeSitterCSharp +#endif +#if Kotlin + import TreeSitterKotlin +#endif +#if SQL + import TreeSitterSql +#endif +#if YAML + import TreeSitterYAML +#endif #if canImport(UIKit) import UIKit @@ -149,69 +185,105 @@ public final class CodeHighlighter { } } - register(["swift"]) { - try makeConfig(tree_sitter_swift(), name: "Swift") - } - register(["python", "py", "python3"]) { - try makeConfig(tree_sitter_python(), name: "Python") - } - register(["javascript", "js", "jsx"]) { - try makeConfig(tree_sitter_javascript(), name: "JavaScript") - } - register(["typescript", "ts"]) { - try makeConfig(tree_sitter_typescript(), name: "TypeScript", - bundleName: "TreeSitterTypeScript_TreeSitterTypeScript") - } - register(["tsx"]) { - try makeConfig(tree_sitter_tsx(), name: "TSX", - bundleName: "TreeSitterTypeScript_TreeSitterTSX") - } - register(["go", "golang"]) { - try makeConfig(tree_sitter_go(), name: "Go") - } - register(["rust", "rs"]) { - try makeConfig(tree_sitter_rust(), name: "Rust") - } - register(["c", "h"]) { - try makeConfig(tree_sitter_c(), name: "C") - } - register(["cpp", "c++", "cc", "cxx", "hpp"]) { - try makeConfig(tree_sitter_cpp(), name: "CPP") - } - register(["java"]) { - try makeConfig(tree_sitter_java(), name: "Java") - } - register(["ruby", "rb"]) { - try makeConfig(tree_sitter_ruby(), name: "Ruby") - } - register(["bash", "sh", "shell", "zsh"]) { - try makeConfig(tree_sitter_bash(), name: "Bash") - } - register(["json", "jsonc"]) { - try makeConfig(tree_sitter_json(), name: "JSON") - } - register(["html", "htm"]) { - try makeConfig(tree_sitter_html(), name: "HTML") - } - register(["css"]) { - try makeConfig(tree_sitter_css(), name: "CSS") - } - register(["csharp", "c#", "cs"]) { - try makeConfig(tree_sitter_c_sharp(), name: "CSharp", - bundleName: "TreeSitterCSharp_TreeSitterCSharp") - } - register(["kotlin", "kt", "kts"]) { - try makeConfig(tree_sitter_kotlin(), name: "Kotlin", - bundleName: "TreeSitterKotlin_TreeSitterKotlin") - } - register(["sql"]) { - try makeConfig(tree_sitter_sql(), name: "SQL", - bundleName: "TreeSitterSql_TreeSitterSql") - } - register(["yaml", "yml"]) { - try makeConfig(tree_sitter_yaml(), name: "YAML", - bundleName: "TreeSitterYAML_TreeSitterYAML") - } + #if Swift + register(["swift"]) { + try makeConfig(tree_sitter_swift(), name: "Swift") + } + #endif + #if Python + register(["python", "py", "python3"]) { + try makeConfig(tree_sitter_python(), name: "Python") + } + #endif + #if JavaScript + register(["javascript", "js", "jsx"]) { + try makeConfig(tree_sitter_javascript(), name: "JavaScript") + } + #endif + #if TypeScript + register(["typescript", "ts"]) { + try makeConfig(tree_sitter_typescript(), name: "TypeScript", + bundleName: "TreeSitterTypeScript_TreeSitterTypeScript") + } + register(["tsx"]) { + try makeConfig(tree_sitter_tsx(), name: "TSX", + bundleName: "TreeSitterTypeScript_TreeSitterTSX") + } + #endif + #if Go + register(["go", "golang"]) { + try makeConfig(tree_sitter_go(), name: "Go") + } + #endif + #if Rust + register(["rust", "rs"]) { + try makeConfig(tree_sitter_rust(), name: "Rust") + } + #endif + #if C + register(["c", "h"]) { + try makeConfig(tree_sitter_c(), name: "C") + } + #endif + #if CPP + register(["cpp", "c++", "cc", "cxx", "hpp"]) { + try makeConfig(tree_sitter_cpp(), name: "CPP") + } + #endif + #if Java + register(["java"]) { + try makeConfig(tree_sitter_java(), name: "Java") + } + #endif + #if Ruby + register(["ruby", "rb"]) { + try makeConfig(tree_sitter_ruby(), name: "Ruby") + } + #endif + #if Bash + register(["bash", "sh", "shell", "zsh"]) { + try makeConfig(tree_sitter_bash(), name: "Bash") + } + #endif + #if JSON + register(["json", "jsonc"]) { + try makeConfig(tree_sitter_json(), name: "JSON") + } + #endif + #if HTML + register(["html", "htm"]) { + try makeConfig(tree_sitter_html(), name: "HTML") + } + #endif + #if CSS + register(["css"]) { + try makeConfig(tree_sitter_css(), name: "CSS") + } + #endif + #if CSharp + register(["csharp", "c#", "cs"]) { + try makeConfig(tree_sitter_c_sharp(), name: "CSharp", + bundleName: "TreeSitterCSharp_TreeSitterCSharp") + } + #endif + #if Kotlin + register(["kotlin", "kt", "kts"]) { + try makeConfig(tree_sitter_kotlin(), name: "Kotlin", + bundleName: "TreeSitterKotlin_TreeSitterKotlin") + } + #endif + #if SQL + register(["sql"]) { + try makeConfig(tree_sitter_sql(), name: "SQL", + bundleName: "TreeSitterSql_TreeSitterSql") + } + #endif + #if YAML + register(["yaml", "yml"]) { + try makeConfig(tree_sitter_yaml(), name: "YAML", + bundleName: "TreeSitterYAML_TreeSitterYAML") + } + #endif return factories }()