|
10 | 10 | // |
11 | 11 | //===----------------------------------------------------------------------===// |
12 | 12 |
|
| 13 | +internal import BuildServerIntegration |
| 14 | +import BuildServerProtocol |
13 | 15 | import LanguageServerProtocol |
14 | 16 | import SourceKitLSP |
15 | 17 | import SwiftSyntax |
| 18 | +import ToolchainRegistry |
16 | 19 |
|
17 | 20 | /// Scans a source file for classes or structs annotated with `@main` and returns a code lens for them. |
18 | 21 | final class SwiftCodeLensScanner: SyntaxVisitor { |
@@ -42,19 +45,38 @@ final class SwiftCodeLensScanner: SyntaxVisitor { |
42 | 45 | /// and returns CodeLens's with Commands to run/debug the application. |
43 | 46 | public static func findCodeLenses( |
44 | 47 | in snapshot: DocumentSnapshot, |
| 48 | + workspace: Workspace?, |
45 | 49 | syntaxTreeManager: SyntaxTreeManager, |
46 | | - targetName: String? = nil, |
47 | | - supportedCommands: [SupportedCodeLensCommand: String] |
| 50 | + supportedCommands: [SupportedCodeLensCommand: String], |
| 51 | + toolchain: Toolchain |
48 | 52 | ) async -> [CodeLens] { |
49 | | - guard snapshot.text.contains("@main") && !supportedCommands.isEmpty else { |
50 | | - // This is intended to filter out files that obviously do not contain an entry point. |
| 53 | + guard !supportedCommands.isEmpty else { |
51 | 54 | return [] |
52 | 55 | } |
53 | 56 |
|
| 57 | + var targetDisplayName: String? = nil |
| 58 | + if let workspace, |
| 59 | + let target = await workspace.buildServerManager.canonicalTarget(for: snapshot.uri), |
| 60 | + let buildTarget = await workspace.buildServerManager.buildTarget(named: target) |
| 61 | + { |
| 62 | + targetDisplayName = buildTarget.displayName |
| 63 | + } |
| 64 | + |
| 65 | + var codeLenses: [CodeLens] = [] |
54 | 66 | let syntaxTree = await syntaxTreeManager.syntaxTree(for: snapshot) |
55 | | - let visitor = SwiftCodeLensScanner(snapshot: snapshot, targetName: targetName, supportedCommands: supportedCommands) |
56 | | - visitor.walk(syntaxTree) |
57 | | - return visitor.result |
| 67 | + if snapshot.text.contains("@main") { |
| 68 | + let visitor = SwiftCodeLensScanner(snapshot: snapshot, targetName: targetDisplayName, supportedCommands: supportedCommands) |
| 69 | + visitor.walk(syntaxTree) |
| 70 | + codeLenses += visitor.result |
| 71 | + } |
| 72 | + |
| 73 | + // "swift.play" CodeLens should be ignored if "swift-play" is not in the toolchain as the client has no way of running |
| 74 | + if toolchain.swiftPlay != nil, let workspace, let playCommand = supportedCommands[SupportedCodeLensCommand.play], snapshot.text.contains("#Playground") { |
| 75 | + let playgrounds = await SwiftPlaygroundsScanner.findDocumentPlaygrounds(in: syntaxTree, workspace: workspace, snapshot: snapshot) |
| 76 | + codeLenses += playgrounds.map({ p in CodeLens(range: p.range, command: Command(title: "Play \"\(p.label ?? p.id)\"", command: playCommand, arguments: [p.encodeToLSPAny()])) }) |
| 77 | + } |
| 78 | + |
| 79 | + return codeLenses |
58 | 80 | } |
59 | 81 |
|
60 | 82 | override func visit(_ node: ClassDeclSyntax) -> SyntaxVisitorContinueKind { |
|
0 commit comments