SwiftTreeSitterLayer provides a high-level way to handle syntax highlighting, especially for documents with nested languages (like Markdown containing Swift code blocks).
- Use
LanguageConfiguration to load language parsers and their bundled queries. - Define a
LanguageLayer.Configuration with a languageProvider closure to map language names (including injection names) to their respective configurations. - Initialize a
LanguageLayer with your root language and configuration. - Use
rootLayer.highlights(in:provider:) to retrieve named ranges for highlighting.
// LanguageConfiguration takes care of finding and loading queries in SPM-created bundles.
let markdownConfig = try LanguageConfiguration(tree_sitter_markdown(), name: "Markdown")
let markdownInlineConfig = try LanguageConfiguration(
tree_sitter_markdown_inline(),
name: "MarkdownInline",
bundleName: "TreeSitterMarkdown_TreeSitterMarkdownInline"
)
let swiftConfig = try LanguageConfiguration(tree_sitter_swift(), name: "Swift")
// Unfortunately, injections do not use standardized language names, and can even be content-dependent. Your system must do this mapping.
let config = LanguageLayer.Configuration(
languageProvider: {
name in
switch name {
case "markdown":
return markdownConfig
case "markdown_inline":
return markdownInlineConfig
case "swift":
return swiftConfig
default:
return nil
}
}
)
let rootLayer = try LanguageLayer(languageConfig: markdownConfig, configuration: config)
let source = """
# this is markdown
```swift
func main(a: Int) {
}
"""
rootLayer.replaceContent(with: source)
let fullRange = NSRange(source.startIndex..<source.endIndex, in: source)
let textProvider = source.predicateTextProvider
let highlights = try rootLayer.highlights(in: fullRange, provider: textProvider)
for namedRange in highlights {
print("(namedRange.name): (namedRange.range)")
}