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
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import Foundation

extension ClientNotification {
/// Whether this notification mutates the server's state.
public var mutatesServerState: Bool {
return true
}
}

extension ClientRequest {
/// Whether this request mutates the server's state.
public var mutatesServerState: Bool {
switch self {
case .initialize:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,36 @@
import Foundation

extension Registration {
/// The client request method this registration corresponds to, if any.
public var requestMethod: ClientRequest.Method? {
return ClientRequest.Method(rawValue: method)
}

/// The client notification method this registration corresponds to, if any.
public var notificationMethod: ClientNotification.Method? {
return ClientNotification.Method(rawValue: method)
}
}

extension Unregistration {
/// The client request method this unregistration corresponds to, if any.
public var requestMethod: ClientRequest.Method? {
return ClientRequest.Method(rawValue: method)
}

/// The client notification method this unregistration corresponds to, if any.
public var notificationMethod: ClientNotification.Method? {
return ClientNotification.Method(rawValue: method)
}
}

extension ServerCapabilities {
/// Applies multiple dynamic registrations to the server capabilities.
public mutating func applyRegistrations(_ registrations: [Registration]) throws {
try registrations.forEach({ try applyRegistration($0) })
}

/// Applies a single dynamic registration to the server capabilities.
public mutating func applyRegistration(_ registration: Registration) throws {
switch registration.requestMethod {
case .textDocumentSemanticTokens:
Expand Down Expand Up @@ -53,10 +59,12 @@ extension ServerCapabilities {
}
}

/// Applies multiple dynamic unregistrations to the server capabilities.
public mutating func applyUnregistrations(_ unregistrations: [Unregistration]) throws {
try unregistrations.forEach({ try applyUnregistration($0) })
}

/// Applies a single dynamic unregistration to the server capabilities.
public mutating func applyUnregistration(_ unregistration: Unregistration) throws {
switch unregistration.requestMethod {
case .textDocumentSemanticTokens:
Expand All @@ -79,6 +87,7 @@ extension ServerCapabilities {
}

extension TwoTypeOption where T == TextDocumentSyncOptions, U == TextDocumentSyncKind {
/// Returns effective text document sync options regardless of the option form.
public var effectiveOptions: TextDocumentSyncOptions {
switch self {
case .optionA(let value):
Expand All @@ -92,6 +101,7 @@ extension TwoTypeOption where T == TextDocumentSyncOptions, U == TextDocumentSyn
}

extension TwoTypeOption where T == SemanticTokensOptions, U == SemanticTokensRegistrationOptions {
/// Returns effective semantic tokens options regardless of the option form.
public var effectiveOptions: SemanticTokensOptions {
switch self {
case .optionA(let options):
Expand All @@ -107,6 +117,7 @@ extension TwoTypeOption where T == SemanticTokensOptions, U == SemanticTokensReg
}

extension SemanticTokensClientCapabilities.Requests.RangeOption {
/// Whether range requests are supported.
public var supported: Bool {
switch self {
case .optionA(let value):
Expand All @@ -118,6 +129,7 @@ extension SemanticTokensClientCapabilities.Requests.RangeOption {
}

extension SemanticTokensClientCapabilities.Requests.FullOption {
/// Whether full requests are supported.
public var supported: Bool {
switch self {
case .optionA(let value):
Expand All @@ -127,6 +139,7 @@ extension SemanticTokensClientCapabilities.Requests.FullOption {
}
}

/// Whether delta updates are supported for full requests.
public var deltaSupported: Bool {
switch self {
case .optionA(_):
Expand Down
12 changes: 12 additions & 0 deletions Sources/LanguageServerProtocol/Additions/Snippet.swift
Original file line number Diff line number Diff line change
@@ -1,23 +1,34 @@
import Foundation

/// Represents an LSP snippet string and provides parsing utilities.
public struct Snippet {
/// A parsed element of a snippet.
public enum Element: Equatable {
/// A plain text element.
case text(String)
/// A tabstop with the given index.
case tabstop(Int)
/// A placeholder with an index and default text.
case placeholder(Int, String)
/// A choice with an index and list of values.
case choice(Int, [String])
/// A variable with a name and default value.
case variable(String, String)
/// A variable with a transform (name, regex, format, options).
case variableTransform(String, String, String, String)
}

/// The raw snippet string value.
public let value: String

/// Creates a snippet from a raw string value.
public init(value: String) {
self.value = value
}
}

extension Snippet {
/// The ranges of snippet elements within the raw value.
public var elementRanges: [NSRange] {
let regex = try! NSRegularExpression(pattern: #"\$(\w+|\{([^$]+)\})"#)

Expand Down Expand Up @@ -52,6 +63,7 @@ extension Snippet {
}
}

/// All parsed snippet elements.
public var elements: [Snippet.Element] {
var list = [Snippet.Element]()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ import Foundation

/// A structure representing a Semantic Token.
public struct Token: Codable, Hashable, Sendable {
/// The range of the token in the document.
public let range: LSPRange
/// The type of the token.
public let tokenType: String
/// The set of modifier names applied to the token.
public let modifiers: Set<String>

/// Creates an instance from its parts.
public init(range: LSPRange, tokenType: String, modifiers: Set<String> = Set()) {
self.range = range
self.tokenType = tokenType
Expand All @@ -16,9 +20,12 @@ public struct Token: Codable, Hashable, Sendable {
/// Stores and updates raw Semantic Token data and converts it into Tokens.
public final class TokenRepresentation {
private var data: [UInt32]
/// The result id of the last applied response, if any.
public private(set) var lastResultId: String?
/// The legend used to interpret token types and modifiers.
public let legend: SemanticTokensLegend

/// Creates a new representation with the given legend.
public init(legend: SemanticTokensLegend) {
self.data = []
self.legend = legend
Expand Down Expand Up @@ -130,6 +137,7 @@ public final class TokenRepresentation {
}

extension TokenRepresentation {
/// Applies a delta response to the token representation.
public func applyResponse(_ response: SemanticTokensDeltaResponse) -> [LSPRange] {
switch response {
case .optionA(let fullResponse):
Expand All @@ -145,6 +153,7 @@ extension TokenRepresentation {
}
}

/// Applies a full response to the token representation.
public func applyResponse(_ response: SemanticTokensResponse) -> [LSPRange] {
guard let response = response else {
self.lastResultId = nil
Expand Down
39 changes: 39 additions & 0 deletions Sources/LanguageServerProtocol/BaseProtocol.swift
Original file line number Diff line number Diff line change
@@ -1,67 +1,94 @@
import Foundation
import JSONRPC

/// The LSP any type.
public typealias LSPAny = JSONValue

/// A non-document URI, transferred as a string.
public typealias URI = String

/// A document URI, transferred as a string whose contents can be parsed as a valid URI.
public typealias DocumentUri = String

/// A token used to report progress, provided by the client or server.
public typealias ProgressToken = TwoTypeOption<Int, String>

/// Parameters for the `$/cancelRequest` notification.
public struct CancelParams: Hashable, Codable, Sendable {
/// The request id to cancel.
public var id: TwoTypeOption<Int, String>

/// Creates an instance with a numeric request id.
public init(id: Int) {
self.id = .optionA(id)
}

/// Creates an instance with a string request id.
public init(id: String) {
self.id = .optionB(id)
}
}

/// Parameters for the `$/progress` notification.
public struct ProgressParams: Hashable, Codable, Sendable {
/// The progress token provided by the client or server.
public var token: ProgressToken
/// The progress data.
public var value: LSPAny?

/// Creates an instance from its parts.
public init(token: ProgressToken, value: LSPAny? = nil) {
self.token = token
self.value = value
}
}

/// Parameters for the `$/logTrace` notification.
public struct LogTraceParams: Hashable, Codable, Sendable {
/// The message to log.
public var string: String
/// Additional verbose information, if any.
public var verbose: String?

/// Creates an instance from its parts.
public init(string: String, verbose: String? = nil) {
self.string = string
self.verbose = verbose
}
}

/// The level of verbosity for trace output.
public enum TraceValue: String, Hashable, Codable, Sendable {
/// Tracing is disabled.
case off
/// Only messages are traced.
case messages
/// Messages and verbose output are traced.
case verbose
}

/// Parameters for the `$/setTrace` notification.
public struct SetTraceParams: Hashable, Codable, Sendable {
/// The new trace value.
public var value: TraceValue

/// Creates an instance from its parts.
public init(value: TraceValue) {
self.value = value
}
}

/// A container for an array of capability values advertised during initialization.
public struct ValueSet<T: Hashable & Codable>: Hashable, Codable {
/// The supported values.
public var valueSet: [T]

/// Creates an instance from an array of values.
public init(valueSet: [T]) {
self.valueSet = valueSet
}

/// Creates an instance containing a single value.
public init(value: T) {
self.valueSet = [value]
}
Expand All @@ -76,6 +103,7 @@ extension ValueSet: ExpressibleByArrayLiteral {
}

extension ValueSet where T: CaseIterable {
/// A value set containing all cases.
public static var all: ValueSet<T> {
return ValueSet(valueSet: Array(T.allCases))
}
Expand All @@ -84,6 +112,7 @@ extension ValueSet where T: CaseIterable {
extension ValueSet: Sendable where T: Sendable {
}

/// A well-known language identifier as defined by the LSP specification.
public enum LanguageIdentifier: String, Codable, CaseIterable, Sendable {
case abap
case windowsbat = "bat"
Expand Down Expand Up @@ -144,11 +173,16 @@ public enum LanguageIdentifier: String, Codable, CaseIterable, Sendable {
case yaml
}

/// A document filter denotes a document through properties like language, scheme, or pattern.
public struct DocumentFilter: Codable, Hashable, Sendable {
/// A language id, like `typescript`.
public let language: LanguageIdentifier?
/// A URI scheme, like `file` or `untitled`.
public let scheme: String?
/// A glob pattern, like `*.{ts,js}`.
public let pattern: String?

/// Creates an instance from its parts.
public init(language: LanguageIdentifier? = nil, scheme: String? = nil, pattern: String? = nil)
{
self.language = language
Expand All @@ -157,15 +191,20 @@ public struct DocumentFilter: Codable, Hashable, Sendable {
}
}

/// The combination of one or more document filters.
public typealias DocumentSelector = [DocumentFilter]

/// An identifier for a text document using its URI.
public struct TextDocumentIdentifier: Codable, Hashable, Sendable {
/// The text document's URI.
public var uri: DocumentUri

/// Creates an instance from a document URI.
public init(uri: DocumentUri) {
self.uri = uri
}

/// Creates an instance from a file path, converting it to a `file://` URI.
public init(path: String) {
self.uri = URL(fileURLWithPath: path).absoluteString
}
Expand Down
Loading