Skip to content

Commit

Permalink
Add Local Refactor
Browse files Browse the repository at this point in the history
Tests

READMË
  • Loading branch information
rockbruno committed Jun 28, 2019
1 parent 8482476 commit bd1eb85
Show file tree
Hide file tree
Showing 17 changed files with 763 additions and 8 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ SourceKit-LSP is still in early development, so you may run into rough edges wit
| Find References || |
| Background Indexing || Build project to update the index using [Indexing While Building](#indexing-while-building) |
| Workspace Symbols || |
| Refactoring || |
| Global Rename || |
| Local Refactoring || |
| Formatting || |
| Folding || |
| Syntax Highlighting || Not currently part of LSP. |
Expand Down
47 changes: 47 additions & 0 deletions Sources/LanguageServerProtocol/ApplyEdit.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

/// Request from the server to the client to modify resources on the client side.
///
/// - Parameters:
/// - label: An optional label of the workspace edit.
/// - edit: The edits to apply.
public struct ApplyEditRequest: RequestType {
public static let method: String = "workspace/applyEdit"
public typealias Response = ApplyEditResponse?

/// An optional label of the workspace edit.
/// Used by the client's user interface for things such as
/// the stack to undo the workspace edit.
public var label: String?

/// The edits to apply.
public var edit: WorkspaceEdit

public init(label: String?, edit: WorkspaceEdit) {
self.label = label
self.edit = edit
}
}

public struct ApplyEditResponse: Codable, Hashable, ResponseType {
/// Indicates whether the edit was applied or not.
public var applied: Bool

/// An optional textual description for why the edit was not applied.
public var failureReason: String?

public init(applied: Bool, failureReason: String?) {
self.applied = applied
self.failureReason = failureReason
}
}
11 changes: 11 additions & 0 deletions Sources/LanguageServerProtocol/ClientCapabilities.swift
Original file line number Diff line number Diff line change
Expand Up @@ -221,12 +221,23 @@ public struct TextDocumentClientCapabilities: Hashable, Codable {
///
/// If specified, the client *also* guarantees that it will handle unknown kinds gracefully.
public var valueSet: [LanguageServerProtocol.CodeActionKind]

public init(valueSet: [LanguageServerProtocol.CodeActionKind]) {
self.valueSet = valueSet
}
}

public var codeActionKind: CodeActionKind

public init(codeActionKind: CodeActionKind) {
self.codeActionKind = codeActionKind
}
}

public var codeActionLiteralSupport: CodeActionLiteralSupport? = nil

public init() {
}
}

