Sources/OrgCore/Syntax/SyntaxNode.swift
99 lines · 3374 bytes
1/// A view of a green node at an absolute offset, with a parent link. Created on demand.
2public final class SyntaxNode: Sendable {
3 public let green: GreenNode
4 public let offset: Int
5 public let parent: SyntaxNode?
6
7 init(green: GreenNode, offset: Int, parent: SyntaxNode?) {
8 self.green = green
9 self.offset = offset
10 self.parent = parent
11 }
12
13 public var kind: SyntaxKind { green.kind }
14 public var range: Range<Int> { offset..<(offset + green.length) }
15 public var text: String { green.text }
16
17 public var children: [SyntaxNode] {
18 var result: [SyntaxNode] = []
19 var at = offset
20 for child in green.children {
21 if case .node(let node) = child {
22 result.append(SyntaxNode(green: node, offset: at, parent: self))
23 }
24 at += child.length
25 }
26 return result
27 }
28
29 public var tokens: [SyntaxToken] {
30 var result: [SyntaxToken] = []
31 var at = offset
32 for child in green.children {
33 if case .token(let token) = child {
34 result.append(SyntaxToken(kind: token.kind, text: token.text, range: at..<(at + token.length)))
35 }
36 at += child.length
37 }
38 return result
39 }
40
41 /// Child nodes overlapping `range`. Only those are created, so a section with thousands of
42 /// children costs little when the range is small.
43 public func children(overlapping range: Range<Int>) -> [SyntaxNode] {
44 var result: [SyntaxNode] = []
45 var at = offset
46 for child in green.children {
47 let childRange = at..<(at + child.length)
48 if childRange.lowerBound >= range.upperBound, !range.isEmpty { break }
49 if case .node(let node) = child, childRange.overlaps(range) {
50 result.append(SyntaxNode(green: node, offset: at, parent: self))
51 }
52 at = childRange.upperBound
53 }
54 return result
55 }
56
57 /// The child node whose range contains `position`.
58 public func child(containing position: Int) -> SyntaxNode? {
59 var at = offset
60 for child in green.children {
61 let end = at + child.length
62 if position < end {
63 if case .node(let node) = child, position >= at { return SyntaxNode(green: node, offset: at, parent: self) }
64 return nil
65 }
66 at = end
67 }
68 return nil
69 }
70
71 /// The first child node of `kind`.
72 public func firstChild(_ kind: SyntaxKind) -> SyntaxNode? {
73 var at = offset
74 for child in green.children {
75 if case .node(let node) = child, node.kind == kind { return SyntaxNode(green: node, offset: at, parent: self) }
76 at += child.length
77 }
78 return nil
79 }
80
81 /// This node and every node below it, in document order.
82 public func descendants() -> [SyntaxNode] {
83 [self] + children.flatMap { $0.descendants() }
84 }
85}
86
87public struct SyntaxToken: Sendable, Equatable {
88 public let kind: SyntaxKind
89 public let text: String
90 public let range: Range<Int>
91}
92
93public struct OrgTree: Sendable {
94 public let green: GreenNode
95 public let settings: OrgSettings
96
97 public var root: SyntaxNode { SyntaxNode(green: green, offset: 0, parent: nil) }
98 public var text: String { green.text }
99}