Skip to content

Commit ae96dca

Browse files
authored
Improve performance of workspace/symbol for large queries + projects (swiftlang#317)
- Avoid short queries (< 3 characters) since they are slow and noisy. Xcode does the same thing. - Limit the number of results returned: - Improves performance for queries which match many symbols - Currently take the first N results to improve performance for large projects but once we support cancellation we should take the top N.
1 parent 1d0f901 commit ae96dca

File tree

1 file changed

+25
-5
lines changed

1 file changed

+25
-5
lines changed

Sources/SourceKitLSP/SourceKitServer.swift

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -658,23 +658,36 @@ extension SourceKitServer {
658658
/// Find all symbols in the workspace that include a string in their name.
659659
/// - returns: An array of SymbolOccurrences that match the string.
660660
func findWorkspaceSymbols(matching: String) -> [SymbolOccurrence] {
661+
// Ignore short queries since they are:
662+
// - noisy and slow, since they can match many symbols
663+
// - normally unintentional, triggered when the user types slowly or if the editor doesn't
664+
// debounce events while the user is typing
665+
guard matching.count >= minWorkspaceSymbolPatternLength else {
666+
return []
667+
}
661668
var symbolOccurenceResults: [SymbolOccurrence] = []
662669
workspace?.index?.forEachCanonicalSymbolOccurrence(
663670
containing: matching,
664671
anchorStart: false,
665672
anchorEnd: false,
666673
subsequence: true,
667674
ignoreCase: true
668-
) {symbol in
669-
if !symbol.location.isSystem && !symbol.roles.contains(.accessorOf) {
670-
symbolOccurenceResults.append(symbol)
675+
) { symbol in
676+
guard !symbol.location.isSystem && !symbol.roles.contains(.accessorOf) else {
677+
return true
671678
}
672-
return true
679+
symbolOccurenceResults.append(symbol)
680+
// FIXME: Once we have cancellation support, we should fetch all results and take the top
681+
// `maxWorkspaceSymbolResults` symbols but bail if cancelled.
682+
//
683+
// Until then, take the first `maxWorkspaceSymbolResults` symbols to limit the impact of
684+
// queries which match many symbols.
685+
return symbolOccurenceResults.count < maxWorkspaceSymbolResults
673686
}
674687
return symbolOccurenceResults
675688
}
676689

677-
/// Handle a workspace/symbols request, returning the SymbolInformation.
690+
/// Handle a workspace/symbol request, returning the SymbolInformation.
678691
/// - returns: An array with SymbolInformation for each matching symbol in the workspace.
679692
func workspaceSymbols(_ req: Request<WorkspaceSymbolsRequest>, workspace: Workspace) {
680693
let symbols = findWorkspaceSymbols(
@@ -1022,6 +1035,13 @@ public func languageService(
10221035
}
10231036
}
10241037

1038+
/// Minimum supported pattern length for a `workspace/symbol` request, smaller pattern
1039+
/// strings are not queried and instead we return no results.
1040+
private let minWorkspaceSymbolPatternLength = 3
1041+
1042+
/// The maximum number of results to return from a `workspace/symbol` request.
1043+
private let maxWorkspaceSymbolResults = 4096
1044+
10251045
public typealias Notification = LanguageServerProtocol.Notification
10261046
public typealias Diagnostic = LanguageServerProtocol.Diagnostic
10271047

0 commit comments

Comments
 (0)