/// Capabilities specific to `textDocument/publishDiagnostics`.
Expand Down
2 changes: 1 addition & 1 deletion Sources/LanguageServerProtocol/Connection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public final class LocalConnection {

var state: State = .ready

var handler: MessageHandler? = nil
public internal(set) var handler: MessageHandler? = nil

public init() {}

Expand Down
41 changes: 41 additions & 0 deletions Sources/LanguageServerProtocol/ExecuteCommand.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

/// Request sent from the client to to trigger command execution on the server.
///
/// The execution of this request can be the result of a request that returns a command,
/// such as CodeActionsRequest and CodeLensRequest. In most cases, the server creates a WorkspaceEdit
/// structure and applies the changes to the workspace using the ApplyEditRequest.
///
/// Servers that provide command execution should set the `executeCommand` server capability.
///
/// - Parameters:
/// - command: The command to be executed.
/// - arguments: The arguments to use when executing the command.
public struct ExecuteCommandRequest: RequestType {
public static let method: String = "workspace/executeCommand"

// The LSP has no response for this request (Any?), but we return
// the resulting edit for testing purposes.
public typealias Response = WorkspaceEdit?

/// The command to be executed.
public var command: String

/// Arguments that the command should be invoked with.
public var arguments: [CommandArgumentType]?

public init(command: String, arguments: [CommandArgumentType]?) {
self.command = command
self.arguments = arguments
}
}
1 change: 1 addition & 0 deletions Sources/LanguageServerProtocol/Messages.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public let builtinRequests: [_RequestType.Type] = [
DocumentColorRequest.self,
ColorPresentationRequest.self,
CodeActionRequest.self,
ExecuteCommandRequest.self,

// MARK: LSP Extension Requests

Expand Down
18 changes: 17 additions & 1 deletion Sources/LanguageServerProtocol/ServerCapabilities.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ public struct ServerCapabilities: Codable, Hashable {
/// Whether the server provides "textDocument/codeAction".
public var codeActionProvider: CodeActionServerCapabilities?

/// Whether the server provides "workspace/executeCommand".
public var executeCommandProvider: ExecuteCommandOptions?

// TODO: fill-in the rest.

public init(
Expand All @@ -66,7 +69,8 @@ public struct ServerCapabilities: Codable, Hashable {
foldingRangeProvider: Bool? = nil,
documentSymbolProvider: Bool? = nil,
colorProvider: Bool? = nil,
codeActionProvider: CodeActionServerCapabilities? = nil
codeActionProvider: CodeActionServerCapabilities? = nil,
executeCommandProvider: ExecuteCommandOptions? = nil
)
{
self.textDocumentSync = textDocumentSync
Expand All @@ -82,6 +86,7 @@ public struct ServerCapabilities: Codable, Hashable {
self.documentSymbolProvider = documentSymbolProvider
self.colorProvider = colorProvider
self.codeActionProvider = codeActionProvider
self.executeCommandProvider = executeCommandProvider
}

public init(from decoder: Decoder) throws {
Expand All @@ -93,6 +98,7 @@ public struct ServerCapabilities: Codable, Hashable {
self.documentSymbolProvider = try container.decodeIfPresent(Bool.self, forKey: .documentSymbolProvider)
self.colorProvider = try container.decodeIfPresent(Bool.self, forKey: .colorProvider)
self.codeActionProvider = try container.decodeIfPresent(CodeActionServerCapabilities.self, forKey: .codeActionProvider)
self.executeCommandProvider = try container.decodeIfPresent(ExecuteCommandOptions.self, forKey: .executeCommandProvider)

if let textDocumentSync = try? container.decode(TextDocumentSyncOptions.self, forKey: .textDocumentSync) {
self.textDocumentSync = textDocumentSync
Expand Down Expand Up @@ -234,3 +240,13 @@ public struct CodeActionOptions: Codable, Hashable {
self.codeActionKinds = codeActionKinds
}
}

public struct ExecuteCommandOptions: Codable, Hashable {

/// The commands to be executed on this server.
public var commands: [String]

public init(commands: [String]) {
self.commands = commands
}
}
26 changes: 26 additions & 0 deletions Sources/LanguageServerProtocol/WorkspaceEdit.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

/// A workspace edit represents changes to many resources managed in the workspace.
public struct WorkspaceEdit: Codable, Hashable, ResponseType {

/// The edits to be applied to existing resources.
public var changes: [String: [TextEdit]]?

public init(changes: [URL: [TextEdit]]?) {
guard let changes = changes else {
return
}
let changesArray = changes.map { ($0.key.absoluteString, $0.value) }
self.changes = Dictionary(uniqueKeysWithValues: changesArray)
}
}
6 changes: 5 additions & 1 deletion Sources/SKTestSupport/TestJSONRPCConnection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ public final class TestClient: LanguageServerEndpoint {
var oneShotNotificationHandlers: [((Any) -> Void)] = []

public var allowUnexpectedNotification: Bool = false
public var allowUnexpectedRequest: Bool = false

public func appendOneShotNotificationHandler<N>(_ handler: @escaping (Notification<N>) -> Void) {
oneShotNotificationHandlers.append({ anyNote in
Expand Down Expand Up @@ -125,7 +126,10 @@ public final class TestClient: LanguageServerEndpoint {
}

override public func _handleUnknown<R>(_ request: Request<R>) where R : RequestType {
fatalError()
guard allowUnexpectedRequest else {
fatalError("unexpected request \(request)")
}
request.reply(.failure(.cancelled))
}
}

Expand Down
29 changes: 28 additions & 1 deletion Sources/SourceKit/SourceKitServer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ public final class SourceKitServer: LanguageServer {
registerWorkspaceRequest(SourceKitServer.documentColor)
registerWorkspaceRequest(SourceKitServer.colorPresentation)
registerWorkspaceRequest(SourceKitServer.codeAction)
registerWorkspaceRequest(SourceKitServer.executeCommand)
}

func registerWorkspaceRequest<R>(
Expand Down Expand Up @@ -268,7 +269,10 @@ extension SourceKitServer {
codeActionProvider: CodeActionServerCapabilities(
clientCapabilities: req.params.capabilities.textDocument?.codeAction,
codeActionOptions: CodeActionOptions(codeActionKinds: nil),
supportsCodeActions: false // TODO: Turn it on after a provider is implemented.
supportsCodeActions: true
),
executeCommandProvider: ExecuteCommandOptions(
commands: builtinSwiftCommands // FIXME: Clangd commands?
)
)))
}
Expand Down Expand Up @@ -367,6 +371,29 @@ extension SourceKitServer {
toolchainTextDocumentRequest(req, workspace: workspace, fallback: nil)
}

func executeCommand(_ req: Request<ExecuteCommandRequest>, workspace: Workspace) {
// FIXME: This request has no URL associated to it, but we need to determine the server
// that it gets sent to. There should be a better way to do this.
let isSwiftCommand = Command.isCommandIdentifierFromSwiftLSP(req.params.command)
let connections = workspace.documentService.values.compactMap { $0 as? LocalConnection }
let service: Connection?
if isSwiftCommand {
service = connections.first { $0.handler is SwiftLanguageServer }
} else {
service = connections.first { $0.handler is ClangLanguageServerShim }
}
guard let serviceToExecute = service else {
req.reply(nil)
return
}
let id = serviceToExecute.send(req.params, queue: DispatchQueue.global()) { result in
req.reply(result)
}
req.cancellationToken.addCancellationHandler { [weak serviceToExecute] in
serviceToExecute?.send(CancelRequest(id: id))
}
}

func definition(_ req: Request<DefinitionRequest>, workspace: Workspace) {
// FIXME: sending yourself a request isn't very convenient

Expand Down
Loading

0 comments on commit bd1eb85

Please sign in to comment.