Skip to content

Commit b85f3af

Browse files
committed
Report MARK comments in the document symbols request
Fixes #963 rdar://117811210
1 parent 9595498 commit b85f3af

File tree

2 files changed

+117
-3
lines changed

2 files changed

+117
-3
lines changed

Sources/SourceKitLSP/Swift/DocumentSymbols.swift

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
import Foundation
1314
import LSPLogging
1415
import LanguageServerProtocol
1516
import SwiftSyntax
@@ -109,6 +110,45 @@ fileprivate final class DocumentSymbolsFinder: SyntaxAnyVisitor {
109110
)
110111
}
111112

113+
private func visit(_ trivia: Trivia, position: AbsolutePosition) {
114+
let markPrefix = "MARK: "
115+
var position = position
116+
for piece in trivia.pieces {
117+
defer {
118+
position = position.advanced(by: piece.sourceLength.utf8Length)
119+
}
120+
switch piece {
121+
case .lineComment(let commentText), .blockComment(let commentText):
122+
let trimmedComment = commentText.trimmingCharacters(in: CharacterSet(["/", "*"]).union(.whitespaces))
123+
if trimmedComment.starts(with: markPrefix) {
124+
let markText = trimmedComment.dropFirst(markPrefix.count)
125+
guard let rangeLowerBound = snapshot.position(of: position),
126+
let rangeUpperBound = snapshot.position(of: position.advanced(by: piece.sourceLength.utf8Length))
127+
else {
128+
break
129+
}
130+
result.append(
131+
DocumentSymbol(
132+
name: String(markText),
133+
kind: .namespace,
134+
range: rangeLowerBound..<rangeUpperBound,
135+
selectionRange: rangeLowerBound..<rangeUpperBound,
136+
children: nil
137+
)
138+
)
139+
}
140+
default:
141+
break
142+
}
143+
}
144+
}
145+
146+
override func visit(_ node: TokenSyntax) -> SyntaxVisitorContinueKind {
147+
self.visit(node.leadingTrivia, position: node.position)
148+
self.visit(node.trailingTrivia, position: node.endPositionBeforeTrailingTrivia)
149+
return .skipChildren
150+
}
151+
112152
override func visit(_ node: EnumCaseElementSyntax) -> SyntaxVisitorContinueKind {
113153
let rangeEnd =
114154
if let parameterClause = node.parameterClause {
@@ -235,13 +275,13 @@ fileprivate extension SyntaxProtocol {
235275
var isMemberOrTopLevelDeclaration: Bool {
236276
if self.parent?.is(MemberBlockItemSyntax.self) ?? false {
237277
return true
238-
} else if let codeBlockItem = self.parent?.as(CodeBlockItemSyntax.self),
278+
}
279+
if let codeBlockItem = self.parent?.as(CodeBlockItemSyntax.self),
239280
codeBlockItem.parent?.parent?.is(SourceFileSyntax.self) ?? false
240281
{
241282
return true
242-
} else {
243-
return false
244283
}
284+
return false
245285
}
246286
}
247287

Tests/SourceKitLSPTests/DocumentSymbolTests.swift

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,80 @@ final class DocumentSymbolTests: XCTestCase {
620620
]
621621
}
622622
}
623+
624+
func testIncludeMarkComments() async throws {
625+
try await assertDocumentSymbols(
626+
"""
627+
1️⃣// MARK: Marker2️⃣
628+
"""
629+
) { positions in
630+
[
631+
DocumentSymbol(
632+
name: "Marker",
633+
kind: .namespace,
634+
range: positions["1️⃣"]..<positions["2️⃣"],
635+
selectionRange: positions["1️⃣"]..<positions["2️⃣"]
636+
)
637+
]
638+
}
639+
640+
try await assertDocumentSymbols(
641+
"""
642+
1️⃣// MARK: - Marker2️⃣
643+
"""
644+
) { positions in
645+
[
646+
DocumentSymbol(
647+
name: "- Marker",
648+
kind: .namespace,
649+
range: positions["1️⃣"]..<positions["2️⃣"],
650+
selectionRange: positions["1️⃣"]..<positions["2️⃣"]
651+
)
652+
]
653+
}
654+
655+
try await assertDocumentSymbols(
656+
"""
657+
1️⃣/* MARK: Marker */2️⃣
658+
"""
659+
) { positions in
660+
[
661+
DocumentSymbol(
662+
name: "Marker",
663+
kind: .namespace,
664+
range: positions["1️⃣"]..<positions["2️⃣"],
665+
selectionRange: positions["1️⃣"]..<positions["2️⃣"]
666+
)
667+
]
668+
}
669+
}
670+
671+
func testIncludeNestedMarkComments() async throws {
672+
try await assertDocumentSymbols(
673+
"""
674+
1️⃣struct 2️⃣Foo3️⃣ {
675+
4️⃣// MARK: Marker5️⃣
676+
}6️⃣
677+
"""
678+
) { positions in
679+
[
680+
DocumentSymbol(
681+
name: "Foo",
682+
kind: .struct,
683+
range: positions["1️⃣"]..<positions["6️⃣"],
684+
selectionRange: positions["2️⃣"]..<positions["3️⃣"],
685+
children: [
686+
DocumentSymbol(
687+
name: "Marker",
688+
kind: .namespace,
689+
range: positions["4️⃣"]..<positions["5️⃣"],
690+
selectionRange: positions["4️⃣"]..<positions["5️⃣"]
691+
)
692+
]
693+
)
694+
]
695+
}
696+
}
623697
}
624698

625699
fileprivate func assertDocumentSymbols(

0 commit comments

Comments
 (0)