-
Notifications
You must be signed in to change notification settings - Fork 314
Add server-side support for inlay hints using CollectExpressionType #406
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
47 changes: 47 additions & 0 deletions
47
Sources/LanguageServerProtocol/Requests/InlayHintsRequest.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 - 2021 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 for inline annotations to be displayed in the editor **(LSP Extension)**. | ||
/// | ||
/// This implements the proposed `textDocument/inlayHints` API from | ||
/// https://github.com/microsoft/language-server-protocol/pull/1249 (commit: `d55733d`) | ||
/// | ||
/// - Parameters: | ||
/// - textDocument: The document for which to provide the inlay hints. | ||
/// | ||
/// - Returns: InlayHints for the entire document | ||
public struct InlayHintsRequest: TextDocumentRequest, Hashable { | ||
fwcd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
public static let method: String = "sourcekit-lsp/inlayHints" | ||
public typealias Response = [InlayHint] | ||
|
||
/// The document for which to provide the inlay hints. | ||
public var textDocument: TextDocumentIdentifier | ||
|
||
/// The range the inlay hints are requested for. If nil, | ||
/// hints for the entire document are requested. | ||
@CustomCodable<PositionRange?> | ||
public var range: Range<Position>? | ||
|
||
/// The categories of hints that are interesting to the client | ||
/// and should be filtered. | ||
public var only: [InlayHintCategory]? | ||
fwcd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
public init( | ||
textDocument: TextDocumentIdentifier, | ||
range: Range<Position>? = nil, | ||
only: [InlayHintCategory]? = nil | ||
) { | ||
self.textDocument = textDocument | ||
self._range = CustomCodable(wrappedValue: range) | ||
self.only = only | ||
} | ||
} |
48 changes: 48 additions & 0 deletions
48
Sources/LanguageServerProtocol/SupportTypes/InlayHint.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This source file is part of the Swift.org open source project | ||
// | ||
// Copyright (c) 2014 - 2021 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
/// Represents an inline annotation displayed by the editor in a source file. | ||
public struct InlayHint: ResponseType, Codable, Hashable { | ||
/// The position within the code that this hint is attached to. | ||
public var position: Position | ||
|
||
/// The hint's kind, used for more flexible client-side styling. | ||
public let category: InlayHintCategory? | ||
|
||
/// The hint's text, e.g. a printed type | ||
public let label: String | ||
|
||
public init( | ||
position: Position, | ||
category: InlayHintCategory? = nil, | ||
label: String | ||
) { | ||
self.position = position | ||
self.category = category | ||
self.label = label | ||
} | ||
} | ||
|
||
/// A hint's kind, used for more flexible client-side styling. | ||
public struct InlayHintCategory: RawRepresentable, Codable, Hashable { | ||
public var rawValue: String | ||
|
||
public init(rawValue: String) { | ||
self.rawValue = rawValue | ||
} | ||
|
||
/// A parameter label. Note that this case is not used by | ||
/// Swift, since Swift already has explicit parameter labels. | ||
public static let parameter: InlayHintCategory = InlayHintCategory(rawValue: "parameter") | ||
/// An inferred type. | ||
public static let type: InlayHintCategory = InlayHintCategory(rawValue: "type") | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This source file is part of the Swift.org open source project | ||
// | ||
// Copyright (c) 2014 - 2021 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 Dispatch | ||
import LanguageServerProtocol | ||
import SourceKitD | ||
|
||
/// A typed expression as returned by sourcekitd's CollectExpressionType. | ||
/// | ||
/// A detailed description of the structure returned by sourcekitd can be found | ||
/// here: https://github.com/apple/swift/blob/main/tools/SourceKit/docs/Protocol.md#expression-type | ||
struct ExpressionTypeInfo { | ||
/// Range of the expression in the source file. | ||
var range: Range<Position> | ||
/// The printed type of the expression. | ||
var printedType: String | ||
|
||
init?(_ dict: SKDResponseDictionary, in snapshot: DocumentSnapshot) { | ||
let keys = dict.sourcekitd.keys | ||
|
||
guard let offset: Int = dict[keys.expression_offset], | ||
let length: Int = dict[keys.expression_length], | ||
let startIndex = snapshot.positionOf(utf8Offset: offset), | ||
let endIndex = snapshot.positionOf(utf8Offset: offset + length), | ||
let printedType: String = dict[keys.expression_type] else { | ||
return nil | ||
} | ||
|
||
self.range = startIndex..<endIndex | ||
self.printedType = printedType | ||
} | ||
} | ||
|
||
enum ExpressionTypeInfoError: Error, Equatable { | ||
/// The given URL is not a known document. | ||
case unknownDocument(DocumentURI) | ||
|
||
/// The underlying sourcekitd request failed with the given error. | ||
case responseError(ResponseError) | ||
} | ||
|
||
extension SwiftLanguageServer { | ||
/// Must be called on self.queue. | ||
private func _expressionTypeInfos( | ||
_ uri: DocumentURI, | ||
_ completion: @escaping (Swift.Result<[ExpressionTypeInfo], ExpressionTypeInfoError>) -> Void | ||
) { | ||
dispatchPrecondition(condition: .onQueue(queue)) | ||
|
||
guard let snapshot = documentManager.latestSnapshot(uri) else { | ||
fwcd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return completion(.failure(.unknownDocument(uri))) | ||
} | ||
|
||
let keys = self.keys | ||
|
||
let skreq = SKDRequestDictionary(sourcekitd: sourcekitd) | ||
skreq[keys.request] = requests.expression_type | ||
skreq[keys.sourcefile] = snapshot.document.uri.pseudoPath | ||
|
||
// FIXME: SourceKit should probably cache this for us. | ||
if let compileCommand = self.commandsByFile[uri] { | ||
skreq[keys.compilerargs] = compileCommand.compilerArgs | ||
} | ||
|
||
let handle = self.sourcekitd.send(skreq, self.queue) { result in | ||
guard let dict = result.success else { | ||
return completion(.failure(.responseError(ResponseError(result.failure!)))) | ||
} | ||
|
||
guard let skExpressionTypeInfos: SKDResponseArray = dict[keys.expression_type_list] else { | ||
return completion(.success([])) | ||
} | ||
|
||
var expressionTypeInfos: [ExpressionTypeInfo] = [] | ||
fwcd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
expressionTypeInfos.reserveCapacity(skExpressionTypeInfos.count) | ||
|
||
skExpressionTypeInfos.forEach { (_, skExpressionTypeInfo) -> Bool in | ||
guard let info = ExpressionTypeInfo(skExpressionTypeInfo, in: snapshot) else { | ||
assertionFailure("ExpressionTypeInfo failed to deserialize") | ||
return true | ||
} | ||
expressionTypeInfos.append(info) | ||
return true | ||
} | ||
|
||
completion(.success(expressionTypeInfos)) | ||
} | ||
|
||
// FIXME: cancellation | ||
_ = handle | ||
} | ||
|
||
/// Provides typed expressions in a document. | ||
/// | ||
/// - Parameters: | ||
/// - url: Document URL in which to perform the request. Must be an open document. | ||
/// - completion: Completion block to asynchronously receive the ExpressionTypeInfos, or error. | ||
func expressionTypeInfos( | ||
_ uri: DocumentURI, | ||
_ completion: @escaping (Swift.Result<[ExpressionTypeInfo], ExpressionTypeInfoError>) -> Void | ||
) { | ||
queue.async { | ||
self._expressionTypeInfos(uri, completion) | ||
} | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.