Skip to content

Commit

Permalink
Adopting ResolvingQueryCursor
Browse files Browse the repository at this point in the history
- Huge internal changes to improve thread-safety and performance
- Some async APIs
- Remove OperationPlus dependency
  • Loading branch information
mattmassicotte committed Apr 1, 2022
1 parent 3e44fb6 commit ba3a497
Show file tree
Hide file tree
Showing 8 changed files with 239 additions and 220 deletions.
17 changes: 4 additions & 13 deletions Package.resolved
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
{
"object": {
"pins": [
{
"package": "OperationPlus",
"repositoryURL": "https://github.com/ChimeHQ/OperationPlus",
"state": {
"branch": null,
"revision": "f5d2899e113943d7ea8f73462639217acc6b92b9",
"version": "1.5.4"
}
},
{
"package": "Rearrange",
"repositoryURL": "https://github.com/ChimeHQ/Rearrange",
Expand All @@ -24,17 +15,17 @@
"repositoryURL": "https://github.com/ChimeHQ/SwiftTreeSitter",
"state": {
"branch": null,
"revision": "8f7413d55c180b4b1184a4ec5cee652d1c9e267a",
"version": "0.4.1"
"revision": "fc0a8623f40ac9f0c5ed6bc7bbcb03b94ebb18d1",
"version": "0.5.0"
}
},
{
"package": "tree-sitter-xcframework",
"repositoryURL": "https://github.com/krzyzanowskim/tree-sitter-xcframework",
"state": {
"branch": null,
"revision": "e24b77438e2d40f796875101e45a5b5f93aaac25",
"version": "0.206.7"
"revision": "668fc0bae9ff3152b458d13007ec9af7806d0655",
"version": "0.206.9"
}
}
]
Expand Down
5 changes: 2 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@ let package = Package(
.library(name: "Neon", targets: ["Neon"]),
],
dependencies: [
.package(url: "https://github.com/ChimeHQ/SwiftTreeSitter", from: "0.4.1"),
.package(url: "https://github.com/ChimeHQ/SwiftTreeSitter", from: "0.5.0"),
.package(url: "https://github.com/ChimeHQ/Rearrange", from: "1.5.1"),
.package(url: "https://github.com/ChimeHQ/OperationPlus", from: "1.5.4"),
],
targets: [
.target(name: "Neon", dependencies: ["SwiftTreeSitter", "Rearrange", "OperationPlus"]),
.target(name: "Neon", dependencies: ["SwiftTreeSitter", "Rearrange"]),
.testTarget(name: "NeonTests", dependencies: ["Neon"]),
]
)
19 changes: 12 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ Some things to consider:

## TreeSitterClient

This class is an asynchronous interface to tree-sitter. It provides an UTF-16 code-point (`NSString`-compatible) API for edits, invalidations, and queries. It can process edits of `String` objects, or raw bytes for even greater flexibility and performance. Invalidations are translated to the current content state, even if a queue of edits are still being processed.
This class is an asynchronous interface to tree-sitter. It provides an UTF-16 code-point (`NSString`-compatible) API for edits, invalidations, and queries. It can process edits of `String` objects, or raw bytes. Invalidations are translated to the current content state, even if a queue of edits are still being processed.

It goes through great lengths to provide APIs that can be both synchronous, asynchronous, or both depending on the state of the system. This kind of interface can be critical for prividing a flicker-free highlighting and live typing interactions.

TreeSitterClient requires a function that can translate UTF16 code points (ie `NSRange`.location) to a tree-sitter `Point` (line + offset).

Expand Down Expand Up @@ -84,14 +86,17 @@ client.willChangeContent(in: range)
client.didChangeContent(to: string, in: range, delta: delta, limit: limit)

// step 4: run queries
// you can execute these queries in the invalidationHandler
// you can execute these queries directly in the invalidationHandler, if desired

// Many tree-sitter highlight queries contain predicates. These are both expensive
// and complex to resolve. This is an optional feature - you can just skip it. Doing
// so makes the process both faster and simpler, but could result in lower-quality
// and even incorrect highlighting.

// produce a function that can read your text content
let provider = { contentRange -> Result<String, Error> in ... }
let provider: TreeSitterClient.TextProvider = { (range, _) -> String? in ... }

client.executeHighlightQuery(query, in: range, contentProvider: provider) { result in
// TreeSitterClient.HighlightMatch objects will tell you about the
// highlights.scm name and range in your text
client.executeHighlightsQuery(query, in: range, textProvider: provider) { result in
// Token values will tell you the highlights.scm name and range in your text
}
```

Expand Down
14 changes: 14 additions & 0 deletions Sources/Neon/Token.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Foundation

public struct Token {
public let name: String
public let range: NSRange

public init(name: String, range: NSRange) {
self.name = name
self.range = range
}
}

extension Token: Hashable {
}
32 changes: 32 additions & 0 deletions Sources/Neon/TreeSitter+Extensions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import Foundation
import SwiftTreeSitter

extension Point {
public typealias LocationTransformer = (Int) -> Point?
}

extension InputEdit {
init?(range: NSRange, delta: Int, oldEndPoint: Point, transformer: Point.LocationTransformer) {
let startLocation = range.location
let newEndLocation = range.max + delta

if newEndLocation < 0 {
assertionFailure("invalid range/delta")
return nil
}

guard
let startPoint = transformer(startLocation),
let newEndPoint = transformer(newEndLocation)
else {
return nil
}

self.init(startByte: UInt32(range.location * 2),
oldEndByte: UInt32(range.max * 2),
newEndByte: UInt32(newEndLocation * 2),
startPoint: startPoint,
oldEndPoint: oldEndPoint,
newEndPoint: newEndPoint)
}
}
Loading

0 comments on commit ba3a497

Please sign in to comment.