Skip to content

Commit

Permalink
Make JSDoc Highlight as Comments (#228)
Browse files Browse the repository at this point in the history
<!--- IMPORTANT: If this PR addresses multiple unrelated issues, it will
be closed until separated. -->

### Description

Makes JSDocs highlight as comments. Because they're injected as a
different language they don't get captured normally. This is the only
language we have to handle this in so it's hard-coded in the
TreeSitterClient.

Also adds a quick check to prevent potential recursive cursor
notifications using SwiftUI.

### Related Issues

<!--- REQUIRED: Tag all related issues (e.g. * #123) -->
<!--- If this PR resolves the issue please specify (e.g. * closes #123)
-->
<!--- If this PR addresses multiple issues, these issues must be related
to one other -->

* [Discord
conversation](https://canary.discord.com/channels/951544472238444645/987416899816149024/1201620579590090853)

### Checklist

<!--- Add things that are not yet implemented above -->

- [x] I read and understood the [contributing
guide](https://github.com/CodeEditApp/CodeEdit/blob/main/CONTRIBUTING.md)
as well as the [code of
conduct](https://github.com/CodeEditApp/CodeEdit/blob/main/CODE_OF_CONDUCT.md)
- [x] The issues this PR addresses are related to each other
- [x] My changes generate no new warnings
- [x] My code builds and runs on my machine
- [x] My changes are all related to the related issue above
- [x] I documented my code

### Screenshots

<img width="285" alt="Screenshot 2024-02-02 at 7 37 19 PM"
src="https://github.com/CodeEditApp/CodeEditSourceEditor/assets/35942988/f201e5ff-1bf9-4bb5-97fb-0914aa66246a">
  • Loading branch information
thecoolwinter authored Feb 3, 2024
1 parent b5a8ca9 commit c971fe9
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ extension TextViewController {
/// Sets new cursor positions.
/// - Parameter positions: The positions to set. Lines and columns are 1-indexed.
public func setCursorPositions(_ positions: [CursorPosition]) {
if isPostingCursorNotification { return }
_ = textView.becomeFirstResponder()

var newSelectedRanges: [NSRange] = []
Expand Down Expand Up @@ -48,6 +49,9 @@ extension TextViewController {
positions.append(CursorPosition(range: selectedRange.range, line: row, column: column))
}
cursorPositions = positions.sorted(by: { $0.range.location < $1.range.location })

isPostingCursorNotification = true
NotificationCenter.default.post(name: Self.cursorPositionUpdatedNotification, object: nil)
isPostingCursorNotification = false
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ public class TextViewController: NSViewController {
internal var highlightLayers: [CALayer] = []
internal var systemAppearance: NSAppearance.Name?

package var isPostingCursorNotification: Bool = false

/// The string contents.
public var string: String {
textView.string
Expand Down
61 changes: 61 additions & 0 deletions Sources/CodeEditSourceEditor/Extensions/Tree+prettyPrint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,65 @@ extension Tree {
}
}
}

extension MutableTree {
func prettyPrint() {
guard let cursor = self.rootNode?.treeCursor else {
print("NO ROOT NODE")
return
}
guard cursor.currentNode != nil else {
print("NO CURRENT NODE")
return
}

func p(_ cursor: TreeCursor, depth: Int) {
guard let node = cursor.currentNode else {
return
}

let visible = node.isNamed

if visible {
print(String(repeating: " ", count: depth * 2), terminator: "")
if let fieldName = cursor.currentFieldName {
print(fieldName, ": ", separator: "", terminator: "")
}
print("(", node.nodeType ?? "NONE", " ", node.range, " ", separator: "", terminator: "")
}

if cursor.goToFirstChild() {
while true {
if cursor.currentNode != nil && cursor.currentNode!.isNamed {
print("")
}

p(cursor, depth: depth + 1)

if !cursor.gotoNextSibling() {
break
}
}

if !cursor.gotoParent() {
fatalError("Could not go to parent, this tree may be invalid.")
}
}

if visible {
print(")", terminator: "")
}
}

if cursor.currentNode?.childCount == 0 {
if !cursor.currentNode!.isNamed {
print("{\(cursor.currentNode!.nodeType ?? "NONE")}")
} else {
print("\"\(cursor.currentNode!.nodeType ?? "NONE")\"")
}
} else {
p(cursor, depth: 1)
}
}
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import CodeEditLanguages

extension TreeSitterClient {
func queryHighlightsForRange(range: NSRange) -> [HighlightRange] {
guard let state = self.state, let readCallback else { return [] }
guard let state = self.state else { return [] }

var highlights: [HighlightRange] = []
var injectedSet = IndexSet(integersIn: range)
Expand All @@ -22,8 +22,7 @@ extension TreeSitterClient {
if let rangeIntersection = range.intersection(layerRange) {
let queryResult = queryLayerHighlights(
layer: layer,
range: rangeIntersection,
readCallback: readCallback
range: rangeIntersection
)

highlights.append(contentsOf: queryResult)
Expand All @@ -36,8 +35,7 @@ extension TreeSitterClient {
for range in injectedSet.rangeView {
let queryResult = queryLayerHighlights(
layer: state.layers[0],
range: NSRange(range),
readCallback: readCallback
range: NSRange(range)
)
highlights.append(contentsOf: queryResult)
}
Expand All @@ -52,8 +50,7 @@ extension TreeSitterClient {
/// - Returns: Any ranges to highlight.
internal func queryLayerHighlights(
layer: LanguageLayer,
range: NSRange,
readCallback: SwiftTreeSitter.Predicate.TextProvider
range: NSRange
) -> [HighlightRange] {
guard let tree = layer.tree,
let rootNode = tree.rootNode else {
Expand All @@ -68,7 +65,16 @@ extension TreeSitterClient {
queryCursor.setRange(range)
queryCursor.matchLimit = Constants.treeSitterMatchLimit

return highlightsFromCursor(cursor: queryCursor, includedRange: range, readCallback: readCallback)
var highlights: [HighlightRange] = []

// See https://github.com/CodeEditApp/CodeEditSourceEditor/pull/228
if layer.id == .jsdoc {
highlights.append(HighlightRange(range: range, capture: .comment))
}

highlights += highlightsFromCursor(cursor: queryCursor, includedRange: range)

return highlights
}

/// Resolves a query cursor to the highlight ranges it contains.
Expand All @@ -79,8 +85,7 @@ extension TreeSitterClient {
/// - Returns: Any highlight ranges contained in the cursor.
internal func highlightsFromCursor(
cursor: QueryCursor,
includedRange: NSRange,
readCallback: SwiftTreeSitter.Predicate.TextProvider
includedRange: NSRange
) -> [HighlightRange] {
return cursor
.flatMap { $0.captures }
Expand All @@ -89,7 +94,7 @@ extension TreeSitterClient {
// in the included range
let intersectionRange = $0.range.intersection(includedRange) ?? .zero
// Check that the capture name is one CESE can parse. If not, ignore it completely.
if intersectionRange.length > 0, let captureName = CaptureName.fromString($0.name ?? "") {
if intersectionRange.length > 0, let captureName = CaptureName.fromString($0.name) {
return HighlightRange(range: intersectionRange, capture: captureName)
}
return nil
Expand Down

0 comments on commit c971fe9

Please sign in to comment.