Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 0 additions & 46 deletions Contributor Documentation/LSP Extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -690,52 +690,6 @@ export interface PeekDocumentsResult {
}
```

## `workspace/playgrounds`

New request for returning the list of all #Playground macros in the workspace.

Primarily designed to allow editors to provide a list of available playgrounds in the project workspace and allow
jumping to the locations where the #Playground macro was expanded.

The request fetches the list of all macros found in the workspace, returning the location, identifier, and optional label
when available for each #Playground macro expansion. If you want to keep the list of playgrounds up to date without needing to
call `workspace/playgrounds` each time a document is changed, you can filter for `swift.play` CodeLens returned by the `textDocument/codelens` request.

SourceKit-LSP will advertise `workspace/playgrounds` in its experimental server capabilities if it supports it.

- params: `WorkspacePlaygroundParams`
- result: `Playground[]`

```ts
export interface WorkspacePlaygroundParams {}

/**
* A `Playground` represents a usage of the #Playground macro, providing the editor with the
* location of the playground and identifiers to allow executing the playground through a "swift play" command.
*/
export interface Playground {
/**
* Unique identifier for the `Playground`. Client can run the playground by executing `swift play <id>`.
*
* This property is always present whether the `Playground` has a `label` or not.
*
* Follows the format output by `swift play --list`.
*/
id: string;

/**
* The label that can be used as a display name for the playground. This optional property is only available
* for named playgrounds. For example: `#Playground("hello") { print("Hello!) }` would have a `label` of `"hello"`.
*/
label?: string

/**
* The location of where the #Playground macro was used in the source code.
*/
location: Location
}
```

## `workspace/synchronize`

Request from the client to the server to wait for SourceKit-LSP to handle all ongoing requests and, optionally, wait for background activity to finish.
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -800,7 +800,7 @@ var dependencies: [Package.Dependency] {
.package(url: "https://github.com/swiftlang/swift-docc.git", branch: relatedDependenciesBranch),
.package(url: "https://github.com/swiftlang/swift-docc-symbolkit.git", branch: relatedDependenciesBranch),
.package(url: "https://github.com/swiftlang/swift-markdown.git", branch: relatedDependenciesBranch),
.package(url: "https://github.com/swiftlang/swift-tools-protocols.git", exact: "0.0.9"),
.package(url: "https://github.com/swiftlang/swift-tools-protocols.git", exact: "0.0.8"),
.package(url: "https://github.com/swiftlang/swift-tools-support-core.git", branch: relatedDependenciesBranch),
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.5.1"),
.package(url: "https://github.com/swiftlang/swift-syntax.git", branch: relatedDependenciesBranch),
Expand Down
4 changes: 1 addition & 3 deletions Sources/SKTestSupport/SwiftPMTestProject.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ package import SKOptions
package import SourceKitLSP
import SwiftExtensions
import TSCBasic
package import ToolchainRegistry
import ToolchainRegistry
@_spi(SourceKitLSP) import ToolsProtocolsSwiftExtensions
import XCTest

Expand Down Expand Up @@ -184,7 +184,6 @@ package class SwiftPMTestProject: MultiFileTestProject {
initializationOptions: LSPAny? = nil,
capabilities: ClientCapabilities = ClientCapabilities(),
options: SourceKitLSPOptions? = nil,
toolchainRegistry: ToolchainRegistry = .forTesting,
hooks: Hooks = Hooks(),
enableBackgroundIndexing: Bool = false,
usePullDiagnostics: Bool = true,
Expand Down Expand Up @@ -226,7 +225,6 @@ package class SwiftPMTestProject: MultiFileTestProject {
initializationOptions: initializationOptions,
capabilities: capabilities,
options: options,
toolchainRegistry: toolchainRegistry,
hooks: hooks,
enableBackgroundIndexing: enableBackgroundIndexing,
usePullDiagnostics: usePullDiagnostics,
Expand Down
1 change: 0 additions & 1 deletion Sources/SwiftLanguageService/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ add_library(SwiftLanguageService STATIC
InlayHints.swift
MacroExpansion.swift
OpenInterface.swift
SwiftPlaygroundsScanner.swift
RefactoringEdit.swift
RefactoringResponse.swift
RelatedIdentifiers.swift
Expand Down
3 changes: 1 addition & 2 deletions Sources/SwiftLanguageService/DocumentFormatting.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import SwiftExtensions
import SwiftParser
import SwiftSyntax
import TSCExtensions
import ToolchainRegistry
@_spi(SourceKitLSP) import ToolsProtocolsSwiftExtensions

import struct TSCBasic.AbsolutePath
Expand Down Expand Up @@ -172,7 +171,7 @@ extension SwiftLanguageService {
options: FormattingOptions,
range: Range<Position>? = nil
) async throws -> [TextEdit]? {
guard let swiftFormat = toolchain.swiftFormat else {
guard let swiftFormat else {
throw ResponseError.unknown(
"Formatting not supported because the toolchain is missing the swift-format executable"
)
Expand Down
55 changes: 7 additions & 48 deletions Sources/SwiftLanguageService/SwiftCodeLensScanner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,9 @@
//
//===----------------------------------------------------------------------===//

internal import BuildServerIntegration
import BuildServerProtocol
@_spi(SourceKitLSP) import LanguageServerProtocol
import SourceKitLSP
import SwiftSyntax
import ToolchainRegistry

/// Scans a source file for classes or structs annotated with `@main` and returns a code lens for them.
final class SwiftCodeLensScanner: SyntaxVisitor {
Expand Down Expand Up @@ -45,57 +42,19 @@ final class SwiftCodeLensScanner: SyntaxVisitor {
/// and returns CodeLens's with Commands to run/debug the application.
public static func findCodeLenses(
in snapshot: DocumentSnapshot,
workspace: Workspace?,
syntaxTreeManager: SyntaxTreeManager,
supportedCommands: [SupportedCodeLensCommand: String],
toolchain: Toolchain
targetName: String? = nil,
supportedCommands: [SupportedCodeLensCommand: String]
) async -> [CodeLens] {
guard !supportedCommands.isEmpty else {
guard snapshot.text.contains("@main") && !supportedCommands.isEmpty else {
// This is intended to filter out files that obviously do not contain an entry point.
return []
}

var targetDisplayName: String? = nil
if let workspace,
let target = await workspace.buildServerManager.canonicalTarget(for: snapshot.uri),
let buildTarget = await workspace.buildServerManager.buildTarget(named: target)
{
targetDisplayName = buildTarget.displayName
}

var codeLenses: [CodeLens] = []
let syntaxTree = await syntaxTreeManager.syntaxTree(for: snapshot)
if snapshot.text.contains("@main") {
let visitor = SwiftCodeLensScanner(
snapshot: snapshot,
targetName: targetDisplayName,
supportedCommands: supportedCommands
)
visitor.walk(syntaxTree)
codeLenses += visitor.result
}

// "swift.play" CodeLens should be ignored if "swift-play" is not in the toolchain as the client has no way of running
if toolchain.swiftPlay != nil, let workspace, let playCommand = supportedCommands[SupportedCodeLensCommand.play],
snapshot.text.contains("#Playground")
{
let playgrounds = await SwiftPlaygroundsScanner.findDocumentPlaygrounds(
in: syntaxTree,
workspace: workspace,
snapshot: snapshot
)
codeLenses += playgrounds.map({
CodeLens(
range: $0.range,
command: Command(
title: "Play \"\($0.label ?? $0.id)\"",
command: playCommand,
arguments: [$0.encodeToLSPAny()]
)
)
})
}

return codeLenses
let visitor = SwiftCodeLensScanner(snapshot: snapshot, targetName: targetName, supportedCommands: supportedCommands)
visitor.walk(syntaxTree)
return visitor.result
}

override func visit(_ node: ClassDeclSyntax) -> SyntaxVisitorContinueKind {
Expand Down
17 changes: 11 additions & 6 deletions Sources/SwiftLanguageService/SwiftLanguageService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ package actor SwiftLanguageService: LanguageService, Sendable {
package let sourcekitd: SourceKitD

/// Path to the swift-format executable if it exists in the toolchain.
let toolchain: Toolchain
let swiftFormat: URL?

/// Queue on which notifications from sourcekitd are handled to ensure we are
/// handling them in-order.
Expand Down Expand Up @@ -213,7 +213,7 @@ package actor SwiftLanguageService: LanguageService, Sendable {
}
self.sourcekitdPath = sourcekitd
self.sourceKitLSPServer = sourceKitLSPServer
self.toolchain = toolchain
self.swiftFormat = toolchain.swiftFormat
let pluginPaths: PluginPaths?
if let clientPlugin = options.sourcekitdOrDefault.clientPlugin,
let servicePlugin = options.sourcekitdOrDefault.servicePlugin
Expand Down Expand Up @@ -1032,13 +1032,18 @@ extension SwiftLanguageService {

package func codeLens(_ req: CodeLensRequest) async throws -> [CodeLens] {
let snapshot = try documentManager.latestSnapshot(req.textDocument.uri)
let workspace = await sourceKitLSPServer?.workspaceForDocument(uri: req.textDocument.uri)
var targetDisplayName: String? = nil
if let workspace = await sourceKitLSPServer?.workspaceForDocument(uri: req.textDocument.uri),
let target = await workspace.buildServerManager.canonicalTarget(for: req.textDocument.uri),
let buildTarget = await workspace.buildServerManager.buildTarget(named: target)
{
targetDisplayName = buildTarget.displayName
}
return await SwiftCodeLensScanner.findCodeLenses(
in: snapshot,
workspace: workspace,
syntaxTreeManager: self.syntaxTreeManager,
supportedCommands: self.capabilityRegistry.supportedCodeLensCommands,
toolchain: toolchain
targetName: targetDisplayName,
supportedCommands: self.capabilityRegistry.supportedCodeLensCommands
)
}

Expand Down
101 changes: 0 additions & 101 deletions Sources/SwiftLanguageService/SwiftPlaygroundsScanner.swift

This file was deleted.

17 changes: 1 addition & 16 deletions Sources/ToolchainRegistry/Toolchain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,6 @@ public final class Toolchain: Sendable {
/// The path to the swift-format executable, if available.
package let swiftFormat: URL?

/// The path to the swift-play executable, if available.
package let swiftPlay: URL?

/// The path to the clangd language server if available.
package let clangd: URL?

Expand Down Expand Up @@ -206,7 +203,6 @@ public final class Toolchain: Sendable {
swift: URL? = nil,
swiftc: URL? = nil,
swiftFormat: URL? = nil,
swiftPlay: URL? = nil,
clangd: URL? = nil,
sourcekitd: URL? = nil,
sourceKitClientPlugin: URL? = nil,
Expand All @@ -220,7 +216,6 @@ public final class Toolchain: Sendable {
self.swift = swift
self.swiftc = swiftc
self.swiftFormat = swiftFormat
self.swiftPlay = swiftPlay
self.clangd = clangd
self.sourcekitd = sourcekitd
self.sourceKitClientPlugin = sourceKitClientPlugin
Expand All @@ -245,9 +240,7 @@ public final class Toolchain: Sendable {
}
}
return isSuperset(for: \.clang) && isSuperset(for: \.swift) && isSuperset(for: \.swiftc)
&& isSuperset(for: \.swiftPlay) && isSuperset(for: \.swiftFormat) && isSuperset(for: \.sourceKitClientPlugin)
&& isSuperset(for: \.sourceKitServicePlugin) && isSuperset(for: \.clangd) && isSuperset(for: \.sourcekitd)
&& isSuperset(for: \.libIndexStore)
&& isSuperset(for: \.clangd) && isSuperset(for: \.sourcekitd) && isSuperset(for: \.libIndexStore)
}

/// Same as `isSuperset` but returns `false` if both toolchains have the same set of tools.
Expand Down Expand Up @@ -285,7 +278,6 @@ public final class Toolchain: Sendable {
var swift: URL? = nil
var swiftc: URL? = nil
var swiftFormat: URL? = nil
var swiftPlay: URL? = nil
var sourcekitd: URL? = nil
var sourceKitClientPlugin: URL? = nil
var sourceKitServicePlugin: URL? = nil
Expand Down Expand Up @@ -345,12 +337,6 @@ public final class Toolchain: Sendable {
foundAny = true
}

let swiftPlayPath = binPath.appending(component: "swift-play\(execExt)")
if FileManager.default.isExecutableFile(atPath: swiftPlayPath.path) {
swiftPlay = swiftPlayPath
foundAny = true
}

// If 'currentPlatform' is nil it's most likely an unknown linux flavor.
let dylibExtension: String
if let dynamicLibraryExtension = Platform.current?.dynamicLibraryExtension {
Expand Down Expand Up @@ -421,7 +407,6 @@ public final class Toolchain: Sendable {
swift: swift,
swiftc: swiftc,
swiftFormat: swiftFormat,
swiftPlay: swiftPlay,
clangd: clangd,
sourcekitd: sourcekitd,
sourceKitClientPlugin: sourceKitClientPlugin,
Expand Down
Loading