Skip to content

Commit

Permalink
Command
Browse files Browse the repository at this point in the history
  • Loading branch information
rockbruno committed Jan 18, 2019
1 parent 6c681d3 commit 736bd60
Show file tree
Hide file tree
Showing 10 changed files with 303 additions and 43 deletions.
35 changes: 11 additions & 24 deletions Sources/LanguageServerProtocol/CodeAction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
//
//===----------------------------------------------------------------------===//

public typealias CodeActionProviderCompletion = (([CodeAction]) -> Void)
public typealias CodeActionProvider = ((CodeActionRequest, CodeActionProviderCompletion?) -> Void)

/// Request for returning all possible code actions for a given text document and range.
///
/// The code action request is sent from the client to the server to compute commands for a given text
Expand Down Expand Up @@ -37,8 +40,8 @@ public struct CodeActionRequest: TextDocumentRequest, Hashable {
/// The document in which the command was invoked.
public var textDocument: TextDocumentIdentifier

public init(range: PositionRange, context: CodeActionContext, textDocument: TextDocumentIdentifier) {
self.range = range
public init(range: Range<Position>, context: CodeActionContext, textDocument: TextDocumentIdentifier) {
self.range = PositionRange(range)
self.context = context
self.textDocument = textDocument
}
Expand All @@ -50,12 +53,12 @@ public struct CodeActionContext: Codable, Hashable {
public var diagnostics: [Diagnostic]

/// Requested kind of actions to return.
/// Actions not of this kind are filtered out by the client before being shown,
/// If provided, actions of these kinds are filtered out by the client before being shown,
/// so servers can omit computing them.
public var only: [CodeActionKind]?
}

public struct CodeAction: Codable, Hashable, ResponseType {
public struct CodeAction: Codable, ResponseType {

/// A short, human-readable, title for this code action.
public var title: String
Expand All @@ -69,34 +72,18 @@ public struct CodeAction: Codable, Hashable, ResponseType {
/// The workspace edit this code action performs, if applicable.
/// If a code action isn't expensive to handle, servers can use this
/// to directly provide the edit that will be executed by this code action.
//FIXME
// public var edit: WorkspaceEdit?
public var edit: WorkspaceEdit?

/// A command this code action executes.
/// If a code action provides an edit and a command,
/// first the edit is executed and then the command.
public var command: Command?
public var command: AnyCommand?

public init(title: String, kind: CodeActionKind? = nil, diagnostics: [Diagnostic]? = nil, command: Command? = nil) {
public init(title: String, kind: CodeActionKind? = nil, diagnostics: [Diagnostic]? = nil, edit: WorkspaceEdit? = nil, command: AnyCommand? = nil) {
self.title = title
self.kind = kind
self.diagnostics = diagnostics
//FIXME
//self.edit = edit
self.command = command
}
}

public struct Command: Codable, Hashable {

/// Title of the command, like `save`.
public var title: String

/// The identifier of the actual command handler.
public var command: String

public init(title: String, command: String) {
self.title = title
self.edit = edit
self.command = command
}
}
110 changes: 110 additions & 0 deletions Sources/LanguageServerProtocol/Command.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 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 `CommandData` represents the underlying data of a custom `Command`.
public protocol CommandData: Codable {
static var identifier: String { get }
}

/// Represents a reference to a command identified by a string. Used as the result of
/// requests that returns actions to the user, later used as the parameter of
/// workspace/executeCommand if the user wishes to execute said command.
public struct Command<Data: CommandData> {

/// Title of the command, like `save`.
public var title: String

/// The internal identifier for this command.
public var command: String {
return type(of: data).identifier
}

/// The data related to this command.
public var data: Data

public init(title: String = "", data: Data) {
self.title = title
self.data = data
}
}

/// Type-erased container of a generic `Command`, used for (de)serialization of commands.
public struct AnyCommand {
private let command: Any

public init<T>(_ command: Command<T>) {
self.command = command
}

public func getAs<T: CommandData>(commandData: Command<T>.Type) -> Command<T>? {
return command as? Command<T>
}
}

extension AnyCommand: Codable {
public enum CodingKeys: String, CodingKey {
case title
case command
case arguments
}

public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let command: String = try container.decode(String.self, forKey: .command)
switch command {
case SemanticRefactorCommandData.identifier:
let data = try container.decode([SemanticRefactorCommandData].self, forKey: .arguments)
let command = Command(data: data[0])
self.init(command)
default:
fatalError()
}
}

public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
if let command = command as? Command<SemanticRefactorCommandData> {
try container.encode(command.title, forKey: .title)
try container.encode(command.command, forKey: .command)
try container.encode([command.data], forKey: .arguments)
} else {
fatalError()
}
}
}

public struct SemanticRefactorCommandData: CommandData {
public static let identifier = "sourcekit.lsp.semantic.refactoring.command"

/// The document URL to refactor.
public var urlString: String

/// The identifier of the refactoring action.
public var actionString: String

/// The starting line of the range to refactor.
public var line: Int

/// The starting column of the range to refactor.
public var column: Int

/// The length of the range to refactor.
public var length: Int

public init(url: URL, actionString: String, line: Int, column: Int, length: Int) {
self.urlString = url.path
self.actionString = actionString
self.line = line
self.column = column
self.length = length
}
}
43 changes: 43 additions & 0 deletions Sources/LanguageServerProtocol/ExecuteCommand.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 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: TextDocumentRequest {
public static let method: String = "workspace/executeCommand"
// FIXME: A response isn't expected for this request. There's probably a better way
// to handle this.
public typealias Response = ExecuteCommandResponse?

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

public var textDocument: TextDocumentIdentifier {
return TextDocumentIdentifier(URL(fileURLWithPath: "/Users/bruno.rocha/Desktop/never.swift"))
}

public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
command = try container.decode(AnyCommand.self)
}
}

public struct ExecuteCommandResponse: Codable, Hashable, ResponseType {}
1 change: 1 addition & 0 deletions Sources/LanguageServerProtocol/Messages.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public let builtinRequests: [_RequestType.Type] = [
DocumentOnTypeFormatting.self,
FoldingRangeRequest.self,
CodeActionRequest.self,
ExecuteCommandRequest.self,

// MARK: LSP Extension Requests

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

/// Whether the server provides "workspace/executeCommand".
//FIXME: Separate these like in ClientCapabilities.
public var executeCommandProvider: ExecuteCommandOptions?

// TODO: fill-in the rest.

public init(
Expand All @@ -58,7 +62,8 @@ public struct ServerCapabilities: Codable, Hashable {
documentRangeFormattingProvider: Bool? = nil,
documentOnTypeFormattingProvider: DocumentOnTypeFormattingOptions? = nil,
foldingRangeProvider: Bool? = nil,
codeActionProvider: CodeActionOptions? = nil
codeActionProvider: CodeActionOptions? = nil,
executeCommandProvider: ExecuteCommandOptions? = nil
)
{
self.textDocumentSync = textDocumentSync
Expand All @@ -72,6 +77,7 @@ public struct ServerCapabilities: Codable, Hashable {
self.documentOnTypeFormattingProvider = documentOnTypeFormattingProvider
self.foldingRangeProvider = foldingRangeProvider
self.codeActionProvider = codeActionProvider
self.executeCommandProvider = executeCommandProvider
}

public init(from decoder: Decoder) throws {
Expand All @@ -80,6 +86,8 @@ public struct ServerCapabilities: Codable, Hashable {
self.hoverProvider = try container.decodeIfPresent(Bool.self, forKey: .hoverProvider)
self.definitionProvider = try container.decodeIfPresent(Bool.self, forKey: .definitionProvider)
self.foldingRangeProvider = try container.decodeIfPresent(Bool.self, forKey: .foldingRangeProvider)
self.codeActionProvider = try container.decodeIfPresent(CodeActionOptions.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 @@ -180,3 +188,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
}
}
20 changes: 20 additions & 0 deletions Sources/LanguageServerProtocol/WorkspaceEdit.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 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.
/// The edit should either provide changes or documentChanges. If the client can handle versioned document
/// edits and if documentChanges are present, the latter are preferred over changes.
public struct WorkspaceEdit: Codable, Hashable {

/// The edits to be applied to existing resources.
public var changes: [TextEdit]?
}
8 changes: 8 additions & 0 deletions Sources/SourceKit/SourceKitServer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public final class SourceKitServer: LanguageServer {
registerWorkspaceRequest(SourceKitServer.foldingRange)
registerWorkspaceRequest(SourceKitServer.symbolInfo)
registerWorkspaceRequest(SourceKitServer.codeAction)
registerWorkspaceRequest(SourceKitServer.executeCommand)
}

func registerWorkspaceRequest<R>(
Expand Down Expand Up @@ -255,6 +256,9 @@ extension SourceKitServer {
foldingRangeProvider: true,
codeActionProvider: CodeActionOptions(
codeActionKinds: [.refactor]
),
executeCommandProvider: ExecuteCommandOptions(
commands: [SemanticRefactorCommandData.identifier]
)
)))
}
Expand Down Expand Up @@ -341,6 +345,10 @@ extension SourceKitServer {
toolchainTextDocumentRequest(req, workspace: workspace, fallback: nil)
}

func executeCommand(_ req: Request<ExecuteCommandRequest>, workspace: Workspace) {
toolchainTextDocumentRequest(req, workspace: workspace, fallback: nil)
}

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

Expand Down
18 changes: 18 additions & 0 deletions Sources/SourceKit/sourcekitd/SemanticRefactoring.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 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
//
//===----------------------------------------------------------------------===//

import LanguageServerProtocol
import Basic
import sourcekitd

struct SemanticRefactoring {
}
Loading

0 comments on commit 736bd60

Please sign in to comment.