Merge pull request #1066 from ahoppen/ahoppen/nested-mark-comments

Don’t display MARK comments as children of the nodes they are attached to
This commit is contained in:
Alex Hoppen
2024-02-21 15:37:32 -08:00
committed by GitHub
2 changed files with 71 additions and 8 deletions

View File

@@ -22,7 +22,13 @@ extension SwiftLanguageServer {
let syntaxTree = await syntaxTreeManager.syntaxTree(for: snapshot)
try Task.checkCancellation()
return .documentSymbols(DocumentSymbolsFinder.find(in: [Syntax(syntaxTree)], snapshot: snapshot))
return .documentSymbols(
DocumentSymbolsFinder.find(
in: [Syntax(syntaxTree)],
snapshot: snapshot,
range: syntaxTree.position..<syntaxTree.endPosition
)
)
}
}
@@ -32,17 +38,25 @@ fileprivate final class DocumentSymbolsFinder: SyntaxAnyVisitor {
/// The snapshot of the document for which we are getting document symbols.
private let snapshot: DocumentSnapshot
/// Only document symbols that intersect with this range get reported.
private let range: Range<AbsolutePosition>
/// Accumulating the result in here.
private var result: [DocumentSymbol] = []
private init(snapshot: DocumentSnapshot) {
private init(snapshot: DocumentSnapshot, range: Range<AbsolutePosition>) {
self.snapshot = snapshot
self.range = range
super.init(viewMode: .sourceAccurate)
}
/// Designated entry point for `DocumentSymbolFinder`.
static func find(in nodes: some Sequence<Syntax>, snapshot: DocumentSnapshot) -> [DocumentSymbol] {
let visitor = Self(snapshot: snapshot)
static func find(
in nodes: some Sequence<Syntax>,
snapshot: DocumentSnapshot,
range: Range<AbsolutePosition>
) -> [DocumentSymbol] {
let visitor = DocumentSymbolsFinder(snapshot: snapshot, range: range)
for node in nodes {
visitor.walk(node)
}
@@ -57,6 +71,9 @@ fileprivate final class DocumentSymbolsFinder: SyntaxAnyVisitor {
range: Range<AbsolutePosition>,
selection: Range<AbsolutePosition>
) -> SyntaxVisitorContinueKind {
if !self.range.overlaps(range) {
return .skipChildren
}
guard let rangeLowerBound = snapshot.position(of: range.lowerBound),
let rangeUpperBound = snapshot.position(of: range.upperBound),
let selectionLowerBound = snapshot.position(of: selection.lowerBound),
@@ -65,8 +82,14 @@ fileprivate final class DocumentSymbolsFinder: SyntaxAnyVisitor {
return .skipChildren
}
let children = DocumentSymbolsFinder.find(in: node.children(viewMode: .sourceAccurate), snapshot: snapshot)
// Record MARK comments on the node's leading and trailing trivia in `result` not as a child of `node`.
visit(node.leadingTrivia, position: node.position)
let children = DocumentSymbolsFinder.find(
in: node.children(viewMode: .sourceAccurate),
snapshot: snapshot,
range: node.positionAfterSkippingLeadingTrivia..<node.endPositionBeforeTrailingTrivia
)
result.append(
DocumentSymbol(
name: name,
@@ -76,6 +99,7 @@ fileprivate final class DocumentSymbolsFinder: SyntaxAnyVisitor {
children: children
)
)
visit(node.trailingTrivia, position: node.endPositionBeforeTrailingTrivia)
return .skipChildren
}
@@ -144,8 +168,12 @@ fileprivate final class DocumentSymbolsFinder: SyntaxAnyVisitor {
}
override func visit(_ node: TokenSyntax) -> SyntaxVisitorContinueKind {
self.visit(node.leadingTrivia, position: node.position)
self.visit(node.trailingTrivia, position: node.endPositionBeforeTrailingTrivia)
if self.range.overlaps(node.position..<node.positionAfterSkippingLeadingTrivia) {
self.visit(node.leadingTrivia, position: node.position)
}
if range.overlaps(node.endPositionBeforeTrailingTrivia..<node.endPosition) {
self.visit(node.trailingTrivia, position: node.endPositionBeforeTrailingTrivia)
}
return .skipChildren
}

View File

@@ -668,7 +668,7 @@ final class DocumentSymbolTests: XCTestCase {
}
}
func testIncludeNestedMarkComments() async throws {
func testNestedMarkComment() async throws {
try await assertDocumentSymbols(
"""
1⃣struct 2⃣Foo3⃣ {
@@ -694,6 +694,41 @@ final class DocumentSymbolTests: XCTestCase {
]
}
}
func testNestedMarkCommentFollowedAttachedToChild() async throws {
try await assertDocumentSymbols(
"""
1⃣struct 2⃣Foo3⃣ {
4⃣// MARK: Marker5
6⃣func 7⃣myFunc()8⃣ { }9
}🔟
"""
) { positions in
[
DocumentSymbol(
name: "Foo",
kind: .struct,
range: positions["1"]..<positions["🔟"],
selectionRange: positions["2"]..<positions["3"],
children: [
DocumentSymbol(
name: "Marker",
kind: .namespace,
range: positions["4"]..<positions["5"],
selectionRange: positions["4"]..<positions["5"]
),
DocumentSymbol(
name: "myFunc()",
kind: .method,
range: positions["6"]..<positions["9"],
selectionRange: positions["7"]..<positions["8"],
children: []
),
]
)
]
}
}
}
fileprivate func assertDocumentSymbols(