-
Notifications
You must be signed in to change notification settings - Fork 314
Add workspace/symbols support #118
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// 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 for all symbols that match a certain query string. | ||
/// | ||
/// This request looks up the canonical occurence of each symbol which has a name that contains the query string. | ||
/// The list of symbol information is returned | ||
/// | ||
/// Servers that provide workspace symbol queries should set the `workspaceSymbolProvider` server capability. | ||
/// | ||
/// - Parameters: | ||
/// - query: The string that should be looked for in symbols of the workspace. | ||
/// | ||
/// - Returns: Information about each symbol with a name that contains the query string | ||
public struct WorkspaceSymbolsRequest: RequestType, Hashable { | ||
|
||
public static let method: String = "workspace/symbol" | ||
public typealias Response = [SymbolInformation]? | ||
|
||
/// The document in which to lookup the symbol location. | ||
public var query: String | ||
|
||
public init(query: String) { | ||
self.query = query | ||
} | ||
} | ||
|
||
public struct SymbolInformation: Hashable, ResponseType { | ||
public var name: String | ||
|
||
public var detail: String? | ||
|
||
public var kind: SymbolKind | ||
|
||
public var deprecated: Bool | ||
|
||
public var location: Location | ||
|
||
public var containerName: String? | ||
|
||
public init(name: String, detail: String?, kind: SymbolKind, deprecated: Bool, location: Location, containerName: String?) { | ||
self.name = name | ||
self.detail = detail | ||
self.kind = kind | ||
self.deprecated = deprecated | ||
self.location = location | ||
self.containerName = containerName | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -71,6 +71,7 @@ public final class SourceKitServer: LanguageServer { | |
registerWorkspaceNotfication(SourceKitServer.didSaveDocument) | ||
registerWorkspaceRequest(SourceKitServer.completion) | ||
registerWorkspaceRequest(SourceKitServer.hover) | ||
registerWorkspaceRequest(SourceKitServer.workspaceSymbols) | ||
registerWorkspaceRequest(SourceKitServer.definition) | ||
registerWorkspaceRequest(SourceKitServer.references) | ||
registerWorkspaceRequest(SourceKitServer.documentSymbolHighlight) | ||
|
@@ -269,7 +270,8 @@ extension SourceKitServer { | |
clientCapabilities: req.params.capabilities.textDocument?.codeAction, | ||
codeActionOptions: CodeActionOptions(codeActionKinds: nil), | ||
supportsCodeActions: false // TODO: Turn it on after a provider is implemented. | ||
) | ||
), | ||
workspaceSymbolProvider: true | ||
))) | ||
} | ||
|
||
|
@@ -338,6 +340,47 @@ extension SourceKitServer { | |
toolchainTextDocumentRequest(req, workspace: workspace, fallback: nil) | ||
} | ||
|
||
func findWorkspaceSymbols(matching: String) -> [SymbolOccurrence] { | ||
var symbolOccurenceResults: [SymbolOccurrence] = [] | ||
workspace?.index?.forEachCanonicalSymbolOccurrence( | ||
containing: matching, | ||
anchorStart: false, | ||
anchorEnd: false, | ||
subsequence: true, | ||
ignoreCase: true | ||
) {symbol in | ||
if !symbol.location.isSystem && !symbol.roles.contains(.accessorOf) { | ||
symbolOccurenceResults.append(symbol) | ||
} | ||
return true | ||
} | ||
return symbolOccurenceResults | ||
} | ||
|
||
func workspaceSymbols(_ req: Request<WorkspaceSymbolsRequest>, workspace: Workspace) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Much of the other functionality seems to be done in SwiftLanguageServer, but I think I need to do this here to have access to index. Is that correct? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, this is the right place for it. Language-agnostic functionality belongs here, which is why we also implement e.g. jump to definition here. |
||
let symbols = findWorkspaceSymbols( | ||
matching: req.params.query | ||
).map({symbolOccurrence -> SymbolInformation in | ||
let symbolPosition = Position( | ||
line: symbolOccurrence.location.line - 1, // 1-based -> 0-based | ||
// FIXME: we need to convert the utf8/utf16 column, which may require reading the file! | ||
utf16index: symbolOccurrence.location.utf8Column - 1) | ||
|
||
let symbolLocation = Location( | ||
url: URL(fileURLWithPath: symbolOccurrence.location.path), | ||
range: Range(symbolPosition)) | ||
// TODO: symbol kind, detail, and containerName should be added | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would like some guidance on how to get kind, detail, and containerName. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are correct that detail came from for containerName, it looks like I will have to pass an ArrayPointer to Swift, which I can't find a good example of. Maybe I could use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Copying should be fine, since the number of relations for a single occurrence will generally be small, and we can do the copy lazily only when you ask for related symbols. Here's a sketch of the C API I would start with. We can always optimize this later if needed. typedef void *indexstoredb_symbol_relation_t;
...
INDEXSTOREDB_PUBLIC uint64_t
indexstoredb_symbol_relation_get_roles(_Nonnull indexstoredb_symbol_relation_t);
INDEXSTOREDB_PUBLIC indexstoredb_symbol_t
indexstoredb_symbol_relation_get_symbol(_Nonnull indexstoredb_symbol_relation_t);
/// The relations are owned by the occurrence and shall not be used after the occurrence is freed.
INDEXSTOREDB_PUBLIC bool
indexstoredb_symbol_occurrence_relations(_Nonnull indexstoredb_occurrence_t,
bool(^applier)(indexstoredb_symbol_relation_t)); On the Swift side, this can lazily create an array from the occurrence. |
||
return SymbolInformation( | ||
name: symbolOccurrence.symbol.name, | ||
detail: nil, | ||
kind: .variable, | ||
deprecated: false, | ||
location: symbolLocation, | ||
containerName: nil) | ||
}) | ||
req.reply(symbols) | ||
} | ||
|
||
/// Forwards a SymbolInfoRequest to the appropriate toolchain service for this document. | ||
func symbolInfo(_ req: Request<SymbolInfoRequest>, workspace: Workspace) { | ||
toolchainTextDocumentRequest(req, workspace: workspace, fallback: []) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what roles should be included. I've excluded
accessorOf
because otherwise getters and setters of variables were returned in addition to the variable itself.